I have encountered an odd issue where LLVM fails to compile arithmetic referencing a local function on Linux/x64.
Here is a minimal (hopefully reproducible) snippet:
; min_test.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define dso_local void @myFunction() {
ret void
}
define i64 @main() {
%1 = ptrtoint ptr @myFunction to i64
%2 = sub i64 %1, 2147483648 ; = 0x80000000
%3 = lshr i64 %2, 1 ; `add` also fails
ret i64 %3
}
I am compiling on Linux/x64 with:
/llvm-17/bin/clang++ -O1 -c min_test.ll -o min_test.o
This gives the following error:
<unknown>:0: error: value of -2147483671 is too large for field of 4 bytes.
error: cannot compile inline asm
1 error generated.
I have found that:
- It fails with LLVM 15, 16, and 17 (I haven’t tested other versions)
- The snippet fails on Linux/x64, but compiles successfully on MacOS/arm64
- Compilation only fails when
myFunction
is declared asdso_local
. - Interestingly, after adding 1 to the integer constant (2147483649 = 0x80000001), the program compiles successfully.
My expectation is that the pointer to myFunction
would be stored in a register, and arithmetic instructions emitted working on that register. (This is indeed the case when changing the integer constant so it compiles successfully). I am not sure where the field of 4 bytes is coming from.
If anyone has any ideas why this might be happening I would appreciate your thoughts!
Thanks