Why does LLVM like putting floating-point constants into RODATA so much? Is that suboptimal?

It is almost impossible to avoid LLVM storing operands in floating-point operations into the data segment, RODATA, of the executable.

For example, here the compiler converts 3 into Float64, storing the bytes into the data section, which then requires loading the bytes from memory to run the code:

julia> f(x) = x + 3
f (generic function with 1 method)

julia> @code_native f(1.5)
        .file   "f"
        .section        .rodata.cst8,"aM",@progbits,8
        .p2align        3, 0x0                          # -- Begin function julia_f_2056
.LCPI0_0:
        .quad   0x4008000000000000              # double 3
        .section        .ltext,"axl",@progbits
        .globl  julia_f_2056
        .p2align        4
        .type   julia_f_2056,@function
julia_f_2056:                           # @julia_f_2056
; Function Signature: f(Float64)
; ┌ @ REPL[1]:1 within `f`
# %bb.0:                                # %top
        #DEBUG_VALUE: f:x <- $xmm0
        push    rbp
        mov     rbp, rsp
        movabs  rax, offset .LCPI0_0
; │┌ @ promotion.jl:433 within `+` @ float.jl:492
        vaddsd  xmm0, xmm0, qword ptr [rax]
        pop     rbp
        ret
.Lfunc_end0:
        .size   julia_f_2056, .Lfunc_end0-julia_f_2056
; └└
                                        # -- End function
        .type   ".L+Core.Float64#2058",@object  # @"+Core.Float64#2058"
        .section        .lrodata,"al",@progbits
        .p2align        3, 0x0
".L+Core.Float64#2058":
        .quad   ".L+Core.Float64#2058.jit"
        .size   ".L+Core.Float64#2058", 8

.set ".L+Core.Float64#2058.jit", 140624736139632
        .size   ".L+Core.Float64#2058.jit", 8
        .section        ".note.GNU-stack","",@progbits

It might more sense to instead encode the integer value 3 directly into an instruction loading it into a register, and then load/convert from the integer register into the floating-point register. That way there’s no data memory access.

Am I missing something? Is this really such a low-hanging fruit in LLVM? Or perhaps it’s Julia specific?

It doesn’t seem to be specific to Julia, compare C version vs Julia version vs Rust version.

1 Like