diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 253d574ac55..0f17e6993ad 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -398,6 +398,9 @@ public: SDNode *getTargetNode(unsigned Opcode, MVT::ValueType VT1, MVT::ValueType VT2, MVT::ValueType VT3, SDOperand Op1, SDOperand Op2); + SDNode *getTargetNode(unsigned Opcode, MVT::ValueType VT1, + MVT::ValueType VT2, MVT::ValueType VT3, + SDOperand Op1, SDOperand Op2, SDOperand Op3); SDNode *getTargetNode(unsigned Opcode, MVT::ValueType VT1, MVT::ValueType VT2, MVT::ValueType VT3, const SDOperand *Ops, unsigned NumOps); diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 74f405f78a4..77d607a2cb6 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -19,6 +19,7 @@ #ifndef LLVM_CODEGEN_SELECTIONDAGNODES_H #define LLVM_CODEGEN_SELECTIONDAGNODES_H +#include "llvm/GlobalVariable.h" #include "llvm/Value.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/GraphTraits.h" @@ -95,7 +96,8 @@ namespace ISD { // Various leaf nodes. STRING, BasicBlock, VALUETYPE, CONDCODE, Register, Constant, ConstantFP, - GlobalAddress, FrameIndex, JumpTable, ConstantPool, ExternalSymbol, + GlobalAddress, GlobalTLSAddress, FrameIndex, + JumpTable, ConstantPool, ExternalSymbol, // The address of the GOT GLOBAL_OFFSET_TABLE, @@ -124,6 +126,7 @@ namespace ISD { // anything else with this node, and this is valid in the target-specific // dag, turning into a GlobalAddress operand. TargetGlobalAddress, + TargetGlobalTLSAddress, TargetFrameIndex, TargetJumpTable, TargetConstantPool, @@ -1164,7 +1167,12 @@ protected: friend class SelectionDAG; GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, MVT::ValueType VT, int o = 0) - : SDNode(isTarget ? ISD::TargetGlobalAddress : ISD::GlobalAddress, + : SDNode(dyn_cast(GA) && + dyn_cast(GA)->isThreadLocal() ? + // Thread Local + (isTarget ? ISD::TargetGlobalTLSAddress : ISD::GlobalTLSAddress) : + // Non Thread Local + (isTarget ? ISD::TargetGlobalAddress : ISD::GlobalAddress), getSDVTList(VT)), Offset(o) { TheGlobal = const_cast(GA); } @@ -1176,11 +1184,12 @@ public: static bool classof(const GlobalAddressSDNode *) { return true; } static bool classof(const SDNode *N) { return N->getOpcode() == ISD::GlobalAddress || - N->getOpcode() == ISD::TargetGlobalAddress; + N->getOpcode() == ISD::TargetGlobalAddress || + N->getOpcode() == ISD::GlobalTLSAddress || + N->getOpcode() == ISD::TargetGlobalTLSAddress; } }; - class FrameIndexSDNode : public SDNode { int FI; virtual void ANCHOR(); // Out-of-line virtual method to give class a home. diff --git a/include/llvm/Target/TargetAsmInfo.h b/include/llvm/Target/TargetAsmInfo.h index 04f9118f837..60de43015dc 100644 --- a/include/llvm/Target/TargetAsmInfo.h +++ b/include/llvm/Target/TargetAsmInfo.h @@ -43,7 +43,15 @@ namespace llvm { /// target doesn't support a BSS section. /// const char *BSSSection; // Default to ".bss". - + + /// TLSDataSection - Section directive for Thread Local data. + /// + const char *TLSDataSection;// Defaults to ".section .tdata,"awT",@progbits". + + /// TLSBSSSection - Section directive for Thread Local uninitialized data. + /// Null if this target doesn't support a BSS section. + /// + const char *TLSBSSSection;// Default to ".section .tbss,"awT",@nobits". /// ZeroFillDirective - Directive for emitting a global to the ZeroFill /// section on this target. Null if this target doesn't support zerofill. const char *ZeroFillDirective; // Default is null. @@ -362,6 +370,12 @@ namespace llvm { const char *getBSSSection() const { return BSSSection; } + const char *getTLSDataSection() const { + return TLSDataSection; + } + const char *getTLSBSSSection() const { + return TLSBSSSection; + } const char *getZeroFillDirective() const { return ZeroFillDirective; } diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index c5288c49ab4..42e7e2268b1 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -622,6 +622,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { case ISD::TargetConstantFP: case ISD::TargetConstantPool: case ISD::TargetGlobalAddress: + case ISD::TargetGlobalTLSAddress: case ISD::TargetExternalSymbol: case ISD::VALUETYPE: case ISD::SRCVALUE: @@ -653,6 +654,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { assert(0 && "Do not know how to legalize this operator!"); abort(); case ISD::GlobalAddress: + case ISD::GlobalTLSAddress: case ISD::ExternalSymbol: case ISD::ConstantPool: case ISD::JumpTable: // Nothing to do. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 7c8a94eaf5e..75fbf8afb9c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -14,6 +14,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Constants.h" #include "llvm/GlobalValue.h" +#include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -296,7 +297,9 @@ static void AddNodeIDNode(FoldingSetNodeID &ID, SDNode *N) { ID.AddDouble(cast(N)->getValue()); break; case ISD::TargetGlobalAddress: - case ISD::GlobalAddress: { + case ISD::GlobalAddress: + case ISD::TargetGlobalTLSAddress: + case ISD::GlobalTLSAddress: { GlobalAddressSDNode *GA = cast(N); ID.AddPointer(GA->getGlobal()); ID.AddInteger(GA->getOffset()); @@ -692,7 +695,12 @@ SDOperand SelectionDAG::getConstantFP(double Val, MVT::ValueType VT, SDOperand SelectionDAG::getGlobalAddress(const GlobalValue *GV, MVT::ValueType VT, int Offset, bool isTargetGA) { - unsigned Opc = isTargetGA ? ISD::TargetGlobalAddress : ISD::GlobalAddress; + const GlobalVariable *GVar = dyn_cast(GV); + unsigned Opc; + if (GVar && GVar->isThreadLocal()) + Opc = isTargetGA ? ISD::TargetGlobalTLSAddress : ISD::GlobalTLSAddress; + else + Opc = isTargetGA ? ISD::TargetGlobalAddress : ISD::GlobalAddress; FoldingSetNodeID ID; AddNodeIDNode(ID, Opc, getVTList(VT), 0, 0); ID.AddPointer(GV); @@ -2282,6 +2290,14 @@ SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1, SDOperand Ops[] = { Op1, Op2 }; return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, 3, Ops, 2).Val; } +SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1, + MVT::ValueType VT2, MVT::ValueType VT3, + SDOperand Op1, SDOperand Op2, + SDOperand Op3) { + const MVT::ValueType *VTs = getNodeValueTypes(VT1, VT2, VT3); + SDOperand Ops[] = { Op1, Op2, Op3 }; + return getNode(ISD::BUILTIN_OP_END+Opcode, VTs, 3, Ops, 3).Val; +} SDNode *SelectionDAG::getTargetNode(unsigned Opcode, MVT::ValueType VT1, MVT::ValueType VT2, MVT::ValueType VT3, const SDOperand *Ops, unsigned NumOps) { @@ -2702,6 +2718,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::Constant: return "Constant"; case ISD::ConstantFP: return "ConstantFP"; case ISD::GlobalAddress: return "GlobalAddress"; + case ISD::GlobalTLSAddress: return "GlobalTLSAddress"; case ISD::FrameIndex: return "FrameIndex"; case ISD::JumpTable: return "JumpTable"; case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE"; @@ -2725,6 +2742,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::TargetConstant: return "TargetConstant"; case ISD::TargetConstantFP:return "TargetConstantFP"; case ISD::TargetGlobalAddress: return "TargetGlobalAddress"; + case ISD::TargetGlobalTLSAddress: return "TargetGlobalTLSAddress"; case ISD::TargetFrameIndex: return "TargetFrameIndex"; case ISD::TargetJumpTable: return "TargetJumpTable"; case ISD::TargetConstantPool: return "TargetConstantPool"; diff --git a/lib/Target/TargetAsmInfo.cpp b/lib/Target/TargetAsmInfo.cpp index cf3f6eec39a..62c8b90e7bf 100644 --- a/lib/Target/TargetAsmInfo.cpp +++ b/lib/Target/TargetAsmInfo.cpp @@ -20,6 +20,8 @@ TargetAsmInfo::TargetAsmInfo() : TextSection(".text"), DataSection(".data"), BSSSection(".bss"), + TLSDataSection("\t.section .tdata,\"awT\",@progbits"), + TLSBSSSection("\t.section .tbss,\"awT\",@nobits"), ZeroFillDirective(0), AddressSize(4), NeedsSet(false), diff --git a/lib/Target/TargetSelectionDAG.td b/lib/Target/TargetSelectionDAG.td index 17c0ddd12f3..3d728e9062c 100644 --- a/lib/Target/TargetSelectionDAG.td +++ b/lib/Target/TargetSelectionDAG.td @@ -211,6 +211,10 @@ def globaladdr : SDNode<"ISD::GlobalAddress", SDTPtrLeaf, [], "GlobalAddressSDNode">; def tglobaladdr : SDNode<"ISD::TargetGlobalAddress", SDTPtrLeaf, [], "GlobalAddressSDNode">; +def globaltlsaddr : SDNode<"ISD::GlobalTLSAddress", SDTPtrLeaf, [], + "GlobalAddressSDNode">; +def tglobaltlsaddr : SDNode<"ISD::TargetGlobalTLSAddress", SDTPtrLeaf, [], + "GlobalAddressSDNode">; def constpool : SDNode<"ISD::ConstantPool", SDTPtrLeaf, [], "ConstantPoolSDNode">; def tconstpool : SDNode<"ISD::TargetConstantPool", SDTPtrLeaf, [], diff --git a/lib/Target/X86/X86ATTAsmPrinter.cpp b/lib/Target/X86/X86ATTAsmPrinter.cpp index f80e6e851c9..f36de92bb39 100755 --- a/lib/Target/X86/X86ATTAsmPrinter.cpp +++ b/lib/Target/X86/X86ATTAsmPrinter.cpp @@ -272,9 +272,13 @@ void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, case MachineOperand::MO_GlobalAddress: { bool isCallOp = Modifier && !strcmp(Modifier, "call"); bool isMemOp = Modifier && !strcmp(Modifier, "mem"); - if (!isMemOp && !isCallOp) O << '$'; GlobalValue *GV = MO.getGlobal(); + GlobalVariable *GVar = dyn_cast(GV); + bool isThreadLocal = GVar && GVar->isThreadLocal(); + + if (!isMemOp && !isCallOp && !isThreadLocal) O << '$'; + std::string Name = Mang->getValueName(GV); X86SharedAsmPrinter::decorateName(Name, GV); @@ -328,7 +332,15 @@ void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, else if (Offset < 0) O << Offset; - if (isMemOp) { + if (isThreadLocal) { + if (TM.getRelocationModel() == Reloc::PIC_) + O << "@TLSGD"; // general dynamic TLS model + else + if (GV->isDeclaration()) + O << "@INDNTPOFF"; // initial exec TLS model + else + O << "@NTPOFF"; // local exec TLS model + } else if (isMemOp) { if (printGOT(TM, Subtarget)) { if (Subtarget->GVRequiresExtraLoad(GV, TM, false)) O << "@GOT"; diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp index bc103d70f17..76037f13bd5 100644 --- a/lib/Target/X86/X86AsmPrinter.cpp +++ b/lib/Target/X86/X86AsmPrinter.cpp @@ -171,7 +171,7 @@ bool X86SharedAsmPrinter::doFinalization(Module &M) { } } - if (!I->hasSection() && + if (!I->hasSection() && !I->isThreadLocal() && (I->hasInternalLinkage() || I->hasWeakLinkage() || I->hasLinkOnceLinkage())) { if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. @@ -256,9 +256,13 @@ bool X86SharedAsmPrinter::doFinalization(Module &M) { SwitchToDataSection(SectionName.c_str()); } else { if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection()) - SwitchToDataSection(TAI->getBSSSection(), I); + SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSBSSSection() : + TAI->getBSSSection(), I); else if (!I->isConstant()) - SwitchToDataSection(TAI->getDataSection(), I); + SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSDataSection() : + TAI->getDataSection(), I); + else if (I->isThreadLocal()) + SwitchToDataSection(TAI->getTLSDataSection()); else { // Read-only data. bool HasReloc = C->ContainsRelocations(); diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 747a15b9476..b37e47cb03e 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -20,6 +20,7 @@ #include "llvm/CallingConv.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" #include "llvm/Function.h" #include "llvm/Intrinsics.h" #include "llvm/ADT/VectorExtras.h" @@ -200,6 +201,7 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM) setOperationAction(ISD::ConstantPool , MVT::i32 , Custom); setOperationAction(ISD::JumpTable , MVT::i32 , Custom); setOperationAction(ISD::GlobalAddress , MVT::i32 , Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32 , Custom); setOperationAction(ISD::ExternalSymbol , MVT::i32 , Custom); if (Subtarget->is64Bit()) { setOperationAction(ISD::ConstantPool , MVT::i64 , Custom); @@ -2943,6 +2945,76 @@ X86TargetLowering::LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG) { return Result; } +// Lower ISD::GlobalTLSAddress using the "general dynamic" model +static SDOperand +LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, SelectionDAG &DAG, + const MVT::ValueType PtrVT) { + SDOperand InFlag; + SDOperand Chain = DAG.getCopyToReg(DAG.getEntryNode(), X86::EBX, + DAG.getNode(X86ISD::GlobalBaseReg, + PtrVT), InFlag); + InFlag = Chain.getValue(1); + + // emit leal symbol@TLSGD(,%ebx,1), %eax + SDVTList NodeTys = DAG.getVTList(PtrVT, MVT::Other, MVT::Flag); + SDOperand TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), + GA->getValueType(0), + GA->getOffset()); + SDOperand Ops[] = { Chain, TGA, InFlag }; + SDOperand Result = DAG.getNode(X86ISD::TLSADDR, NodeTys, Ops, 3); + InFlag = Result.getValue(2); + Chain = Result.getValue(1); + + // call ___tls_get_addr. This function receives its argument in + // the register EAX. + Chain = DAG.getCopyToReg(Chain, X86::EAX, Result, InFlag); + InFlag = Chain.getValue(1); + + NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + SDOperand Ops1[] = { Chain, + DAG.getTargetExternalSymbol("___tls_get_addr", + PtrVT), + DAG.getRegister(X86::EAX, PtrVT), + DAG.getRegister(X86::EBX, PtrVT), + InFlag }; + Chain = DAG.getNode(X86ISD::CALL, NodeTys, Ops1, 5); + InFlag = Chain.getValue(1); + + return DAG.getCopyFromReg(Chain, X86::EAX, PtrVT, InFlag); +} + +// Lower ISD::GlobalTLSAddress using the "initial exec" (for no-pic) or +// "local exec" model. +static SDOperand +LowerToTLSExecModel(GlobalAddressSDNode *GA, SelectionDAG &DAG, + const MVT::ValueType PtrVT) { + // Get the Thread Pointer + SDOperand ThreadPointer = DAG.getNode(X86ISD::THREAD_POINTER, PtrVT); + // emit "addl x@ntpoff,%eax" (local exec) or "addl x@indntpoff,%eax" (initial + // exec) + SDOperand TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), + GA->getValueType(0), + GA->getOffset()); + SDOperand Offset = DAG.getNode(X86ISD::Wrapper, PtrVT, TGA); + // The address of the thread local variable is the add of the thread + // pointer with the offset of the variable. + return DAG.getNode(ISD::ADD, PtrVT, ThreadPointer, Offset); +} + +SDOperand +X86TargetLowering::LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG) { + // TODO: implement the "local dynamic" model + // TODO: implement the "initial exec"model for pic executables + assert(!Subtarget->is64Bit() && "TLS not implemented for X86_64"); + GlobalAddressSDNode *GA = cast(Op); + // If the relocation model is PIC, use the "General Dynamic" TLS Model, + // otherwise use the "Local Exec"TLS Model + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) + return LowerToTLSGeneralDynamicModel(GA, DAG, getPointerTy()); + else + return LowerToTLSExecModel(GA, DAG, getPointerTy()); +} + SDOperand X86TargetLowering::LowerExternalSymbol(SDOperand Op, SelectionDAG &DAG) { const char *Sym = cast(Op)->getSymbol(); @@ -4022,6 +4094,7 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) { case ISD::SCALAR_TO_VECTOR: return LowerSCALAR_TO_VECTOR(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG); case ISD::SHL_PARTS: case ISD::SRA_PARTS: @@ -4090,6 +4163,8 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::PINSRW: return "X86ISD::PINSRW"; case X86ISD::FMAX: return "X86ISD::FMAX"; case X86ISD::FMIN: return "X86ISD::FMIN"; + case X86ISD::TLSADDR: return "X86ISD::TLSADDR"; + case X86ISD::THREAD_POINTER: return "X86ISD::THREAD_POINTER"; } } diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 8b9c269dca4..88064d37c6e 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -176,7 +176,9 @@ namespace llvm { /// FMAX, FMIN - Floating point max and min. /// - FMAX, FMIN + FMAX, FMIN, + // Thread Local Storage + TLSADDR, THREAD_POINTER }; } @@ -386,6 +388,7 @@ namespace llvm { SDOperand LowerSCALAR_TO_VECTOR(SDOperand Op, SelectionDAG &DAG); SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG); SDOperand LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG); SDOperand LowerExternalSymbol(SDOperand Op, SelectionDAG &DAG); SDOperand LowerShift(SDOperand Op, SelectionDAG &DAG); SDOperand LowerSINT_TO_FP(SDOperand Op, SelectionDAG &DAG); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index bfdaff6b1a8..fdc2bc923fe 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -47,6 +47,10 @@ def SDTX86RdTsc : SDTypeProfile<0, 0, []>; def SDTX86Wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; +def SDT_X86TLSADDR : SDTypeProfile<1, 1, [SDTCisPtrTy<0>, SDTCisInt<1>]>; + +def SDT_X86TLSTP : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; + def X86shld : SDNode<"X86ISD::SHLD", SDTIntShiftDOp>; def X86shrd : SDNode<"X86ISD::SHRD", SDTIntShiftDOp>; @@ -87,6 +91,11 @@ def X86rdtsc : SDNode<"X86ISD::RDTSC_DAG",SDTX86RdTsc, def X86Wrapper : SDNode<"X86ISD::Wrapper", SDTX86Wrapper>; def X86WrapperRIP : SDNode<"X86ISD::WrapperRIP", SDTX86Wrapper>; +def X86tlsaddr : SDNode<"X86ISD::TLSADDR", SDT_X86TLSADDR, + [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; +def X86TLStp : SDNode<"X86ISD::THREAD_POINTER", SDT_X86TLSTP, []>; + + //===----------------------------------------------------------------------===// // X86 Operand Definitions. // @@ -2448,6 +2457,19 @@ def MOV16_mr : I<0x89, MRMDestMem, (ops i16mem:$dst, GR16_:$src), def MOV32_mr : I<0x89, MRMDestMem, (ops i32mem:$dst, GR32_:$src), "mov{l} {$src, $dst|$dst, $src}", []>; +//===----------------------------------------------------------------------===// +// Thread Local Storage Instructions +// + +def TLS_addr : I<0, Pseudo, (ops GR32:$dst, i32imm:$sym), + "leal $sym(,%ebx,1), $dst", + [(set GR32:$dst, (X86tlsaddr tglobaltlsaddr:$sym))]>, + Imp<[EBX],[]>; + +def TLS_tp : I<0, Pseudo, (ops GR32:$dst), + "movl %gs:0, $dst", + [(set GR32:$dst, X86TLStp)]>; + //===----------------------------------------------------------------------===// // DWARF Pseudo Instructions // diff --git a/utils/TableGen/DAGISelEmitter.cpp b/utils/TableGen/DAGISelEmitter.cpp index 6ad7999c3f5..11f7f77e9d4 100644 --- a/utils/TableGen/DAGISelEmitter.cpp +++ b/utils/TableGen/DAGISelEmitter.cpp @@ -2654,10 +2654,12 @@ public: } else { NodeOps.push_back(Val); } - } else if (!N->isLeaf() && N->getOperator()->getName() == "tglobaladdr") { + } else if (!N->isLeaf() && (N->getOperator()->getName() == "tglobaladdr" + || N->getOperator()->getName() == "tglobaltlsaddr")) { Record *Op = OperatorMap[N->getName()]; // Transform GlobalAddress to TargetGlobalAddress - if (Op && Op->getName() == "globaladdr") { + if (Op && (Op->getName() == "globaladdr" || + Op->getName() == "globaltlsaddr")) { emitCode("SDOperand Tmp" + utostr(ResNo) + " = CurDAG->getTarget" "GlobalAddress(cast(" + Val + ")->getGlobal(), " + getEnumName(N->getTypeNum(0)) + @@ -3716,6 +3718,7 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) { << " case ISD::TargetConstantPool:\n" << " case ISD::TargetFrameIndex:\n" << " case ISD::TargetJumpTable:\n" + << " case ISD::TargetGlobalTLSAddress:\n" << " case ISD::TargetGlobalAddress: {\n" << " return NULL;\n" << " }\n"