Skip to content

Conversation

@jrevels
Copy link
Member

@jrevels jrevels commented Oct 8, 2018

This branch is a proof-of-concept showing how we can get LLVM to do better CSE by leveraging/inferring function attributes. This is entirely @maleadt's work, I just want to call attention to it before the branch goes stale w.r.t. master 😛

I think Tim might be a bit busy right now, but I would be willing to devote some cycles to polishing this in November, if folks agree it's a good idea.

With this PR:

julia> function f(x)
         _1 = exp(x)
         _2 = exp(x)
         return _1 + _2
       end
f (generic function with 1 method)

julia> @code_llvm f(1.)

; Function f
; Location: REPL[1]:2
; Function Attrs: readnone
define double @julia_f_1527076232(double) #0 {
top:
  %1 = call double @julia_exp_1527076233(double %0) #0
; Location: REPL[1]:4
; Function +; {
; Location: float.jl:395
  %2 = fadd double %1, %1
;}
  ret double %2
}

@Keno
Copy link
Member

Keno commented Oct 8, 2018

I think this is reasonable, though I think it would be even better to track this kind of thing during inference.

Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think doing this as an IPO pass is valid (or, at least, won't be in the future, when we allow caching native code and compiling functions non-recursively).

@KristofferC
Copy link
Member

KristofferC commented Nov 5, 2018

So inference can clearly figure out that e.g. sin is pure.

julia> f() =  sin(3)
f (generic function with 2 methods)

julia> @code_typed f()
CodeInfo(
1 1return 0.14112                                                                                                                                                                    │
) => Float64

What is required to make it figure out that

julia> f(x) =  sin(x) + sin(x)
f (generic function with 2 methods)

julia> @code_typed f(3)
CodeInfo(
1 1%1 = (Base.sitofp)(Float64, x)::Float64                                                                                                                                    │╻╷╷╷ sin
  │   %2 = invoke Base.Math.sin(%1::Float64)::Float64                                                                                                                            ││
  │   %3 = (Base.sitofp)(Float64, x)::Float64                                                                                                                                    ││╻╷╷  float
  │   %4 = invoke Base.Math.sin(%3::Float64)::Float64                                                                                                                            ││
  │   %5 = (Base.add_float)(%2, %4)::Float64                                                                                                                                     │╻    +
  └──      return %5                                                                                                                                                             │
) => Float64

can be simplified?

Something like : first notice that sitoffp is pure, figure out %3 == %1 and eliminate it:

1 1%1 = (Base.sitofp)(Float64, x)::Float64                                                                                                                                    │╻╷╷╷ sin
  │   %2 = invoke Base.Math.sin(%1::Float64)::Float64                                                                                                                            ││
  │   %4 = invoke Base.Math.sin(%1::Float64)::Float64                                                                                                                            ││
  │   %5 = (Base.add_float)(%2, %4)::Float64                                                                                                                                     │╻    +
  └──      return %5                                                                                                                                                             │
) => Float64

Now use the knowledge that sin(::Float64) is pure, see that %2 == %4, eliminate %4:

1 1%1 = (Base.sitofp)(Float64, x)::Float64                                                                                                                                    │╻╷╷╷ sin
  │   %2 = invoke Base.Math.sin(%1::Float64)::Float64                                                                                                                            ││
  │   %5 = (Base.add_float)(%2, %2)::Float64                                                                                                                                     │╻    +
  └──      return %5                                                                                                                                                             │
) => Float64

?

Is there some complication or just someone has to implement it?

What's the advantage of doing it in inference instead of letting LLVM handle it`

@Keno
Copy link
Member

Keno commented Nov 5, 2018

Yes, we could have a GVN pass in the optimizer. However, GVN is a non-trivial pass to implement, so since LLVM already has it, it'd be nice to at least pass that information down.

@vchuravy
Copy link
Member

As a side-note I was looking today at function attributes since I would love to do LICM on Julia functions. For that we would want to infer functions attributes much earlier in the pipeline (this PR does it at the end), but if we do it before LowerPTLS the call to julia.ptls_states prohibits any inference of interesting attributes like readnone, readonly, argmemonly, and we also can't get rid of the PTLS getter until late in the pipeline.

@vchuravy vchuravy mentioned this pull request Jul 28, 2020
3 tasks
@giordano giordano deleted the tb/fnattrs branch December 27, 2022 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants