From d1b526fb95c867ea816180194cbf4348f64d9c7e Mon Sep 17 00:00:00 2001 From: wanglei Date: Tue, 11 Oct 2022 17:43:59 +0800 Subject: [PATCH] [LoongArch] Add codegen support of GlobalTLSAddress lowering There are static and dynamic TLS address lowering in DAG stage according to different TLS models. TLS address will be lowered to pseudo instruction and then expanded by the `LoongArch Pre-RA pseudo instruction expansion` pass. Differential Revision: https://reviews.llvm.org/D134713 --- .../LoongArch/LoongArchExpandPseudoInsts.cpp | 85 +++++++++++ .../lib/Target/LoongArch/LoongArchISelLowering.cpp | 83 +++++++++++ llvm/lib/Target/LoongArch/LoongArchISelLowering.h | 5 + llvm/lib/Target/LoongArch/LoongArchInstrInfo.td | 12 ++ llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp | 18 +++ .../LoongArch/MCTargetDesc/LoongArchBaseInfo.h | 6 + llvm/test/CodeGen/LoongArch/tls-models.ll | 166 +++++++++++++++++++++ 7 files changed, 375 insertions(+) create mode 100644 llvm/test/CodeGen/LoongArch/tls-models.ll diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp index 08b3a0f..1961444 100644 --- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp @@ -62,6 +62,18 @@ private: bool expandLoadAddressGot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddressTLSLE(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddressTLSIE(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddressTLSLD(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); + bool expandLoadAddressTLSGD(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI); }; char LoongArchPreRAExpandPseudo::ID = 0; @@ -96,6 +108,14 @@ bool LoongArchPreRAExpandPseudo::expandMI( return expandLoadAddressPcrel(MBB, MBBI, NextMBBI); case LoongArch::PseudoLA_GOT: return expandLoadAddressGot(MBB, MBBI, NextMBBI); + case LoongArch::PseudoLA_TLS_LE: + return expandLoadAddressTLSLE(MBB, MBBI, NextMBBI); + case LoongArch::PseudoLA_TLS_IE: + return expandLoadAddressTLSIE(MBB, MBBI, NextMBBI); + case LoongArch::PseudoLA_TLS_LD: + return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI); + case LoongArch::PseudoLA_TLS_GD: + return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI); } return false; } @@ -154,6 +174,71 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressGot( SecondOpcode, LoongArchII::MO_GOT_PC_LO); } +bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLE( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + // Code Sequence: + // lu12i.w $rd, %le_hi20(sym) + // ori $rd, $rd, %le_lo12(sym) + MachineFunction *MF = MBB.getParent(); + MachineInstr &MI = *MBBI; + DebugLoc DL = MI.getDebugLoc(); + + Register DestReg = MI.getOperand(0).getReg(); + Register ScratchReg = + MF->getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass); + MachineOperand &Symbol = MI.getOperand(1); + + BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W), ScratchReg) + .addDisp(Symbol, 0, LoongArchII::MO_LE_HI); + + BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ORI), DestReg) + .addReg(ScratchReg) + .addDisp(Symbol, 0, LoongArchII::MO_LE_LO); + + MI.eraseFromParent(); + return true; +} + +bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSIE( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + // Code Sequence: + // pcalau12i $rd, %ie_pc_hi20(sym) + // ld.w/d $rd, $rd, %ie_pc_lo12(sym) + MachineFunction *MF = MBB.getParent(); + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W; + return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_IE_PC_HI, + SecondOpcode, LoongArchII::MO_IE_PC_LO); +} + +bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSLD( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + // Code Sequence: + // pcalau12i $rd, %ld_pc_hi20(sym) + // addi.w/d $rd, $rd, %got_pc_lo12(sym) + MachineFunction *MF = MBB.getParent(); + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; + return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_LD_PC_HI, + SecondOpcode, LoongArchII::MO_GOT_PC_LO); +} + +bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + MachineBasicBlock::iterator &NextMBBI) { + // Code Sequence: + // pcalau12i $rd, %gd_pc_hi20(sym) + // addi.w/d $rd, $rd, %got_pc_lo12(sym) + MachineFunction *MF = MBB.getParent(); + const auto &STI = MF->getSubtarget(); + unsigned SecondOpcode = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; + return expandPcalau12iInstPair(MBB, MBBI, NextMBBI, LoongArchII::MO_GD_PC_HI, + SecondOpcode, LoongArchII::MO_GOT_PC_LO); +} + } // end namespace INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "LoongArch-prera-expand-pseudo", diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index 003a4ac..2b00bb4 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -62,6 +62,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, ISD::JumpTable}, GRLenVT, Custom); + setOperationAction(ISD::GlobalTLSAddress, GRLenVT, Custom); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); setOperationAction(ISD::EH_DWARF_CFA, MVT::i32, Custom); @@ -193,6 +195,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, return lowerEH_DWARF_CFA(Op, DAG); case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG); + case ISD::GlobalTLSAddress: + return lowerGlobalTLSAddress(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); case ISD::BlockAddress: @@ -353,6 +357,85 @@ SDValue LoongArchTargetLowering::lowerGlobalAddress(SDValue Op, return getAddr(N, DAG, N->getGlobal()->isDSOLocal()); } +SDValue LoongArchTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG, + unsigned Opc) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + MVT GRLenVT = Subtarget.getGRLenVT(); + + SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); + SDValue Offset = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); + + // Add the thread pointer. + return DAG.getNode(ISD::ADD, DL, Ty, Offset, + DAG.getRegister(LoongArch::R2, GRLenVT)); +} + +SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, + SelectionDAG &DAG, + unsigned Opc) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); + + // Use a PC-relative addressing mode to access the dynamic GOT address. + SDValue Addr = DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, 0); + SDValue Load = SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0); + + // Prepare argument list to generate call. + ArgListTy Args; + ArgListEntry Entry; + Entry.Node = Load; + Entry.Ty = CallTy; + Args.push_back(Entry); + + // Setup call to __tls_get_addr. + TargetLowering::CallLoweringInfo CLI(DAG); + CLI.setDebugLoc(DL) + .setChain(DAG.getEntryNode()) + .setLibCallee(CallingConv::C, CallTy, + DAG.getExternalSymbol("__tls_get_addr", Ty), + std::move(Args)); + + return LowerCallTo(CLI).first; +} + +SDValue +LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op, + SelectionDAG &DAG) const { + GlobalAddressSDNode *N = cast(Op); + assert(N->getOffset() == 0 && "unexpected offset in global node"); + + SDValue Addr; + TLSModel::Model Model = getTargetMachine().getTLSModel(N->getGlobal()); + + switch (Model) { + case TLSModel::GeneralDynamic: + // In this model, application code calls the dynamic linker function + // __tls_get_addr to locate TLS offsets into the dynamic thread vector at + // runtime. + Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_GD); + break; + case TLSModel::LocalDynamic: + // Same as GeneralDynamic, except for assembly modifiers and relocation + // records. + Addr = getDynamicTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LD); + break; + case TLSModel::InitialExec: + // This model uses the GOT to resolve TLS offsets. + Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_IE); + break; + case TLSModel::LocalExec: + // This model is used when static linking as the TLS offsets are resolved + // during program linking. + Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE); + break; + } + + return Addr; +} + SDValue LoongArchTargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { unsigned IntNo = Op.getConstantOperandVal(0); diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index 084b269..a0b9a8d 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -138,9 +138,14 @@ private: template SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const; + SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, + unsigned Opc) const; + SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, + unsigned Opc) const; SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 4a0f6ed..657c494 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -926,6 +926,18 @@ def PseudoLA_PCREL : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in def PseudoLA_GOT : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def PseudoLA_TLS_LE : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def PseudoLA_TLS_IE : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def PseudoLA_TLS_LD : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def PseudoLA_TLS_GD : Pseudo<(outs GPR:$dst), (ins grlenimm:$src), []>; + /// BSTRINS and BSTRPICK let Predicates = [IsLA32] in { diff --git a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp index af17ffc..40c9814 100644 --- a/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp @@ -53,6 +53,24 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, case LoongArchII::MO_GOT_PC_LO: Kind = LoongArchMCExpr::VK_LoongArch_GOT_LO12; break; + case LoongArchII::MO_LE_HI: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20; + break; + case LoongArchII::MO_LE_LO: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12; + break; + case LoongArchII::MO_IE_PC_HI: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20; + break; + case LoongArchII::MO_IE_PC_LO: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12; + break; + case LoongArchII::MO_LD_PC_HI: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20; + break; + case LoongArchII::MO_GD_PC_HI: + Kind = LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20; + break; // TODO: Handle more target-flags. } diff --git a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h index 77938b9..c5f0726 100644 --- a/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h +++ b/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h @@ -33,6 +33,12 @@ enum { MO_PCREL_LO, MO_GOT_PC_HI, MO_GOT_PC_LO, + MO_LE_HI, + MO_LE_LO, + MO_IE_PC_HI, + MO_IE_PC_LO, + MO_LD_PC_HI, + MO_GD_PC_HI, // TODO: Add more flags. }; } // end namespace LoongArchII diff --git a/llvm/test/CodeGen/LoongArch/tls-models.ll b/llvm/test/CodeGen/LoongArch/tls-models.ll new file mode 100644 index 0000000..1128532 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/tls-models.ll @@ -0,0 +1,166 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 --relocation-model=pic < %s | FileCheck %s --check-prefix=LA32PIC +; RUN: llc --mtriple=loongarch64 --relocation-model=pic < %s | FileCheck %s --check-prefix=LA64PIC +; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s --check-prefix=LA32NOPIC +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s --check-prefix=LA64NOPIC + +;; Check that TLS symbols are lowered correctly based on the specified +;; model. Make sure they're external to avoid them all being optimised to Local +;; Exec for the executable. + +@unspecified = external thread_local global i32 +@ld = external thread_local(localdynamic) global i32 +@ie = external thread_local(initialexec) global i32 +@le = external thread_local(localexec) global i32 + +;; No model specified (global dynamic) + +define ptr @f1() nounwind { +; LA32PIC-LABEL: f1: +; LA32PIC: # %bb.0: # %entry +; LA32PIC-NEXT: addi.w $sp, $sp, -16 +; LA32PIC-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill +; LA32PIC-NEXT: pcalau12i $a0, %gd_pc_hi20(unspecified) +; LA32PIC-NEXT: addi.w $a0, $a0, %got_lo12(unspecified) +; LA32PIC-NEXT: bl %plt(__tls_get_addr) +; LA32PIC-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload +; LA32PIC-NEXT: addi.w $sp, $sp, 16 +; LA32PIC-NEXT: ret +; +; LA64PIC-LABEL: f1: +; LA64PIC: # %bb.0: # %entry +; LA64PIC-NEXT: addi.d $sp, $sp, -16 +; LA64PIC-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill +; LA64PIC-NEXT: pcalau12i $a0, %gd_pc_hi20(unspecified) +; LA64PIC-NEXT: addi.d $a0, $a0, %got_lo12(unspecified) +; LA64PIC-NEXT: bl %plt(__tls_get_addr) +; LA64PIC-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload +; LA64PIC-NEXT: addi.d $sp, $sp, 16 +; LA64PIC-NEXT: ret +; +; LA32NOPIC-LABEL: f1: +; LA32NOPIC: # %bb.0: # %entry +; LA32NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(unspecified) +; LA32NOPIC-NEXT: ld.w $a0, $a0, %ie_pc_lo12(unspecified) +; LA32NOPIC-NEXT: add.w $a0, $a0, $tp +; LA32NOPIC-NEXT: ret +; +; LA64NOPIC-LABEL: f1: +; LA64NOPIC: # %bb.0: # %entry +; LA64NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(unspecified) +; LA64NOPIC-NEXT: ld.d $a0, $a0, %ie_pc_lo12(unspecified) +; LA64NOPIC-NEXT: add.d $a0, $a0, $tp +; LA64NOPIC-NEXT: ret +entry: + ret ptr @unspecified +} + +;; localdynamic specified + +define ptr @f2() nounwind { +; LA32PIC-LABEL: f2: +; LA32PIC: # %bb.0: # %entry +; LA32PIC-NEXT: addi.w $sp, $sp, -16 +; LA32PIC-NEXT: st.w $ra, $sp, 12 # 4-byte Folded Spill +; LA32PIC-NEXT: pcalau12i $a0, %ld_pc_hi20(ld) +; LA32PIC-NEXT: addi.w $a0, $a0, %got_lo12(ld) +; LA32PIC-NEXT: bl %plt(__tls_get_addr) +; LA32PIC-NEXT: ld.w $ra, $sp, 12 # 4-byte Folded Reload +; LA32PIC-NEXT: addi.w $sp, $sp, 16 +; LA32PIC-NEXT: ret +; +; LA64PIC-LABEL: f2: +; LA64PIC: # %bb.0: # %entry +; LA64PIC-NEXT: addi.d $sp, $sp, -16 +; LA64PIC-NEXT: st.d $ra, $sp, 8 # 8-byte Folded Spill +; LA64PIC-NEXT: pcalau12i $a0, %ld_pc_hi20(ld) +; LA64PIC-NEXT: addi.d $a0, $a0, %got_lo12(ld) +; LA64PIC-NEXT: bl %plt(__tls_get_addr) +; LA64PIC-NEXT: ld.d $ra, $sp, 8 # 8-byte Folded Reload +; LA64PIC-NEXT: addi.d $sp, $sp, 16 +; LA64PIC-NEXT: ret +; +; LA32NOPIC-LABEL: f2: +; LA32NOPIC: # %bb.0: # %entry +; LA32NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ld) +; LA32NOPIC-NEXT: ld.w $a0, $a0, %ie_pc_lo12(ld) +; LA32NOPIC-NEXT: add.w $a0, $a0, $tp +; LA32NOPIC-NEXT: ret +; +; LA64NOPIC-LABEL: f2: +; LA64NOPIC: # %bb.0: # %entry +; LA64NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ld) +; LA64NOPIC-NEXT: ld.d $a0, $a0, %ie_pc_lo12(ld) +; LA64NOPIC-NEXT: add.d $a0, $a0, $tp +; LA64NOPIC-NEXT: ret +entry: + ret ptr @ld +} + +;; initialexec specified + +define ptr @f3() nounwind { +; LA32PIC-LABEL: f3: +; LA32PIC: # %bb.0: # %entry +; LA32PIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ie) +; LA32PIC-NEXT: ld.w $a0, $a0, %ie_pc_lo12(ie) +; LA32PIC-NEXT: add.w $a0, $a0, $tp +; LA32PIC-NEXT: ret +; +; LA64PIC-LABEL: f3: +; LA64PIC: # %bb.0: # %entry +; LA64PIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ie) +; LA64PIC-NEXT: ld.d $a0, $a0, %ie_pc_lo12(ie) +; LA64PIC-NEXT: add.d $a0, $a0, $tp +; LA64PIC-NEXT: ret +; +; LA32NOPIC-LABEL: f3: +; LA32NOPIC: # %bb.0: # %entry +; LA32NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ie) +; LA32NOPIC-NEXT: ld.w $a0, $a0, %ie_pc_lo12(ie) +; LA32NOPIC-NEXT: add.w $a0, $a0, $tp +; LA32NOPIC-NEXT: ret +; +; LA64NOPIC-LABEL: f3: +; LA64NOPIC: # %bb.0: # %entry +; LA64NOPIC-NEXT: pcalau12i $a0, %ie_pc_hi20(ie) +; LA64NOPIC-NEXT: ld.d $a0, $a0, %ie_pc_lo12(ie) +; LA64NOPIC-NEXT: add.d $a0, $a0, $tp +; LA64NOPIC-NEXT: ret +entry: + ret ptr @ie +} + +;; localexec specified + +define ptr @f4() nounwind { +; LA32PIC-LABEL: f4: +; LA32PIC: # %bb.0: # %entry +; LA32PIC-NEXT: lu12i.w $a0, %le_hi20(le) +; LA32PIC-NEXT: ori $a0, $a0, %le_lo12(le) +; LA32PIC-NEXT: add.w $a0, $a0, $tp +; LA32PIC-NEXT: ret +; +; LA64PIC-LABEL: f4: +; LA64PIC: # %bb.0: # %entry +; LA64PIC-NEXT: lu12i.w $a0, %le_hi20(le) +; LA64PIC-NEXT: ori $a0, $a0, %le_lo12(le) +; LA64PIC-NEXT: add.d $a0, $a0, $tp +; LA64PIC-NEXT: ret +; +; LA32NOPIC-LABEL: f4: +; LA32NOPIC: # %bb.0: # %entry +; LA32NOPIC-NEXT: lu12i.w $a0, %le_hi20(le) +; LA32NOPIC-NEXT: ori $a0, $a0, %le_lo12(le) +; LA32NOPIC-NEXT: add.w $a0, $a0, $tp +; LA32NOPIC-NEXT: ret +; +; LA64NOPIC-LABEL: f4: +; LA64NOPIC: # %bb.0: # %entry +; LA64NOPIC-NEXT: lu12i.w $a0, %le_hi20(le) +; LA64NOPIC-NEXT: ori $a0, $a0, %le_lo12(le) +; LA64NOPIC-NEXT: add.d $a0, $a0, $tp +; LA64NOPIC-NEXT: ret +entry: + ret ptr @le +} -- 2.7.4