<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/NHDaly/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/NHDaly">@NHDaly</a>  and I found this the day before juliacon, but forgot to open an issue.<br>
I think <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/Keno/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/Keno">@Keno</a>'s theory was that the <code class="notranslate">literal_pow</code> stuff broke this.</p>
<p dir="auto">Basically constant folding stops for exponents greater than 4.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @code_typed (()-&gt;10^4)()
CodeInfo(
1 ─      nothing::Nothing
2 ┄ %2 = φ (#1 =&gt; 10, #3 =&gt; %7)::Int64
│   %3 = φ (#1 =&gt; 3, #3 =&gt; %4)::Int64
│   %4 = Base.sub_int(%3, 1)::Int64
│   %5 = Base.slt_int(0, %4)::Bool
└──      goto #4 if not %5
3 ─ %7 = Base.mul_int(%2, %2)::Int64
└──      goto #2
4 ─      goto #5
5 ─      goto #6
6 ─      goto #7
7 ─      return %2
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^3)()
CodeInfo(
1 ─     return 1000
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^2)()
CodeInfo(
1 ─     return 100
) =&gt; Int64


julia&gt; @code_typed (()-&gt;10^1)()
CodeInfo(
1 ─     return 10
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^0)()
CodeInfo(
1 ─     return 1
) =&gt; Int64


julia&gt; @code_typed (()-&gt;10^-1)()
CodeInfo(
1 ─     return 0.1
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-2)()
CodeInfo(
1 ─     return 0.010000000000000002
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-3)()
CodeInfo(
1 ─     return 0.0010000000000000002
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-4)()
CodeInfo(
1 ─ %1 = $(Expr(:foreigncall, &quot;llvm.pow.f64&quot;, Float64, svec(Float64, Float64), 0, :(:llvmcall), 0.1, 4.0, 4.0, 0.1))::Float64
└──      return %1
) =&gt; Float64"><pre class="notranslate"><code class="notranslate">julia&gt; @code_typed (()-&gt;10^4)()
CodeInfo(
1 ─      nothing::Nothing
2 ┄ %2 = φ (#1 =&gt; 10, #3 =&gt; %7)::Int64
│   %3 = φ (#1 =&gt; 3, #3 =&gt; %4)::Int64
│   %4 = Base.sub_int(%3, 1)::Int64
│   %5 = Base.slt_int(0, %4)::Bool
└──      goto #4 if not %5
3 ─ %7 = Base.mul_int(%2, %2)::Int64
└──      goto #2
4 ─      goto #5
5 ─      goto #6
6 ─      goto #7
7 ─      return %2
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^3)()
CodeInfo(
1 ─     return 1000
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^2)()
CodeInfo(
1 ─     return 100
) =&gt; Int64


julia&gt; @code_typed (()-&gt;10^1)()
CodeInfo(
1 ─     return 10
) =&gt; Int64

julia&gt; @code_typed (()-&gt;10^0)()
CodeInfo(
1 ─     return 1
) =&gt; Int64


julia&gt; @code_typed (()-&gt;10^-1)()
CodeInfo(
1 ─     return 0.1
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-2)()
CodeInfo(
1 ─     return 0.010000000000000002
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-3)()
CodeInfo(
1 ─     return 0.0010000000000000002
) =&gt; Float64

julia&gt; @code_typed (()-&gt;10^-4)()
CodeInfo(
1 ─ %1 = $(Expr(:foreigncall, "llvm.pow.f64", Float64, svec(Float64, Float64), 0, :(:llvmcall), 0.1, 4.0, 4.0, 0.1))::Float64
└──      return %1
) =&gt; Float64
</code></pre></div>
<p dir="auto">LLVM actually has our back here though.<br>
It will constant fold for all negative integer powers I think.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @code_llvm (()-&gt;10^-4)()

;  @ REPL[15]:1 within `#35'
define double @&quot;julia_#35_16849&quot;() {
top:
  ret double 0x3F1A36E2EB1C432E
}

julia&gt; @code_llvm (()-&gt;10^-100)()

;  @ REPL[19]:1 within `#43'
define double @&quot;julia_#43_16854&quot;() {
top:
  ret double 0x2B2BFF2EE48E055C
}"><pre class="notranslate"><code class="notranslate">julia&gt; @code_llvm (()-&gt;10^-4)()

;  @ REPL[15]:1 within `#35'
define double @"julia_#35_16849"() {
top:
  ret double 0x3F1A36E2EB1C432E
}

julia&gt; @code_llvm (()-&gt;10^-100)()

;  @ REPL[19]:1 within `#43'
define double @"julia_#43_16854"() {
top:
  ret double 0x2B2BFF2EE48E055C
}
</code></pre></div>
<p dir="auto">But for positive powers it only does 1 extra: 10^4</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @code_llvm (()-&gt;10^4)()

;  @ REPL[16]:1 within `#37'
define i64 @&quot;julia_#37_16850&quot;() {
top:
  ret i64 10000
}

julia&gt; @code_llvm (()-&gt;10^5)()

;  @ REPL[17]:1 within `#39'
define i64 @&quot;julia_#39_16851&quot;() {
L21.lr.ph:
; ┌ @ none within `literal_pow'
; │┌ @ none within `macro expansion'
; ││┌ @ intfuncs.jl:221 within `^'
; │││┌ @ intfuncs.jl:208 within `power_by_squaring'
      br label %L21

L21:                                              ; preds = %L21.lr.ph, %L21
      %0 = phi i64 [ 1, %L21.lr.ph ], [ %2, %L21 ]
      %value_phi35 = phi i64 [ 10, %L21.lr.ph ], [ %1, %L21 ]
; ││││ @ intfuncs.jl:209 within `power_by_squaring'
; ││││┌ @ int.jl:54 within `*'
       %1 = mul i64 %value_phi35, %value_phi35
; ││││└
; ││││ @ intfuncs.jl:208 within `power_by_squaring'
; ││││┌ @ int.jl:52 within `-'
       %2 = add nsw i64 %0, -1
; ││││└
; ││││┌ @ operators.jl:341 within `&gt;='
; │││││┌ @ int.jl:410 within `&lt;='
        %3 = icmp slt i64 %0, 1
; ││││└└
      br i1 %3, label %L23, label %L21

L23:                                              ; preds = %L21
      %phitmp = mul i64 %1, 10
; └└└└
  ret i64 %phitmp
}"><pre class="notranslate"><code class="notranslate">julia&gt; @code_llvm (()-&gt;10^4)()

;  @ REPL[16]:1 within `#37'
define i64 @"julia_#37_16850"() {
top:
  ret i64 10000
}

julia&gt; @code_llvm (()-&gt;10^5)()

;  @ REPL[17]:1 within `#39'
define i64 @"julia_#39_16851"() {
L21.lr.ph:
; ┌ @ none within `literal_pow'
; │┌ @ none within `macro expansion'
; ││┌ @ intfuncs.jl:221 within `^'
; │││┌ @ intfuncs.jl:208 within `power_by_squaring'
      br label %L21

L21:                                              ; preds = %L21.lr.ph, %L21
      %0 = phi i64 [ 1, %L21.lr.ph ], [ %2, %L21 ]
      %value_phi35 = phi i64 [ 10, %L21.lr.ph ], [ %1, %L21 ]
; ││││ @ intfuncs.jl:209 within `power_by_squaring'
; ││││┌ @ int.jl:54 within `*'
       %1 = mul i64 %value_phi35, %value_phi35
; ││││└
; ││││ @ intfuncs.jl:208 within `power_by_squaring'
; ││││┌ @ int.jl:52 within `-'
       %2 = add nsw i64 %0, -1
; ││││└
; ││││┌ @ operators.jl:341 within `&gt;='
; │││││┌ @ int.jl:410 within `&lt;='
        %3 = icmp slt i64 %0, 1
; ││││└└
      br i1 %3, label %L23, label %L21

L23:                                              ; preds = %L21
      %phitmp = mul i64 %1, 10
; └└└└
  ret i64 %phitmp
}
</code></pre></div>
<p dir="auto">Was reminded when this came up in <a href="https://discourse.julialang.org/t/no-constant-expression-elimination-for-e-g-2-24-1/30964/8" rel="nofollow">https://discourse.julialang.org/t/no-constant-expression-elimination-for-e-g-2-24-1/30964/8</a></p>
<p dir="auto">Have a look at:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; f() = 2^5; @code_native f()
    .text
; Function f {
; Location: none:1
; Function literal_pow; {
; Location: none
; Function macro expansion; {
; Location: none
; Function ^; {
; Location: none:1
    pushq   %rax
    movabsq $power_by_squaring, %rax
    movl    $2, %edi
    movl    $5, %esi
    callq   *%rax
;}}}
    popq    %rcx
    retq
    nopl    (%rax)
;}"><pre class="notranslate"><code class="notranslate">julia&gt; f() = 2^5; @code_native f()
    .text
; Function f {
; Location: none:1
; Function literal_pow; {
; Location: none
; Function macro expansion; {
; Location: none
; Function ^; {
; Location: none:1
    pushq   %rax
    movabsq $power_by_squaring, %rax
    movl    $2, %edi
    movl    $5, %esi
    callq   *%rax
;}}}
    popq    %rcx
    retq
    nopl    (%rax)
;}
</code></pre></div>
<p dir="auto">This behaviour is weird. Since the result is completely fixed, shouldn't it compile all the way down to "return this predefined number" instead of requiring a new function call?<br>
To make things weirder, the following functions <em>do</em> compile down to "return this number":<br>
<code class="notranslate">m() = 2^8; n() = 3^4; g() = 2.0^5; h() = 2^5.0, k() = 1&lt;&lt;5</code><br>
In practice, this means that running <code class="notranslate">k()</code> is unnecessarily ~3x faster than <code class="notranslate">f()</code>. Is this a bug that should be fixed?</p>
<h3 dir="auto">Environment:</h3>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; versioninfo()
Julia Version 1.0.0
Commit 5d4eaca0c9 (2018-08-08 20:58 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i5-4210H CPU @ 2.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, haswell)
Environment:
  JULIA_EDITOR = atom -a
  JULIA_NUM_THREADS = 2"><pre class="notranslate"><code class="notranslate">julia&gt; versioninfo()
Julia Version 1.0.0
Commit 5d4eaca0c9 (2018-08-08 20:58 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i5-4210H CPU @ 2.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, haswell)
Environment:
  JULIA_EDITOR = atom -a
  JULIA_NUM_THREADS = 2
</code></pre></div>