Stream: helpdesk (published)

Topic: Constant propagation


view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:03):

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.

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:03):

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

view this post on Zulip Zachary P Christensen (Jul 22 2022 at 18:14):

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.

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:16):

The next thing I'm trying is just adding manual type annotations.. think that'll work?

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:17):

The context is the top-level functions in https://github.com/brenhinkeller/StaticMPI.jl

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:19):

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{}

view this post on Zulip Zachary P Christensen (Jul 22 2022 at 18:20):

is it the source, dest, and tag in the MPI_* methods?

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:27):

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

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:28):

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

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:28):

But the Isend and Irecv have been a lot of trouble to get working

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:37):

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: )

view this post on Zulip Fredrik Ekre (Jul 22 2022 at 18:48):

What happens if you use the concrete type RefValue{T} instead of the abstract type Ref{T}?

view this post on Zulip Brenhin Keller (Jul 22 2022 at 18:49):

Hmm, good point..

view this post on Zulip Zachary P Christensen (Jul 22 2022 at 18:54):

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.

view this post on Zulip Brenhin Keller (Jul 22 2022 at 19:13):

Yeah, that probably doesn't help..

view this post on Zulip chriselrod (Jul 23 2022 at 04:13):

BTW, note that Julia 1.8 adds the effects system, and Cthulhu can help you inspect inferred effects (e for effects).

view this post on Zulip chriselrod (Jul 23 2022 at 04:18):

It helps to turn off optimizations o, otherwise a lot of the interesting code will be compiled away.

view this post on Zulip chriselrod (Jul 23 2022 at 04:18):

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 RefValues 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

view this post on Zulip chriselrod (Jul 23 2022 at 04:19):

Some sort of lifetime modeling could handle this in the future.


Last updated: Oct 02 2023 at 04:34 UTC