diff --git a/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp index 2700b4307308c..5d3867222f928 100644 --- a/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp +++ b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp @@ -18,6 +18,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/TargetParser/Triple.h" using namespace llvm; @@ -108,6 +109,15 @@ static GlobalVariable *createRelLookupTable(Function &Func, uint64_t Idx = 0; SmallVector RelLookupTableContents(NumElts); + // Apple's ld-classic assigns incorrect relative addresses on + // x86_64-apple-darwin. See https://github.com/rust-lang/rust/issues/140686. + Triple TT(M.getTargetTriple()); + if (TT.isX86() && TT.isOSDarwin()) + for (Use &Operand : LookupTableArr->operands()) { + if (auto *GlobalElement = dyn_cast(Operand)) + GlobalElement->setUnnamedAddr(GlobalValue::UnnamedAddr::None); + } + for (Use &Operand : LookupTableArr->operands()) { Constant *Element = cast(Operand); Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext()); diff --git a/llvm/test/Transforms/RelLookupTableConverter/X86/darwin.ll b/llvm/test/Transforms/RelLookupTableConverter/X86/darwin.ll new file mode 100644 index 0000000000000..61ef6d4f7b908 --- /dev/null +++ b/llvm/test/Transforms/RelLookupTableConverter/X86/darwin.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=x86_64-apple-darwin -S | FileCheck -check-prefix=NO-UNNAMED-ADDR %s +; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=x86_64 -S | FileCheck -check-prefix=UNNAMED-ADDR %s +; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=aarch64-apple-darwin -S | FileCheck -check-prefix=UNNAMED-ADDR %s + +; NO-UNNAMED-ADDR: @L{{.*}} = private constant +; UNNAMED-ADDR: @L{{.*}} = private unnamed_addr constant + +@L1 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 +@L2 = private unnamed_addr constant [8 x i8] c"\01\02\03\04\05\06\07\08", align 1 +@L3 = private unnamed_addr constant [1 x i8] c"\09", align 1 +@switch.table.broken = private unnamed_addr constant [3 x ptr] [ptr @L1, ptr @L2, ptr @L3], align 8 +@switch.table.broken.1 = private unnamed_addr constant [3 x ptr] [ptr getelementptr inbounds ([1 x i8], ptr @L1, i64 1, i64 0), ptr getelementptr inbounds ([8 x i8], ptr @L2, i64 1, i64 0), ptr getelementptr inbounds ([1 x i8], ptr @L3, i64 1, i64 0)], align 8 + +define i64 @broken(i64 %0) { + %2 = getelementptr inbounds [3 x ptr], ptr @switch.table.broken, i64 0, i64 %0 + %3 = load ptr, ptr %2, align 8 + %4 = getelementptr inbounds [3 x ptr], ptr @switch.table.broken.1, i64 0, i64 %0 + %5 = load ptr, ptr %4, align 8 + %6 = tail call i64 @slice_len_from_ptr_end(ptr %3, ptr %5) + ret i64 %6 +} + +declare i64 @slice_len_from_ptr_end(ptr, ptr)