diff options
-rw-r--r-- | lib/Target/ARM/ARMAsmPrinter.cpp | 16 | ||||
-rw-r--r-- | lib/Target/ARM/ARMConstantPoolValue.cpp | 19 | ||||
-rw-r--r-- | lib/Target/ARM/ARMConstantPoolValue.h | 8 | ||||
-rw-r--r-- | lib/Target/ARM/ARMISelLowering.cpp | 89 | ||||
-rw-r--r-- | lib/Target/ARM/ARMISelLowering.h | 9 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.td | 15 | ||||
-rw-r--r-- | lib/Target/ARM/ARMInstrThumb.td | 12 | ||||
-rw-r--r-- | lib/Target/ARM/ARMTargetAsmInfo.cpp | 2 |
8 files changed, 157 insertions, 13 deletions
diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 6e9a9038dc..d873378986 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -134,10 +134,14 @@ namespace { } else O << Name; if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; - if (ACPV->getPCAdjustment() != 0) + if (ACPV->getPCAdjustment() != 0) { O << "-(" << TAI->getPrivateGlobalPrefix() << "PC" << utostr(ACPV->getLabelId()) - << "+" << (unsigned)ACPV->getPCAdjustment() << ")"; + << "+" << (unsigned)ACPV->getPCAdjustment(); + if (ACPV->mustAddCurrentAddress()) + O << "-."; + O << ")"; + } O << "\n"; // If the constant pool value is a extern weak symbol, remember to emit @@ -869,9 +873,13 @@ bool ARMAsmPrinter::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/ARM/ARMConstantPoolValue.cpp b/lib/Target/ARM/ARMConstantPoolValue.cpp index 1fe66fb174..30a8eafefd 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.cpp +++ b/lib/Target/ARM/ARMConstantPoolValue.cpp @@ -20,18 +20,20 @@ using namespace llvm; ARMConstantPoolValue::ARMConstantPoolValue(GlobalValue *gv, unsigned id, ARMCP::ARMCPKind k, unsigned char PCAdj, - const char *Modif) + const char *Modif, + bool AddCA) : MachineConstantPoolValue((const Type*)gv->getType()), GV(gv), S(NULL), LabelId(id), Kind(k), PCAdjust(PCAdj), - Modifier(Modif) {} + Modifier(Modif), AddCurrentAddress(AddCA) {} ARMConstantPoolValue::ARMConstantPoolValue(const char *s, unsigned id, ARMCP::ARMCPKind k, unsigned char PCAdj, - const char *Modif) + const char *Modif, + bool AddCA) : MachineConstantPoolValue((const Type*)Type::Int32Ty), GV(NULL), S(s), LabelId(id), Kind(k), PCAdjust(PCAdj), - Modifier(Modif) {} + Modifier(Modif), AddCurrentAddress(AddCA) {} ARMConstantPoolValue::ARMConstantPoolValue(GlobalValue *gv, ARMCP::ARMCPKind k, @@ -78,6 +80,11 @@ void ARMConstantPoolValue::print(std::ostream &O) const { if (isNonLazyPointer()) O << "$non_lazy_ptr"; else if (isStub()) O << "$stub"; if (Modifier) O << "(" << Modifier << ")"; - if (PCAdjust != 0) O << "-(LPIC" << LabelId << "+" - << (unsigned)PCAdjust << ")"; + if (PCAdjust != 0) { + O << "-(LPIC" << LabelId << "+" + << (unsigned)PCAdjust; + if (AddCurrentAddress) + O << "-."; + O << ")"; + } } diff --git a/lib/Target/ARM/ARMConstantPoolValue.h b/lib/Target/ARM/ARMConstantPoolValue.h index b7511aa8dd..d71bcf0ff4 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.h +++ b/lib/Target/ARM/ARMConstantPoolValue.h @@ -37,14 +37,17 @@ class ARMConstantPoolValue : public MachineConstantPoolValue { unsigned char PCAdjust; // Extra adjustment if constantpool is pc relative. // 8 for ARM, 4 for Thumb. const char *Modifier; // GV modifier i.e. (&GV(modifier)-(LPIC+8)) + bool AddCurrentAddress; public: ARMConstantPoolValue(GlobalValue *gv, unsigned id, ARMCP::ARMCPKind Kind = ARMCP::CPValue, - unsigned char PCAdj = 0, const char *Modifier = NULL); + unsigned char PCAdj = 0, const char *Modifier = NULL, + bool AddCurrentAddress = false); ARMConstantPoolValue(const char *s, unsigned id, ARMCP::ARMCPKind Kind = ARMCP::CPValue, - unsigned char PCAdj = 0, const char *Modifier = NULL); + unsigned char PCAdj = 0, const char *Modifier = NULL, + bool AddCurrentAddress = false); ARMConstantPoolValue(GlobalValue *GV, ARMCP::ARMCPKind Kind, const char *Modifier); @@ -53,6 +56,7 @@ public: const char *getSymbol() const { return S; } const char *getModifier() const { return Modifier; } bool hasModifier() const { return Modifier != NULL; } + bool mustAddCurrentAddress() const { return AddCurrentAddress; } unsigned getLabelId() const { return LabelId; } bool isNonLazyPointer() const { return Kind == ARMCP::CPNonLazyPtr; } bool isStub() const { return Kind == ARMCP::CPStub; } diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 529467a26e..747a2879d4 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -186,6 +186,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); setOperationAction(ISD::ConstantPool, MVT::i32, Custom); setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); // Expand mem operations genericly. setOperationAction(ISD::MEMSET , MVT::Other, Expand); @@ -293,6 +294,8 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::FMRRD: return "ARMISD::FMRRD"; case ARMISD::FMDRR: return "ARMISD::FMDRR"; + + case ARMISD::THREAD_POINTER:return "ARMISD::THREAD_POINTER"; } } @@ -701,6 +704,91 @@ static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) { return DAG.getNode(ARMISD::Wrapper, MVT::i32, Res); } +// Lower ISD::GlobalTLSAddress using the "general dynamic" model +SDOperand +ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) { + MVT::ValueType PtrVT = getPointerTy(); + unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; + ARMConstantPoolValue *CPV = + new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue, + PCAdj, "tlsgd", true); + SDOperand Argument = DAG.getTargetConstantPool(CPV, PtrVT, 2); + Argument = DAG.getNode(ARMISD::Wrapper, MVT::i32, Argument); + Argument = DAG.getLoad(PtrVT, DAG.getEntryNode(), Argument, NULL, 0); + SDOperand Chain = Argument.getValue(1); + + SDOperand PICLabel = DAG.getConstant(ARMPCLabelIndex++, MVT::i32); + Argument = DAG.getNode(ARMISD::PIC_ADD, PtrVT, Argument, PICLabel); + + // call __tls_get_addr. + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Argument; + Entry.Ty = (const Type *) Type::Int32Ty; + Args.push_back(Entry); + std::pair<SDOperand, SDOperand> CallResult = + LowerCallTo(Chain, (const Type *) Type::Int32Ty, false, false, + CallingConv::C, false, + DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG); + return CallResult.first; +} + +// Lower ISD::GlobalTLSAddress using the "initial exec" or +// "local exec" model. +SDOperand +ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, + SelectionDAG &DAG) { + GlobalValue *GV = GA->getGlobal(); + SDOperand Offset; + SDOperand Chain = DAG.getEntryNode(); + MVT::ValueType PtrVT = getPointerTy(); + // Get the Thread Pointer + SDOperand ThreadPointer = DAG.getNode(ARMISD::THREAD_POINTER, PtrVT); + + if (GV->isDeclaration()){ + // initial exec model + unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; + ARMConstantPoolValue *CPV = + new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue, + PCAdj, "gottpoff", true); + Offset = DAG.getTargetConstantPool(CPV, PtrVT, 2); + Offset = DAG.getNode(ARMISD::Wrapper, MVT::i32, Offset); + Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0); + Chain = Offset.getValue(1); + + SDOperand PICLabel = DAG.getConstant(ARMPCLabelIndex++, MVT::i32); + Offset = DAG.getNode(ARMISD::PIC_ADD, PtrVT, Offset, PICLabel); + + Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0); + } else { + // local exec model + ARMConstantPoolValue *CPV = + new ARMConstantPoolValue(GV, ARMCP::CPValue, "tpoff"); + Offset = DAG.getTargetConstantPool(CPV, PtrVT, 2); + Offset = DAG.getNode(ARMISD::Wrapper, MVT::i32, Offset); + Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0); + } + + // 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 +ARMTargetLowering::LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG) { + // TODO: implement the "local dynamic" model + assert(Subtarget->isTargetELF() && + "TLS not implemented for non-ELF targets"); + GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(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); + else + return LowerToTLSExecModels(GA, DAG); +} + SDOperand ARMTargetLowering::LowerGlobalAddressELF(SDOperand Op, SelectionDAG &DAG) { MVT::ValueType PtrVT = getPointerTy(); @@ -1249,6 +1337,7 @@ SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) { case ISD::GlobalAddress: return Subtarget->isTargetDarwin() ? LowerGlobalAddressDarwin(Op, DAG) : LowerGlobalAddressELF(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::CALL: return LowerCALL(Op, DAG); case ISD::RET: return LowerRET(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, Subtarget); diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 5b182f9b5b..8e9ef88989 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -63,7 +63,9 @@ namespace llvm { RRX, // V = RRX X, Flag -> srl X, 1 + shift in carry flag. FMRRD, // double to two gprs. - FMDRR // Two gprs to double. + FMDRR, // Two gprs to double. + + THREAD_POINTER }; } @@ -125,6 +127,11 @@ namespace llvm { SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG); SDOperand LowerGlobalAddressDarwin(SDOperand Op, SelectionDAG &DAG); SDOperand LowerGlobalAddressELF(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG); + SDOperand LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG); + SDOperand LowerToTLSExecModels(GlobalAddressSDNode *GA, + SelectionDAG &DAG); SDOperand LowerGLOBAL_OFFSET_TABLE(SDOperand Op, SelectionDAG &DAG); SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG); SDOperand LowerBR_JT(SDOperand Op, SelectionDAG &DAG); diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 43cbed2440..22665e71e9 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -39,6 +39,8 @@ def SDT_ARMCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, SDTCisPtrTy<1>, SDTCisVT<2, i32>]>; +def SDT_ARMThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; + // Node definitions. def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>; def ARMWrapperJT : SDNode<"ARMISD::WrapperJT", SDTIntBinOp>; @@ -79,6 +81,8 @@ def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>; def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>; def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInFlag ]>; +def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>; + //===----------------------------------------------------------------------===// // ARM Instruction Predicate Definitions. // @@ -1068,6 +1072,17 @@ def LEApcrelJT : AI1<(ops GPR:$dst, i32imm:$label, i32imm:$id), !strconcat("${:private}PCRELL${:uid}:\n\t", "add $dst, pc, #PCRELV${:uid}")), []>; +//===----------------------------------------------------------------------===// +// TLS Instructions +// + +// __aeabi_read_tp preserves the registers r1-r3. +let isCall = 1, + Defs = [R0, R12, LR] in { + def TPsoft : AI<(ops), + "bl __aeabi_read_tp", + [(set R0, ARMthread_pointer)]>; +} //===----------------------------------------------------------------------===// // Non-Instruction Patterns diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index 48196369ad..fa66ddc717 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -524,6 +524,18 @@ def tLEApcrelJT : TIx2<(ops GPR:$dst, i32imm:$label, i32imm:$id), []>; //===----------------------------------------------------------------------===// +// TLS Instructions +// + +// __aeabi_read_tp preserves the registers r1-r3. +let isCall = 1, + Defs = [R0, LR] in { + def tTPsoft : TIx2<(ops), + "bl __aeabi_read_tp", + [(set R0, ARMthread_pointer)]>; +} + +//===----------------------------------------------------------------------===// // Non-Instruction Patterns // diff --git a/lib/Target/ARM/ARMTargetAsmInfo.cpp b/lib/Target/ARM/ARMTargetAsmInfo.cpp index 4524041fa4..196348b9e9 100644 --- a/lib/Target/ARM/ARMTargetAsmInfo.cpp +++ b/lib/Target/ARM/ARMTargetAsmInfo.cpp @@ -70,6 +70,8 @@ ARMTargetAsmInfo::ARMTargetAsmInfo(const ARMTargetMachine &TM) { StaticCtorsSection = "\t.section .ctors,\"aw\",%progbits"; StaticDtorsSection = "\t.section .dtors,\"aw\",%progbits"; } + TLSDataSection = "\t.section .tdata,\"awT\",%progbits"; + TLSBSSSection = "\t.section .tbss,\"awT\",%nobits"; } ZeroDirective = "\t.space\t"; |