Is there a way to tell constant propagation to just keep propagating? I keep running into cases where the types are perfectly well known, but constant propagation has been "Disabled by argument and rettype heuristics" and the return type has been widened into something else.
At first glance it seems like Base.@constprop :aggressive
should do exactly what I want, but so far when I've tried it it actually hasn't helped
I haven't found it terribly useful in practice (similar experiences). I would be happy to help but I can't promise that I'm smart enough to figure it out.
The next thing I'm trying is just adding manual type annotations.. think that'll work?
The context is the top-level functions in https://github.com/brenhinkeller/StaticMPI.jl
I'm trying to get things to statically compile, so need total type stability -- which so far works fine if I keep the whole program _super simple_ -- but as soon as I try to do something less trivial, functions that were previously inferring stably start giving that "Disabled by argument and rettype heuristics" message in Cthulhu and I start getting Union{}
is it the source
, dest
, and tag
in the MPI_*
methods?
The return types of functions like https://github.com/brenhinkeller/StaticMPI.jl/blob/main/src/StaticMPI.jl#L110-L118 have been giving me a lot of trouble -- like I'll put an Int32 in the ref, but when I fetch it back out it doesn't seem to know the type any more unless I annotate it
The very simplest functions are fine, so like this example in the tests works just fine: https://github.com/brenhinkeller/StaticMPI.jl/blob/main/test/scripts/mpihello_mpich.jl
But the Isend and Irecv have been a lot of trouble to get working
This is my current attempt which I just can't get to work
https://github.com/brenhinkeller/StaticMPI.jl/blob/main/test/scripts/mpisendrecv.jl
(though there may also be some regular old bugs in there confounding things -- it doesn't help that I can't call any of these MPI functions interactively to test things because they segfault unless compiled in a way that links to libmpi :laughing: )
What happens if you use the concrete type RefValue{T}
instead of the abstract type Ref{T}
?
Hmm, good point..
RefValue
was my gonna be my first guess too. Perhaps going back and forth betweenRef
and ⅋
into a pointer is part of the problem. I'm not sure how well the heuristics of constant propagation play with memory storage.
Yeah, that probably doesn't help..
BTW, note that Julia 1.8 adds the effects system, and Cthulhu can help you inspect inferred effects (e
for effects).
It helps to turn off optimizations o
, otherwise a lot of the interesting code will be compiled away.
These allow constant evaluation, which is dramatically faster than constant propagation. E.g., constant propagation for sin(1.0)
means running code through the AbstractInterpreter, which is a very slow interpreter, while constant evaluation means the compiler just gets to call sin(::Float64)
, so it's likely to be more aggressive.
But RefValue
s do cause problems currently, because of course setfield!
has a side effect, and getfield
of a memory address isn't consistent
[(!c,!e,+n,+t,+s)]reftest()
@ Main REPL[5]:1
Variables
#self#::Core.Const(reftest)
x::Base.RefValue{Int64}
│ ─ %-1 = invoke reftest()::Int64
@ REPL[5]:2 within `reftest`
1 ─ %1 = Base.RefValue::Core.Const(Base.RefValue)
│ %2 = Core.apply_type(%1, Main.Int)::Core.Const(Base.RefValue{Int64})
│ (x = (%2)())::Base.RefValue{Int64}
│ @ REPL[5]:3 within `reftest`
│ Base.setindex!(x, 3)::Any
│ @ REPL[5]:4 within `reftest`
│ %5 = Base.getindex(x)::Int64
└── return %5
Select a call to descend into or ↩ to ascend. [q]uit. [b]ookmark.
Toggles: [o]ptimize, [w]arn, [h]ide type-stable statements, [d]ebuginfo, [r]emarks, [e]ffects, [i]nlining costs, [t]ype annotations, [s]yntax highlight for Source/LLVM/Native.
Show: [S]ource code, [A]ST, [T]yped code, [L]LVM IR, [N]ative code
Actions: [E]dit source code, [R]evise and redisplay
Advanced: dump [P]arams cache.
• (?c,+e,+n,+t,+s) %3 = RefValue()::Base.RefValue{Int64}
(!c,!e,+n,+t,+s) %4 = < constprop > setindex!(::Base.RefValue{Int64},::Core.Const(3))::Any
(!c,+e,+n,+t,+s) %5 = getindex(::Base.RefValue{Int64})::Int64
Some sort of lifetime modeling could handle this in the future.
Folks in Boston were treated to an excellent presentation by @Shuhei Kadowaki on Thursday.
Oh cool!
Success! https://github.com/brenhinkeller/StaticMPI.jl/blob/main/test/scripts/mpisendrecv.jl
Turns out there were still a bunch of actual bugs I had to iron out, and once I took care of those I didn't actually need any manual type annotations any more
There are still a bunch of warnings in Cthulhu about constprop being disabled, but it turns out none of them were actually preventing static compilation (just making it a bit harder for me to find where my actual problem was)
So I owe the compiler a bit of an apology :sweat_smile:
Brenhin Keller has marked this topic as resolved.
Last updated: Dec 28 2024 at 04:38 UTC