From cb1dca602c436c80c6923e106c9a9d8fc2353e8c Mon Sep 17 00:00:00 2001 From: Venkatraman Govindaraju Date: Sun, 22 Sep 2013 06:48:52 +0000 Subject: [PATCH] [Sparc] Add support for TLS in sparc. llvm-svn: 191164 --- llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h | 22 ++++- llvm/lib/Target/Sparc/SparcAsmPrinter.cpp | 50 +++++++++- llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp | 6 +- llvm/lib/Target/Sparc/SparcISelLowering.cpp | 103 ++++++++++++++++++++- llvm/lib/Target/Sparc/SparcISelLowering.h | 9 +- llvm/lib/Target/Sparc/SparcInstr64Bit.td | 9 ++ llvm/lib/Target/Sparc/SparcInstrInfo.td | 49 ++++++++++ llvm/test/CodeGen/SPARC/tls.ll | 73 +++++++++++++++ 8 files changed, 311 insertions(+), 10 deletions(-) create mode 100644 llvm/test/CodeGen/SPARC/tls.ll diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h index aac0e8d..f3caeaa 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h @@ -53,7 +53,27 @@ enum TOF { // Extract bits 41-32 of an address. // Assembler: %hm(addr) - MO_HM + MO_HM, + + // TargetFlags for Thread Local Storage. + MO_TLS_GD_HI22, + MO_TLS_GD_LO10, + MO_TLS_GD_ADD, + MO_TLS_GD_CALL, + MO_TLS_LDM_HI22, + MO_TLS_LDM_LO10, + MO_TLS_LDM_ADD, + MO_TLS_LDM_CALL, + MO_TLS_LDO_HIX22, + MO_TLS_LDO_LOX10, + MO_TLS_LDO_ADD, + MO_TLS_IE_HI22, + MO_TLS_IE_LO10, + MO_TLS_IE_LD, + MO_TLS_IE_LDX, + MO_TLS_IE_ADD, + MO_TLS_LE_HIX22, + MO_TLS_LE_LOX10 }; } // end namespace SPII diff --git a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp index b695dd8..d561093 100644 --- a/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -105,11 +105,37 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, assert(TF == SPII::MO_NO_FLAG && "Cannot handle target flags on call address"); else if (MI->getOpcode() == SP::SETHIi) - assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH) && + assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH + || TF == SPII::MO_TLS_GD_HI22 + || TF == SPII::MO_TLS_LDM_HI22 + || TF == SPII::MO_TLS_LDO_HIX22 + || TF == SPII::MO_TLS_IE_HI22 + || TF == SPII::MO_TLS_LE_HIX22) && "Invalid target flags for address operand on sethi"); + else if (MI->getOpcode() == SP::TLS_CALL) + assert((TF == SPII::MO_NO_FLAG + || TF == SPII::MO_TLS_GD_CALL + || TF == SPII::MO_TLS_LDM_CALL) && + "Cannot handle target flags on tls call address"); + else if (MI->getOpcode() == SP::TLS_ADDrr) + assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD + || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) && + "Cannot handle target flags on add for TLS"); + else if (MI->getOpcode() == SP::TLS_LDrr) + assert(TF == SPII::MO_TLS_IE_LD && + "Cannot handle target flags on ld for TLS"); + else if (MI->getOpcode() == SP::TLS_LDXrr) + assert(TF == SPII::MO_TLS_IE_LDX && + "Cannot handle target flags on ldx for TLS"); + else if (MI->getOpcode() == SP::XORri) + assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && + "Cannot handle target flags on xor for TLS"); else - assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 || - TF == SPII::MO_HM) && + assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 + || TF == SPII::MO_HM + || TF == SPII::MO_TLS_GD_LO10 + || TF == SPII::MO_TLS_LDM_LO10 + || TF == SPII::MO_TLS_IE_LO10 ) && "Invalid target flags for small address operand"); } #endif @@ -128,6 +154,24 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, case SPII::MO_L44: O << "%l44("; break; case SPII::MO_HH: O << "%hh("; break; case SPII::MO_HM: O << "%hm("; break; + case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break; + case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break; + case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break; + case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break; + case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break; + case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break; + case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break; + case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break; + case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break; + case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break; + case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break; + case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break; + case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break; + case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break; + case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break; + case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break; + case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break; + case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break; } switch (MO.getType()) { diff --git a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp index db62151..e17a187 100644 --- a/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -80,7 +80,8 @@ bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, return true; } if (Addr.getOpcode() == ISD::TargetExternalSymbol || - Addr.getOpcode() == ISD::TargetGlobalAddress) + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) return false; // direct calls. if (Addr.getOpcode() == ISD::ADD) { @@ -117,7 +118,8 @@ bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr, bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { if (Addr.getOpcode() == ISD::FrameIndex) return false; if (Addr.getOpcode() == ISD::TargetExternalSymbol || - Addr.getOpcode() == ISD::TargetGlobalAddress) + Addr.getOpcode() == ISD::TargetGlobalAddress || + Addr.getOpcode() == ISD::TargetGlobalTLSAddress) return false; // direct calls. if (Addr.getOpcode() == ISD::ADD) { diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index eb9896c..86bac7e 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1544,6 +1544,9 @@ const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const { case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG"; case SPISD::FLUSHW: return "SPISD::FLUSHW"; + case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; + case SPISD::TLS_LD: return "SPISD::TLS_LD"; + case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; } } @@ -1699,6 +1702,103 @@ SDValue SparcTargetLowering::LowerBlockAddress(SDValue Op, return makeAddress(Op, DAG); } +SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + + GlobalAddressSDNode *GA = cast(Op); + SDLoc DL(GA); + const GlobalValue *GV = GA->getGlobal(); + EVT PtrVT = getPointerTy(); + + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { + unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22 + : SPII::MO_TLS_LDM_HI22); + unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10 + : SPII::MO_TLS_LDM_LO10); + unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD + : SPII::MO_TLS_LDM_ADD); + unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL + : SPII::MO_TLS_LDM_CALL); + + SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG); + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + SDValue Argument = DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Base, HiLo, + withTargetFlags(Op, addTF, DAG)); + + SDValue Chain = DAG.getEntryNode(); + SDValue InFlag; + + Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(1, true), DL); + Chain = DAG.getCopyToReg(Chain, DL, SP::O0, Argument, InFlag); + InFlag = Chain.getValue(1); + SDValue Callee = DAG.getTargetExternalSymbol("__tls_get_addr", PtrVT); + SDValue Symbol = withTargetFlags(Op, callTF, DAG); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + Ops.push_back(Symbol); + Ops.push_back(DAG.getRegister(SP::O0, PtrVT)); + const uint32_t *Mask = getTargetMachine() + .getRegisterInfo()->getCallPreservedMask(CallingConv::C); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + Ops.push_back(InFlag); + Chain = DAG.getNode(SPISD::TLS_CALL, DL, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(1, true), + DAG.getIntPtrConstant(0, true), InFlag, DL); + InFlag = Chain.getValue(1); + SDValue Ret = DAG.getCopyFromReg(Chain, DL, SP::O0, PtrVT, InFlag); + + if (model != TLSModel::LocalDynamic) + return Ret; + + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG)); + HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo, + withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG)); + } + + if (model == TLSModel::InitialExec) { + unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX + : SPII::MO_TLS_IE_LD); + + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this + // function has calls. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setHasCalls(true); + + SDValue TGA = makeHiLoPair(Op, + SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA); + SDValue Offset = DAG.getNode(SPISD::TLS_LD, + DL, PtrVT, Ptr, + withTargetFlags(Op, ldTF, DAG)); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset, + withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG)); + } + + assert(model == TLSModel::LocalExec); + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, + withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG)); + SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + + return DAG.getNode(ISD::ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset); +} + SDValue SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, SDValue Arg, SDLoc DL, @@ -2333,8 +2433,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); - case ISD::GlobalTLSAddress: - llvm_unreachable("TLS not implemented for Sparc."); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h index 64c688d..57ef099 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -40,8 +40,12 @@ namespace llvm { CALL, // A call instruction. RET_FLAG, // Return with a flag operand. - GLOBAL_BASE_REG, // Global base reg for PIC - FLUSHW // FLUSH register windows to stack + GLOBAL_BASE_REG, // Global base reg for PIC. + FLUSHW, // FLUSH register windows to stack. + + TLS_ADD, // For Thread Local Storage (TLS). + TLS_LD, + TLS_CALL }; } @@ -119,6 +123,7 @@ namespace llvm { SDLoc DL, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td index 47658ee..212bd1c 100644 --- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -162,6 +162,9 @@ def : Pat<(subc i64:$a, i64:$b), (SUBCCrr $a, $b)>; def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; +def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym), + (TLS_ADDrr $a, $b, $sym)>; + // Register-immediate instructions. def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>; @@ -237,6 +240,12 @@ def LDXri : F3_2<3, 0b001011, (outs I64Regs:$dst), (ins MEMri:$addr), "ldx [$addr], $dst", [(set i64:$dst, (load ADDRri:$addr))]>; +let mayLoad = 1 in + def TLS_LDXrr : F3_1<3, 0b001011, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + "ldx [$addr], $dst, $sym", + [(set i64:$dst, + (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; // Extending loads to i64. def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>; diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td index 695be33..7dc17cc 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -85,6 +85,8 @@ def MEMri : Operand { let MIOperandInfo = (ops ptr_rc, i32imm); } +def TLSSym : Operand; + // Branch targets have OtherVT type. def brtarget : Operand; def calltarget : Operand; @@ -106,6 +108,11 @@ SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisFP<1>]>; def SDTSPITOF : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f32>]>; +def SDTSPtlsadd : +SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; +def SDTSPtlsld : +SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; + def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; @@ -144,6 +151,12 @@ def retflag : SDNode<"SPISD::RET_FLAG", SDT_SPRet, def flushw : SDNode<"SPISD::FLUSHW", SDTNone, [SDNPHasChain, SDNPSideEffect, SDNPMayStore]>; +def tlsadd : SDNode<"SPISD::TLS_ADD", SDTSPtlsadd>; +def tlsld : SDNode<"SPISD::TLS_LD", SDTSPtlsld>; +def tlscall : SDNode<"SPISD::TLS_CALL", SDT_SPCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; + def getPCX : Operand { let PrintMethod = "printGetPCX"; } @@ -807,6 +820,34 @@ let Defs = [FCC] in { } //===----------------------------------------------------------------------===// +// Instructions for Thread Local Storage(TLS). +//===----------------------------------------------------------------------===// + +def TLS_ADDrr : F3_1<2, 0b000000, + (outs IntRegs:$rd), + (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym), + "add $rs1, $rs2, $rd, $sym", + [(set i32:$rd, + (tlsadd i32:$rs1, i32:$rs2, tglobaltlsaddr:$sym))]>; + +let mayLoad = 1 in + def TLS_LDrr : F3_1<3, 0b000000, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + "ld [$addr], $dst, $sym", + [(set i32:$dst, + (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>; + +let Uses = [O6], isCall = 1 in + def TLS_CALL : InstSP<(outs), + (ins calltarget:$disp, TLSSym:$sym, variable_ops), + "call $disp, $sym\n\tnop", + [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)]> { + bits<30> disp; + let op = 1; + let Inst{29-0} = disp; +} + +//===----------------------------------------------------------------------===// // V9 Instructions //===----------------------------------------------------------------------===// @@ -915,6 +956,14 @@ def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>; def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; def : Pat<(SPlo tconstpool:$in), (ORri (i32 G0), tconstpool:$in)>; +// GlobalTLS addresses +def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>; +def : Pat<(SPlo tglobaltlsaddr:$in), (ORri (i32 G0), tglobaltlsaddr:$in)>; +def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (ADDri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; +def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (XORri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; + // Blockaddress def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>; def : Pat<(SPlo tblockaddress:$in), (ORri (i32 G0), tblockaddress:$in)>; diff --git a/llvm/test/CodeGen/SPARC/tls.ll b/llvm/test/CodeGen/SPARC/tls.ll new file mode 100644 index 0000000..660ddff --- /dev/null +++ b/llvm/test/CodeGen/SPARC/tls.ll @@ -0,0 +1,73 @@ +; RUN: llc <%s -march=sparc -relocation-model=static | FileCheck %s --check-prefix=v8abs +; RUN: llc <%s -march=sparcv9 -relocation-model=static | FileCheck %s --check-prefix=v9abs +; RUN: llc <%s -march=sparc -relocation-model=pic | FileCheck %s --check-prefix=pic +; RUN: llc <%s -march=sparcv9 -relocation-model=pic | FileCheck %s --check-prefix=pic + + +@local_symbol = internal thread_local global i32 0 +@extern_symbol = external thread_local global i32 + +; v8abs-LABEL: test_tls_local +; v8abs: sethi %tle_hix22(local_symbol), [[R0:%[goli][0-7]]] +; v8abs: xor [[R0]], %tle_lox10(local_symbol), [[R1:%[goli][0-7]]] +; v8abs: ld [%g7+[[R1]]] + +; v9abs-LABEL: test_tls_local +; v9abs: sethi %tle_hix22(local_symbol), [[R0:%[goli][0-7]]] +; v9abs: xor [[R0]], %tle_lox10(local_symbol), [[R1:%[goli][0-7]]] +; v9abs: ld [%g7+[[R1]]] + +; pic-LABEL: test_tls_local +; pic: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +; pic: add [[PC]], %o7, [[GOTBASE:%[goli][0-7]]] +; pic-DAG: sethi %tldm_hi22(local_symbol), [[R0:%[goli][0-7]]] +; pic-DAG: add [[R0]], %tldm_lo10(local_symbol), [[R1:%[goli][0-7]]] +; pic-DAG: add [[GOTBASE]], [[R1]], %o0, %tldm_add(local_symbol) +; pic-DAG: call __tls_get_addr, %tldm_call(local_symbol) +; pic-DAG: sethi %tldo_hix22(local_symbol), [[R2:%[goli][0-7]]] +; pic-DAG: xor [[R2]], %tldo_lox10(local_symbol), [[R3:%[goli][0-7]]] +; pic: add %o0, [[R3]], {{.+}}, %tldo_add(local_symbol) + +define i32 @test_tls_local() { +entry: + %0 = load i32* @local_symbol, align 4 + %1 = add i32 %0, 1 + store i32 %1, i32* @local_symbol, align 4 + ret i32 %1 +} + + +; v8abs-LABEL: test_tls_extern +; v8abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +; v8abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]] +; v8abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]] +; v8abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]] +; v8abs: ld [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ld(extern_symbol) +; v8abs: add %g7, [[R3]], %[[R4:[goli][0-7]]], %tie_add(extern_symbol) +; v8abs: ld [%[[R4]]] + +; v9abs-LABEL: test_tls_extern +; v9abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +; v9abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]] +; v9abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]] +; v9abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]] +; v9abs: ldx [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ldx(extern_symbol) +; v9abs: add %g7, [[R3]], %[[R4:[goli][0-7]]], %tie_add(extern_symbol) +; v9abs: ld [%[[R4]]] + +; pic-LABEL: test_tls_extern +; pic: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +; pic: add [[PC]], %o7, [[GOTBASE:%[goli][0-7]]] +; pic: sethi %tgd_hi22(extern_symbol), [[R0:%[goli][0-7]]] +; pic: add [[R0]], %tgd_lo10(extern_symbol), [[R1:%[goli][0-7]]] +; pic: add [[GOTBASE]], [[R1]], %o0, %tgd_add(extern_symbol) +; pic: call __tls_get_addr, %tgd_call(extern_symbol) +; pic-NEXT: nop + +define i32 @test_tls_extern() { +entry: + %0 = load i32* @extern_symbol, align 4 + %1 = add i32 %0, 1 + store i32 %1, i32* @extern_symbol, align 4 + ret i32 %1 +} -- 2.7.4