diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -374,6 +374,12 @@ "Insert LFENCE instructions to prevent data speculatively injected " "into loads from being used maliciously.">; +def FeatureTaggedGlobals + : SubtargetFeature< + "tagged-globals", "AllowTaggedGlobals", "true", + "Use an instruction sequence for taking the address of a global " + "that allows a memory tag in the upper address bits.">; + //===----------------------------------------------------------------------===// // X86 Subtarget Tuning features //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h --- a/llvm/lib/Target/X86/X86Subtarget.h +++ b/llvm/lib/Target/X86/X86Subtarget.h @@ -476,6 +476,10 @@ /// loads from being used maliciously. bool UseLVILoadHardening = false; + /// Use an instruction sequence for taking the address of a global that allows + /// a memory tag in the upper address bits. + bool AllowTaggedGlobals = false; + /// Use software floating point for code generation. bool UseSoftFloat = false; @@ -795,6 +799,7 @@ bool preferMaskRegisters() const { return PreferMaskRegisters; } bool useGLMDivSqrtCosts() const { return UseGLMDivSqrtCosts; } bool useLVIControlFlowIntegrity() const { return UseLVIControlFlowIntegrity; } + bool allowTaggedGlobals() const { return AllowTaggedGlobals; } bool useLVILoadHardening() const { return UseLVILoadHardening; } bool useSpeculativeExecutionSideEffectSuppression() const { return UseSpeculativeExecutionSideEffectSuppression; diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -67,6 +67,13 @@ unsigned char X86Subtarget::classifyLocalReference(const GlobalValue *GV) const { + // Tagged globals have non-zero upper bits, which makes direct references + // require a 64-bit immediate. On the small code model this causes relocation + // errors, so we go through the GOT instead. + if (AllowTaggedGlobals && TM.getCodeModel() == CodeModel::Small && + !isa_and_nonnull(GV)) + return X86II::MO_GOTPCREL; + // If we're not PIC, it's not very interesting. if (!isPositionIndependent()) return X86II::MO_NO_FLAG; diff --git a/llvm/test/CodeGen/X86/tagged-globals-pic.ll b/llvm/test/CodeGen/X86/tagged-globals-pic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/tagged-globals-pic.ll @@ -0,0 +1,45 @@ +; RUN: llc --relocation-model=pic < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@global = external global i32 +declare void @func() + +define i32* @global_addr() #0 { + ; CHECK-LABEL: global_addr: + ; CHECK: movq global@GOTPCREL(%rip), %rax + ; CHECK: retq + + ret i32* @global +} + +define i32 @global_load() #0 { + ; CHECK-LABEL: global_load: + ; CHECK: movq global@GOTPCREL(%rip), [[REG:%r[0-9a-z]+]] + ; CHECK: movl ([[REG]]), %eax + ; CHECK: retq + + %load = load i32, i32* @global + ret i32 %load +} + +define void @global_store() #0 { + ; CHECK-LABEL: global_store: + ; CHECK: movq global@GOTPCREL(%rip), [[REG:%r[0-9a-z]+]] + ; CHECK: movl $0, ([[REG]]) + ; CHECK: retq + + store i32 0, i32* @global + ret void +} + +define void ()* @func_addr() #0 { + ; CHECK-LABEL: func_addr: + ; CHECK: movq func@GOTPCREL(%rip), %rax + ; CHECK: retq + + ret void ()* @func +} + +attributes #0 = { "target-features"="+tagged-globals" } diff --git a/llvm/test/CodeGen/X86/tagged-globals-static.ll b/llvm/test/CodeGen/X86/tagged-globals-static.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/tagged-globals-static.ll @@ -0,0 +1,45 @@ +; RUN: llc --relocation-model=static < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@global = external dso_local global i32 +declare dso_local void @func() + +define i32* @global_addr() #0 { + ; CHECK-LABEL: global_addr: + ; CHECK: movq global@GOTPCREL(%rip), %rax + ; CHECK: retq + + ret i32* @global +} + +define i32 @global_load() #0 { + ; CHECK-LABEL: global_load: + ; CHECK: movq global@GOTPCREL(%rip), [[REG:%r[0-9a-z]+]] + ; CHECK: movl ([[REG]]), %eax + ; CHECK: retq + + %load = load i32, i32* @global + ret i32 %load +} + +define void @global_store() #0 { + ; CHECK-LABEL: global_store: + ; CHECK: movq global@GOTPCREL(%rip), [[REG:%r[0-9a-z]+]] + ; CHECK: movl $0, ([[REG]]) + ; CHECK: retq + + store i32 0, i32* @global + ret void +} + +define void ()* @func_addr() #0 { + ; CHECK-LABEL: func_addr: + ; CHECK: movl $func, %eax + ; CHECK: retq + + ret void ()* @func +} + +attributes #0 = { "target-features"="+tagged-globals" }