From d979686bb47f2dcdca60f0a088f59d1964346453 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Tue, 31 May 2011 02:53:58 +0000 Subject: [PATCH] This patch implements the thread local storage. Implemented are General Dynamic, Initial Exec and Local Exec TLS models. Patch by Sasa Stankovic git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132322 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsAsmPrinter.cpp | 4 ++ lib/Target/Mips/MipsISelDAGToDAG.cpp | 17 ++++++++ lib/Target/Mips/MipsISelLowering.cpp | 60 +++++++++++++++++++++++++++- lib/Target/Mips/MipsISelLowering.h | 10 +++++ lib/Target/Mips/MipsInstrInfo.h | 16 +++++++- lib/Target/Mips/MipsInstrInfo.td | 30 ++++++++++++++ lib/Target/Mips/MipsRegisterInfo.td | 10 +++++ test/CodeGen/Mips/tls.ll | 46 +++++++++++++++++++++ 8 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/Mips/tls.ll diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index 565e02ac74b..8caa7cd2f75 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -318,6 +318,10 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, case MipsII::MO_GOT: O << "%got("; break; case MipsII::MO_ABS_HI: O << "%hi("; break; case MipsII::MO_ABS_LO: O << "%lo("; break; + case MipsII::MO_TLSGD: O << "%tlsgd("; break; + case MipsII::MO_GOTTPREL: O << "%gottprel("; break; + case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; + case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; } switch (MO.getType()) { diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 1d97fbfbb3c..b2aba273054 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -128,6 +128,11 @@ SelectAddr(SDValue Addr, SDValue &Offset, SDValue &Base) { if ((Addr.getOpcode() == ISD::TargetExternalSymbol || Addr.getOpcode() == ISD::TargetGlobalAddress)) return false; + else if (Addr.getOpcode() == ISD::TargetGlobalTLSAddress) { + Base = CurDAG->getRegister(Mips::GP, MVT::i32); + Offset = Addr; + return true; + } } // Operand is a result from an ADD. @@ -441,6 +446,18 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) { return ResNode; // Other cases are autogenerated. break; + + case MipsISD::ThreadPointer: { + unsigned SrcReg = Mips::HWR29; + unsigned DestReg = Mips::V1; + SDNode *Rdhwr = CurDAG->getMachineNode(Mips::RDHWR, Node->getDebugLoc(), + Node->getValueType(0), CurDAG->getRegister(SrcReg, MVT::i32)); + SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, DestReg, + SDValue(Rdhwr, 0)); + SDValue ResNode = CurDAG->getCopyFromReg(Chain, dl, DestReg, MVT::i32); + ReplaceUses(SDValue(Node, 0), ResNode); + return ResNode.getNode(); + } } // Select the default instruction diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index e5dfb253f55..1ee51722da0 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -41,6 +41,10 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::Hi: return "MipsISD::Hi"; case MipsISD::Lo: return "MipsISD::Lo"; case MipsISD::GPRel: return "MipsISD::GPRel"; + case MipsISD::TlsGd: return "MipsISD::TlsGd"; + case MipsISD::TprelHi: return "MipsISD::TprelHi"; + case MipsISD::TprelLo: return "MipsISD::TprelLo"; + case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer"; case MipsISD::Ret: return "MipsISD::Ret"; case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; case MipsISD::FPCmp: return "MipsISD::FPCmp"; @@ -822,8 +826,60 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op, SDValue MipsTargetLowering:: LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { - llvm_unreachable("TLS not implemented for MIPS."); - return SDValue(); // Not reached + // If the relocation model is PIC, use the General Dynamic TLS Model, + // otherwise use the Initial Exec or Local Exec TLS Model. + // TODO: implement Local Dynamic TLS model + + GlobalAddressSDNode *GA = cast(Op); + DebugLoc dl = GA->getDebugLoc(); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(); + + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // General Dynamic TLS Model + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, + 0, MipsII::MO_TLSGD); + SDValue Tlsgd = DAG.getNode(MipsISD::TlsGd, dl, MVT::i32, TGA); + SDValue GP = DAG.getRegister(Mips::GP, MVT::i32); + SDValue Argument = DAG.getNode(ISD::ADD, dl, MVT::i32, GP, Tlsgd); + + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Argument; + Entry.Ty = (const Type *) Type::getInt32Ty(*DAG.getContext()); + Args.push_back(Entry); + std::pair CallResult = + LowerCallTo(DAG.getEntryNode(), + (const Type *) Type::getInt32Ty(*DAG.getContext()), + false, false, false, false, + 0, CallingConv::C, false, true, + DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG, dl); + + return CallResult.first; + } else { + SDValue Offset; + if (GV->isDeclaration()) { + // Initial Exec TLS Model + SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + MipsII::MO_GOTTPREL); + Offset = DAG.getLoad(MVT::i32, dl, + DAG.getEntryNode(), TGA, MachinePointerInfo(), + false, false, 0); + } else { + // Local Exec TLS Model + SDVTList VTs = DAG.getVTList(MVT::i32); + SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + MipsII::MO_TPREL_HI); + SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, + MipsII::MO_TPREL_LO); + SDValue Hi = DAG.getNode(MipsISD::TprelHi, dl, VTs, &TGAHi, 1); + SDValue Lo = DAG.getNode(MipsISD::TprelLo, dl, MVT::i32, TGALo); + Offset = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo); + } + + SDValue ThreadPointer = DAG.getNode(MipsISD::ThreadPointer, dl, PtrVT); + return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset); + } } SDValue MipsTargetLowering:: diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 805ac955072..24dc157832c 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -40,6 +40,16 @@ namespace llvm { // Handle gp_rel (small data/bss sections) relocation. GPRel, + // General Dynamic TLS + TlsGd, + + // Local Exec TLS + TprelHi, + TprelLo, + + // Thread Pointer + ThreadPointer, + // Floating Point Branch Conditional FPBrcond, diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h index 5fdbf1f230a..abf67733f08 100644 --- a/lib/Target/Mips/MipsInstrInfo.h +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -146,7 +146,21 @@ namespace MipsII { /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol /// address. MO_ABS_HI, - MO_ABS_LO + MO_ABS_LO, + + /// MO_TLSGD - Represents the offset into the global offset table at which + // the module ID and TSL block offset reside during execution (General + // Dynamic TLS). + MO_TLSGD, + + /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial + // Exec TLS). + MO_GOTTPREL, + + /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from + // the thread pointer (Local Exec TLS). + MO_TPREL_HI, + MO_TPREL_LO }; } diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index d3fb724e824..b9b81f7fc37 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -37,6 +37,8 @@ def SDT_MipsDivRem : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>]>; +def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; + // Call def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, @@ -49,6 +51,16 @@ def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>; def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>; def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>; +// TlsGd node is used to handle General Dynamic TLS +def MipsTlsGd : SDNode<"MipsISD::TlsGd", SDTIntUnaryOp>; + +// TprelHi and TprelLo nodes are used to handle Local Exec TLS +def MipsTprelHi : SDNode<"MipsISD::TprelHi", SDTIntUnaryOp>; +def MipsTprelLo : SDNode<"MipsISD::TprelLo", SDTIntUnaryOp>; + +// Thread pointer +def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>; + // Return def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain, SDNPOptInGlue]>; @@ -353,6 +365,13 @@ class CondMov func, string instr_asm, PatLeaf MovCode>: CPURegs:$cond), !strconcat(instr_asm, "\t$dst, $T, $cond"), [], NoItinerary>; +// Read Hardware +class ReadHardware: FR<0x1f, 0x3b, (outs CPURegs:$dst), (ins HWRegs:$src), + "rdhwr\t$dst, $src", [], IIAlu> { + let rs = 0; + let shamt = 0; +} + //===----------------------------------------------------------------------===// // Pseudo instructions //===----------------------------------------------------------------------===// @@ -540,6 +559,8 @@ def MSUBU : MArithR<5, "msubu", MipsMSubu>; // it is a real instruction. def MUL : ArithR<0x1c, 0x02, "mul", mul, IIImul, 1>, Requires<[IsMips32]>; +def RDHWR : ReadHardware; + //===----------------------------------------------------------------------===// // Arbitrary patterns that map to one or more instructions //===----------------------------------------------------------------------===// @@ -592,6 +613,15 @@ def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)), def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)), (ADDiu CPURegs:$gp, tconstpool:$in)>; +// tlsgd +def : Pat<(add CPURegs:$gp, (MipsTlsGd tglobaltlsaddr:$in)), + (ADDiu CPURegs:$gp, tglobaltlsaddr:$in)>; + +// tprel hi/lo +def : Pat<(MipsTprelHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>; +def : Pat<(add CPURegs:$hi, (MipsTprelLo tglobaltlsaddr:$lo)), + (ADDiu CPURegs:$hi, tglobaltlsaddr:$lo)>; + // wrapper_pic class WrapperPICPat: Pat<(MipsWrapperPIC node:$in), diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index db00b0dbe44..3134f9974f9 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -44,6 +44,11 @@ class AFPR num, string n, list subregs> let SubRegIndices = [sub_fpeven, sub_fpodd]; } +// Mips Hardware Registers +class HWR num, string n> : MipsReg { + let Num = num; +} + //===----------------------------------------------------------------------===// // Registers //===----------------------------------------------------------------------===// @@ -143,6 +148,9 @@ let Namespace = "Mips" in { // Status flags register def FCR31 : Register<"31">; + + // Hardware register $29 + def HWR29 : Register<"29">; } //===----------------------------------------------------------------------===// @@ -262,3 +270,5 @@ def CCR : RegisterClass<"Mips", [i32], 32, [FCR31]>; // Hi/Lo Registers def HILO : RegisterClass<"Mips", [i32], 32, [HI, LO]>; +// Hardware registers +def HWRegs : RegisterClass<"Mips", [i32], 32, [HWR29]>; diff --git a/test/CodeGen/Mips/tls.ll b/test/CodeGen/Mips/tls.ll new file mode 100644 index 00000000000..034738b6262 --- /dev/null +++ b/test/CodeGen/Mips/tls.ll @@ -0,0 +1,46 @@ +; RUN: llc -march=mipsel -mcpu=mips2 < %s | FileCheck %s -check-prefix=PIC +; RUN: llc -march=mipsel -mcpu=mips2 -relocation-model=static < %s \ +; RUN: | FileCheck %s -check-prefix=STATIC + + +@t1 = thread_local global i32 0, align 4 + +define i32 @f1() nounwind { +entry: + %tmp = load i32* @t1, align 4 + ret i32 %tmp + +; CHECK: f1: + +; PIC: lw $25, %call16(__tls_get_addr)($gp) +; PIC: addiu $4, $gp, %tlsgd(t1) +; PIC: jalr $25 +; PIC: lw $2, 0($2) + +; STATIC: rdhwr $3, $29 +; STATIC: lui $[[R0:[0-9]+]], %tprel_hi(t1) +; STATIC: addiu $[[R1:[0-9]+]], $[[R0]], %tprel_lo(t1) +; STATIC: addu $[[R2:[0-9]+]], $3, $[[R1]] +; STATIC: lw $2, 0($[[R2]]) +} + + +@t2 = external thread_local global i32 + +define i32 @f2() nounwind { +entry: + %tmp = load i32* @t2, align 4 + ret i32 %tmp + +; CHECK: f2: + +; PIC: lw $25, %call16(__tls_get_addr)($gp) +; PIC: addiu $4, $gp, %tlsgd(t2) +; PIC: jalr $25 +; PIC: lw $2, 0($2) + +; STATIC: rdhwr $3, $29 +; STATIC: lw $[[R0:[0-9]+]], %gottprel(t2)($gp) +; STATIC: addu $[[R1:[0-9]+]], $3, $[[R0]] +; STATIC: lw $2, 0($[[R1]]) +} -- 2.34.1