diff options
| author | Krzysztof Parzyszek <kparzysz@codeaurora.org> | 2016-02-18 15:42:57 +0000 |
|---|---|---|
| committer | Krzysztof Parzyszek <kparzysz@codeaurora.org> | 2016-02-18 15:42:57 +0000 |
| commit | 7a737d1abb55e3f8962ebdc71f2d2a125f2d2872 (patch) | |
| tree | 6169a7409d5920c2d5e67702a3800eb6e51296a5 /llvm | |
| parent | 72dae62b8ad99c2cde043f0a220c37d104c82950 (diff) | |
| download | bcm5719-llvm-7a737d1abb55e3f8962ebdc71f2d2a125f2d2872.tar.gz bcm5719-llvm-7a737d1abb55e3f8962ebdc71f2d2a125f2d2872.zip | |
[Hexagon] Implement TLS support
Patch by Anand Kodnani.
llvm-svn: 261218
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLowering.cpp | 156 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonISelLowering.h | 10 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp | 15 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h | 22 | ||||
| -rw-r--r-- | llvm/test/CodeGen/Hexagon/tls_pic.ll | 37 | ||||
| -rw-r--r-- | llvm/test/CodeGen/Hexagon/tls_static.ll | 28 |
7 files changed, 267 insertions, 2 deletions
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp index 2a113118cf6..4c454f42710 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -1518,7 +1518,7 @@ HexagonTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { Reloc::Model RM = HTM.getRelocationModel(); if (RM == Reloc::Static) { - SDValue A = DAG.getTargetBlockAddress(BA, PtrVT); + SDValue A = DAG.getTargetBlockAddress(BA, PtrVT); return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, A); } @@ -1535,6 +1535,158 @@ HexagonTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), PtrVT, GOTSym); } +SDValue +HexagonTargetLowering::GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain, + GlobalAddressSDNode *GA, SDValue *InFlag, EVT PtrVT, unsigned ReturnReg, + unsigned char OperandFlags) const { + 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); + // Create Operands for the call.The Operands should have the following: + // 1. Chain SDValue + // 2. Callee which in this case is the Global address value. + // 3. Registers live into the call.In this case its R0, as we + // have just one argument to be passed. + // 4. InFlag if there is any. + // Note: The order is important. + + if (InFlag) { + SDValue Ops[] = { Chain, TGA, + DAG.getRegister(Hexagon::R0, PtrVT), *InFlag }; + Chain = DAG.getNode(HexagonISD::CALLv3, dl, NodeTys, Ops); + } else { + SDValue Ops[] = { Chain, TGA, DAG.getRegister(Hexagon::R0, PtrVT)}; + Chain = DAG.getNode(HexagonISD::CALLv3, dl, NodeTys, Ops); + } + + // Inform MFI that function has calls. + MFI->setAdjustsStack(true); + + SDValue Flag = Chain.getValue(1); + return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Flag); +} + +// +// Lower using the intial executable model for TLS addresses +// +SDValue +HexagonTargetLowering::LowerToTLSInitialExecModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDLoc dl(GA); + int64_t Offset = GA->getOffset(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + + // Get the thread pointer. + SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT); + + Reloc::Model RM = HTM.getRelocationModel(); + unsigned char TF = (RM == Reloc::PIC_) ? HexagonII::MO_IEGOT + : HexagonII::MO_IE; + + // First generate the TLS symbol address + SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, + Offset, TF); + + SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA); + + if (RM == Reloc::PIC_) { + // Generate the GOT pointer in case of position independent code + SDValue GOT = LowerGLOBAL_OFFSET_TABLE(Sym, DAG); + + // Add the TLS Symbol address to GOT pointer.This gives + // GOT relative relocation for the symbol. + Sym = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym); + } + + // Load the offset value for TLS symbol.This offset is relative to + // thread pointer. + SDValue LoadOffset = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Sym, + MachinePointerInfo(), + false, false, false, 0); + + // Address of the thread local variable is the add of thread + // pointer and the offset of the variable. + return DAG.getNode(ISD::ADD, dl, PtrVT, TP, LoadOffset); +} + +// +// Lower using the local executable model for TLS addresses +// +SDValue +HexagonTargetLowering::LowerToTLSLocalExecModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDLoc dl(GA); + int64_t Offset = GA->getOffset(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + + // Get the thread pointer. + SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT); + // Generate the TLS symbol address + SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset, + HexagonII::MO_TPREL); + SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA); + + // Address of the thread local variable is the add of thread + // pointer and the offset of the variable. + return DAG.getNode(ISD::ADD, dl, PtrVT, TP, Sym); +} + +// +// Lower using the general dynamic model for TLS addresses +// +SDValue +HexagonTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const { + SDLoc dl(GA); + int64_t Offset = GA->getOffset(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + + // First generate the TLS symbol address + SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset, + HexagonII::MO_GDGOT); + + // Then, generate the GOT pointer + SDValue GOT = LowerGLOBAL_OFFSET_TABLE(TGA, DAG); + + // Add the TLS symbol and the GOT pointer + SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA); + SDValue Chain = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym); + + // Copy over the argument to R0 + SDValue InFlag; + Chain = DAG.getCopyToReg(DAG.getEntryNode(), dl, Hexagon::R0, Chain, InFlag); + InFlag = Chain.getValue(1); + + return GetDynamicTLSAddr(DAG, Chain, GA, &InFlag, PtrVT, + Hexagon::R0, HexagonII::MO_GDPLT); +} + +// +// Lower TLS addresses. +// +// For now for dynamic models, we only support the general dynamic model. +// +SDValue +HexagonTargetLowering::LowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); + + switch (HTM.getTLSModel(GA->getGlobal())) { + case TLSModel::GeneralDynamic: + case TLSModel::LocalDynamic: + return LowerToTLSGeneralDynamicModel(GA, DAG); + case TLSModel::InitialExec: + return LowerToTLSInitialExecModel(GA, DAG); + case TLSModel::LocalExec: + return LowerToTLSLocalExecModel(GA, DAG); + } + llvm_unreachable("Bogus TLS model"); +} + //===----------------------------------------------------------------------===// // TargetLowering Implementation //===----------------------------------------------------------------------===// @@ -1638,6 +1790,7 @@ HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM, setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom); + setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); // Custom legalize GlobalAddress nodes into CONST32. @@ -2626,6 +2779,7 @@ HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { // Frame & Return address. Currently unimplemented. case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG); case ISD::GlobalAddress: return LowerGLOBALADDRESS(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.h b/llvm/lib/Target/Hexagon/HexagonISelLowering.h index 1a682fcb9f3..e6024b8cfad 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelLowering.h +++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.h @@ -136,6 +136,16 @@ bool isPositiveHalfWord(SDNode *N); SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const override; SDValue LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const; + SDValue LowerToTLSInitialExecModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const; + SDValue LowerToTLSLocalExecModel(GlobalAddressSDNode *GA, + SelectionDAG &DAG) const; + SDValue GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain, + GlobalAddressSDNode *GA, SDValue *InFlag, EVT PtrVT, + unsigned ReturnReg, unsigned char OperandFlags) const; SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, diff --git a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp index 2b77294d4ec..401a8b75bce 100644 --- a/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp +++ b/llvm/lib/Target/Hexagon/HexagonMCInstLower.cpp @@ -58,6 +58,21 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol, case HexagonII::MO_GPREL: RelocationType = MCSymbolRefExpr::VK_Hexagon_GPREL; break; + case HexagonII::MO_GDGOT: + RelocationType = MCSymbolRefExpr::VK_Hexagon_GD_GOT; + break; + case HexagonII::MO_GDPLT: + RelocationType = MCSymbolRefExpr::VK_Hexagon_GD_PLT; + break; + case HexagonII::MO_IE: + RelocationType = MCSymbolRefExpr::VK_Hexagon_IE; + break; + case HexagonII::MO_IEGOT: + RelocationType = MCSymbolRefExpr::VK_Hexagon_IE_GOT; + break; + case HexagonII::MO_TPREL: + RelocationType = MCSymbolRefExpr::VK_TPREL; + break; } ME = MCSymbolRefExpr::create(Symbol, RelocationType, MC); diff --git a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp index fbec687372d..ccd02249afc 100644 --- a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp @@ -121,6 +121,7 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF) Reserved.set(Hexagon::LC1); Reserved.set(Hexagon::SA0); Reserved.set(Hexagon::SA1); + Reserved.set(Hexagon::UGP); Reserved.set(Hexagon::GP); Reserved.set(Hexagon::CS0); Reserved.set(Hexagon::CS1); diff --git a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h index 47a6f863627..c63f044b712 100644 --- a/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h +++ b/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonBaseInfo.h @@ -227,7 +227,27 @@ namespace HexagonII { MO_LO16, MO_HI16, // Offset from the base of the SDA. - MO_GPREL + MO_GPREL, + + // MO_GDGOT - indicates GOT relative relocation for TLS + // GeneralDynamic method + MO_GDGOT, + + // MO_GDPLT - indicates PLT relative relocation for TLS + // GeneralDynamic method + MO_GDPLT, + + // MO_IE - indicates non PIC relocation for TLS + // Initial Executable method + MO_IE, + + // MO_IEGOT - indicates PIC relocation for TLS + // Initial Executable method + MO_IEGOT, + + // MO_TPREL - indicates relocation for TLS + // local Executable method + MO_TPREL }; // Hexagon Sub-instruction classes. diff --git a/llvm/test/CodeGen/Hexagon/tls_pic.ll b/llvm/test/CodeGen/Hexagon/tls_pic.ll new file mode 100644 index 00000000000..87f7813cf0b --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/tls_pic.ll @@ -0,0 +1,37 @@ +; RUN: llc -O2 -march=hexagon -relocation-model=pic < %s | FileCheck %s + +@dst_ie = thread_local(initialexec) global i32 0, align 4 +@src_ie = thread_local(initialexec) global i32 0, align 4 + +; CHECK-LABEL: test_initial_exec +; CHECK: = add(pc, ##_GLOBAL_OFFSET_TABLE_@PCREL) +; CHECK-DAG: = ##src_ie@IEGOT +; CHECK-DAG: = ##dst_ie@IEGOT +; CHECK-DAG-NOT: call +define i32 @test_initial_exec() nounwind { +entry: + %0 = load i32, i32* @src_ie, align 4 + store i32 %0, i32* @dst_ie, align 4 + ret i32 0 +} + +@dst_gd = external thread_local global i32 +@src_gd = external thread_local global i32 + +; At the moment, the local-dynamic model uses the same code as the +; general-dynamic model. + +; CHECK-LABEL: test_dynamic +; CHECK: = add(pc, ##_GLOBAL_OFFSET_TABLE_@PCREL) +; CHECK-DAG: = ##src_gd@GDGOT +; CHECK-DAG: = ##dst_gd@GDGOT +; CHECK-DAG: call src_gd@GDPLT +; CHECK-DAG: call dst_gd@GDPLT + +define i32 @test_dynamic() nounwind { +entry: + %0 = load i32, i32* @src_gd, align 4 + store i32 %0, i32* @dst_gd, align 4 + ret i32 0 +} + diff --git a/llvm/test/CodeGen/Hexagon/tls_static.ll b/llvm/test/CodeGen/Hexagon/tls_static.ll new file mode 100644 index 00000000000..de35373fbd9 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/tls_static.ll @@ -0,0 +1,28 @@ +; RUN: llc -O2 -march=hexagon -relocation-model=static < %s | FileCheck %s + +@dst_le = thread_local global i32 0, align 4 +@src_le = thread_local global i32 0, align 4 + +; CHECK-LABEL: test_local_exec +; CHECK-DAG: = ##src_le@TPREL +; CHECK-DAG: = ##dst_le@TPREL +define i32 @test_local_exec() nounwind { +entry: + %0 = load i32, i32* @src_le, align 4 + store i32 %0, i32* @dst_le, align 4 + ret i32 0 +} + +@dst_ie = external thread_local global i32 +@src_ie = external thread_local global i32 + +; CHECK-LABEL: test_initial_exec: +; CHECK-DAG: = memw(##src_ie@IE) +; CHECK-DAG: = memw(##dst_ie@IE) +define i32 @test_initial_exec() nounwind { +entry: + %0 = load i32, i32* @src_ie, align 4 + store i32 %0, i32* @dst_ie, align 4 + ret i32 0 +} + |

