Skip to content

Commit

Permalink
[X86] Add Support for X86 TLSDESC Relocations (#83136)
Browse files Browse the repository at this point in the history
  • Loading branch information
phoebewang committed Mar 15, 2024
1 parent 0b9f19a commit f4676b6
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 19 deletions.
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,8 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC,
SupportedArgument = V == "desc" || V == "trad";
EnableTLSDESC = V == "desc";
} else if (Triple.isX86()) {
SupportedArgument = V == "gnu";
SupportedArgument = V == "gnu" || V == "gnu2";
EnableTLSDESC = V == "gnu2";
} else {
Unsupported = true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/tls-dialect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// RUN: %clang -### --target=riscv64-linux -mtls-dialect=trad %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=riscv64-linux %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=x86_64-linux -mtls-dialect=gnu %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=x86_64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=DESC %s

/// Android supports TLSDESC by default on RISC-V
/// TLSDESC is not on by default in Linux, even on RISC-V, and is covered above
Expand All @@ -18,7 +19,6 @@

/// Unsupported argument
// RUN: not %clang -### --target=riscv64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s
// RUN: not %clang -### --target=x86_64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s

// DESC: "-cc1" {{.*}}"-enable-tlsdesc"
// NODESC-NOT: "-enable-tlsdesc"
Expand Down
16 changes: 11 additions & 5 deletions llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3090,13 +3090,19 @@ bool X86DAGToDAGISel::selectLEAAddr(SDValue N,
bool X86DAGToDAGISel::selectTLSADDRAddr(SDValue N, SDValue &Base,
SDValue &Scale, SDValue &Index,
SDValue &Disp, SDValue &Segment) {
assert(N.getOpcode() == ISD::TargetGlobalTLSAddress);
auto *GA = cast<GlobalAddressSDNode>(N);
assert(N.getOpcode() == ISD::TargetGlobalTLSAddress ||
N.getOpcode() == ISD::TargetExternalSymbol);

X86ISelAddressMode AM;
AM.GV = GA->getGlobal();
AM.Disp += GA->getOffset();
AM.SymbolFlags = GA->getTargetFlags();
if (auto *GA = dyn_cast<GlobalAddressSDNode>(N)) {
AM.GV = GA->getGlobal();
AM.Disp += GA->getOffset();
AM.SymbolFlags = GA->getTargetFlags();
} else {
auto *SA = cast<ExternalSymbolSDNode>(N);
AM.ES = SA->getSymbol();
AM.SymbolFlags = SA->getTargetFlags();
}

if (Subtarget->is32Bit()) {
AM.Scale = 1;
Expand Down
38 changes: 31 additions & 7 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18592,13 +18592,22 @@ GetTLSADDR(SelectionDAG &DAG, SDValue Chain, GlobalAddressSDNode *GA,
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
SDLoc dl(GA);
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl,
GA->getValueType(0),
GA->getOffset(),
OperandFlags);
SDValue TGA;
bool UseTLSDESC = DAG.getTarget().useTLSDESC();
if (LocalDynamic && UseTLSDESC) {
TGA = DAG.getTargetExternalSymbol("_TLS_MODULE_BASE_", PtrVT, OperandFlags);
auto UI = TGA->use_begin();
// Reuse existing GetTLSADDR node if we can find it.
if (UI != TGA->use_end())
return SDValue(*UI->use_begin()->use_begin(), 0);
} else {
TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, GA->getValueType(0),
GA->getOffset(), OperandFlags);
}

X86ISD::NodeType CallType = LocalDynamic ? X86ISD::TLSBASEADDR
: X86ISD::TLSADDR;
X86ISD::NodeType CallType = UseTLSDESC ? X86ISD::TLSDESC
: LocalDynamic ? X86ISD::TLSBASEADDR
: X86ISD::TLSADDR;

if (InGlue) {
SDValue Ops[] = { Chain, TGA, *InGlue };
Expand All @@ -18613,7 +18622,19 @@ GetTLSADDR(SelectionDAG &DAG, SDValue Chain, GlobalAddressSDNode *GA,
MFI.setHasCalls(true);

SDValue Glue = Chain.getValue(1);
return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Glue);
SDValue Ret = DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Glue);

if (!UseTLSDESC)
return Ret;

const X86Subtarget &Subtarget = DAG.getSubtarget<X86Subtarget>();
unsigned Seg = Subtarget.is64Bit() ? X86AS::FS : X86AS::GS;

Value *Ptr = Constant::getNullValue(PointerType::get(*DAG.getContext(), Seg));
SDValue Offset =
DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), DAG.getIntPtrConstant(0, dl),
MachinePointerInfo(Ptr));
return DAG.getNode(ISD::ADD, dl, PtrVT, Ret, Offset);
}

// Lower ISD::GlobalTLSAddress using the "general dynamic" model, 32 bit
Expand Down Expand Up @@ -33426,6 +33447,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(TLSADDR)
NODE_NAME_CASE(TLSBASEADDR)
NODE_NAME_CASE(TLSCALL)
NODE_NAME_CASE(TLSDESC)
NODE_NAME_CASE(EH_SJLJ_SETJMP)
NODE_NAME_CASE(EH_SJLJ_LONGJMP)
NODE_NAME_CASE(EH_SJLJ_SETUP_DISPATCH)
Expand Down Expand Up @@ -36206,6 +36228,8 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case X86::TLS_base_addr32:
case X86::TLS_base_addr64:
case X86::TLS_base_addrX32:
case X86::TLS_desc32:
case X86::TLS_desc64:
return EmitLoweredTLSAddr(MI, BB);
case X86::INDIRECT_THUNK_CALL32:
case X86::INDIRECT_THUNK_CALL64:
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/X86/X86ISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ namespace llvm {
// thunk at the address from an earlier relocation.
TLSCALL,

// Thread Local Storage. A descriptor containing pointer to
// code and to argument to get the TLS offset for the symbol.
TLSDESC,

// Exception Handling helpers.
EH_RETURN,

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/X86/X86InstrCompiler.td
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,16 @@ def TLS_base_addrX32 : I<0, Pseudo, (outs), (ins i32mem:$sym),
Requires<[In64BitMode, NotLP64]>;
}

// TLSDESC only clobbers EAX and EFLAGS. ESP is marked as a use to prevent
// stack-pointer assignments that appear immediately before calls from
// potentially appearing dead.
let Defs = [EAX, EFLAGS], usesCustomInserter = 1, Uses = [RSP, SSP] in {
def TLS_desc32 : I<0, Pseudo, (outs), (ins i32mem:$sym),
"# TLS_desc32", [(X86tlsdesc tls32addr:$sym)]>;
def TLS_desc64 : I<0, Pseudo, (outs), (ins i64mem:$sym),
"# TLS_desc64", [(X86tlsdesc tls64addr:$sym)]>;
}

// Darwin TLS Support
// For i386, the address of the thunk is passed on the stack, on return the
// address of the variable is in %eax. %ecx is trashed during the function
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/X86InstrFragments.td
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ def X86tlsaddr : SDNode<"X86ISD::TLSADDR", SDT_X86TLSADDR,
def X86tlsbaseaddr : SDNode<"X86ISD::TLSBASEADDR", SDT_X86TLSBASEADDR,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;

def X86tlsdesc : SDNode<"X86ISD::TLSDESC", SDT_X86TLSADDR,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;

def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
[SDNPHasChain]>;

Expand Down
33 changes: 28 additions & 5 deletions llvm/lib/Target/X86/X86MCInstLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,10 +519,8 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering,
const MachineInstr &MI) {
NoAutoPaddingScope NoPadScope(*OutStreamer);
bool Is64Bits = MI.getOpcode() != X86::TLS_addr32 &&
MI.getOpcode() != X86::TLS_base_addr32;
bool Is64BitsLP64 = MI.getOpcode() == X86::TLS_addr64 ||
MI.getOpcode() == X86::TLS_base_addr64;
bool Is64Bits = getSubtarget().is64Bit();
bool Is64BitsLP64 = getSubtarget().isTarget64BitLP64();
MCContext &Ctx = OutStreamer->getContext();

MCSymbolRefExpr::VariantKind SRVK;
Expand All @@ -539,6 +537,10 @@ void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering,
case X86::TLS_base_addrX32:
SRVK = MCSymbolRefExpr::VK_TLSLD;
break;
case X86::TLS_desc32:
case X86::TLS_desc64:
SRVK = MCSymbolRefExpr::VK_TLSDESC;
break;
default:
llvm_unreachable("unexpected opcode");
}
Expand All @@ -554,7 +556,26 @@ void X86AsmPrinter::LowerTlsAddr(X86MCInstLower &MCInstLowering,
bool UseGot = MMI->getModule()->getRtLibUseGOT() &&
Ctx.getTargetOptions()->X86RelaxRelocations;

if (Is64Bits) {
if (SRVK == MCSymbolRefExpr::VK_TLSDESC) {
const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(
MCInstLowering.GetSymbolFromOperand(MI.getOperand(3)),
MCSymbolRefExpr::VK_TLSCALL, Ctx);
EmitAndCountInstruction(
MCInstBuilder(Is64BitsLP64 ? X86::LEA64r : X86::LEA32r)
.addReg(Is64BitsLP64 ? X86::RAX : X86::EAX)
.addReg(Is64Bits ? X86::RIP : X86::EBX)
.addImm(1)
.addReg(0)
.addExpr(Sym)
.addReg(0));
EmitAndCountInstruction(
MCInstBuilder(Is64Bits ? X86::CALL64m : X86::CALL32m)
.addReg(Is64BitsLP64 ? X86::RAX : X86::EAX)
.addImm(1)
.addReg(0)
.addExpr(Expr)
.addReg(0));
} else if (Is64Bits) {
bool NeedsPadding = SRVK == MCSymbolRefExpr::VK_TLSGD;
if (NeedsPadding && Is64BitsLP64)
EmitAndCountInstruction(MCInstBuilder(X86::DATA16_PREFIX));
Expand Down Expand Up @@ -2164,6 +2185,8 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) {
case X86::TLS_base_addr32:
case X86::TLS_base_addr64:
case X86::TLS_base_addrX32:
case X86::TLS_desc32:
case X86::TLS_desc64:
return LowerTlsAddr(MCInstLowering, *MI);

case X86::MOVPC32r: {
Expand Down

0 comments on commit f4676b6

Please sign in to comment.