LLVM miscompiles globals with absolute_symbol metadata?


According to LLVM documentation (https://llvm.org/docs/LangRef.html#absolute-symbol-metadata), the ‘absolute_symbol’ metadata can be applied to a global to force absolute relocations and allows expressing the range of the address for the symbol.

However, it seems like LLVM miscompiles the following simple example:

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”

@f = external dso_local global i32, align 4, !absolute_symbol !0

define dso_local i64 @g(i64 %0) {
%2 = add i64 %0, ptrtoint (i32* @f to i64)
ret i64 %2

!0 = !{ i64 0, i64 1000000000000000000 }

After compiling using ‘llc -O=3 -filetype=obj test.ll’, I get the following output:

0000000000000000 :
0: 48 8d 87 00 00 00 00 lea 0x0(%rdi),%rax
3: R_X86_64_32S f

7: c3 retq

This is wrong because ‘f’ has an address range larger than signed 32 bits.

However, if I change the IR to

%2 = add i64 %0, mul(i64 ptrtoint (i32* @f to i64), i64 2)

LLVM compiles correctly and generates an R_X86_64_64 relocation record.

So it seems like a bug in the x86-64 backend lowering where absolute_symbol is not respected in some cases? Any idea on what the problem is and how to fix it?