Skip to content

Commit

Permalink
[LoongArch][Codegen] Add support for TLSDESC
Browse files Browse the repository at this point in the history
The implementation only enables when the `-enable-tlsdesc` option is
passed and the TLS model is `dynamic`.

LoongArch's GCC has the same option(-mtls-dialet=) as RISC-V.

Reviewers: heiher, MaskRay, SixWeining

Reviewed By: SixWeining, MaskRay

Pull Request: #90159
  • Loading branch information
wangleiat committed Apr 30, 2024
1 parent ff6c0ca commit eb148ae
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 16 deletions.
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC,
StringRef V = A->getValue();
bool SupportedArgument = false, EnableTLSDESC = false;
bool Unsupported = !Triple.isOSBinFormatELF();
if (Triple.isRISCV()) {
if (Triple.isLoongArch() || Triple.isRISCV()) {
SupportedArgument = V == "desc" || V == "trad";
EnableTLSDESC = V == "desc";
} else if (Triple.isX86()) {
Expand Down
14 changes: 14 additions & 0 deletions clang/test/CodeGen/LoongArch/tls-dialect.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// REQUIRES: loongarch-registered-target
/// cc1 -enable-tlsdesc (due to -mtls-dialect=desc) enables TLSDESC.
// RUN: %clang_cc1 -triple loongarch64 -S -mrelocation-model pic -pic-level 1 -enable-tlsdesc %s -o - | FileCheck %s --check-prefix=DESC
// RUN: %clang_cc1 -triple loongarch64 -S -mrelocation-model pic -pic-level 1 %s -o - | FileCheck %s --check-prefix=NODESC

__thread int x;

// DESC: %desc_pc_hi20
// DESC-NOT: %gd_pc_hi20
// NODESC: %gd_pc_hi20
// NODESC-NOT: %desc_pc_hi20
int use() {
return x;
}
5 changes: 5 additions & 0 deletions clang/test/Driver/tls-dialect.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// RUN: %clang -### --target=loongarch64-linux -mtls-dialect=trad %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=loongarch64-linux %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=riscv64-freebsd -mtls-dialect=desc %s 2>&1 | FileCheck --check-prefix=DESC %s
// RUN: %clang -### --target=riscv64-linux -mtls-dialect=trad %s 2>&1 | FileCheck --check-prefix=NODESC %s
// RUN: %clang -### --target=riscv64-linux %s 2>&1 | FileCheck --check-prefix=NODESC %s
Expand All @@ -9,6 +11,8 @@
// RUN: %clang -### --target=riscv64-android %s 2>&1 | FileCheck --check-prefix=DESC %s

/// LTO
// RUN: %clang -### --target=loongarch64-linux -flto -mtls-dialect=desc %s 2>&1 | FileCheck --check-prefix=LTO-DESC %s
// RUN: %clang -### --target=loongarch64-linux -flto %s 2>&1 | FileCheck --check-prefix=LTO-NODESC %s
// RUN: %clang -### --target=riscv64-linux -flto -mtls-dialect=desc %s 2>&1 | FileCheck --check-prefix=LTO-DESC %s
// RUN: %clang -### --target=riscv64-linux -flto %s 2>&1 | FileCheck --check-prefix=LTO-NODESC %s

Expand All @@ -18,6 +22,7 @@
// RUN: not %clang --target=x86_64-apple-macos -mtls-dialect=desc -flto %s 2>&1 | FileCheck -check-prefix=UNSUPPORTED-TARGET %s

/// Unsupported argument
// RUN: not %clang -### --target=loongarch64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s
// RUN: not %clang -### --target=riscv64-linux -mtls-dialect=gnu2 %s 2>&1 | FileCheck --check-prefix=UNSUPPORTED-ARG %s

// DESC: "-cc1" {{.*}}"-enable-tlsdesc"
Expand Down
108 changes: 108 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class LoongArchPreRAExpandPseudo : public MachineFunctionPass {
bool expandLoadAddressTLSGD(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandLoadAddressTLSDesc(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
};

char LoongArchPreRAExpandPseudo::ID = 0;
Expand Down Expand Up @@ -122,6 +125,8 @@ bool LoongArchPreRAExpandPseudo::expandMI(
return expandLoadAddressTLSLD(MBB, MBBI, NextMBBI);
case LoongArch::PseudoLA_TLS_GD:
return expandLoadAddressTLSGD(MBB, MBBI, NextMBBI);
case LoongArch::PseudoLA_TLS_DESC_PC:
return expandLoadAddressTLSDesc(MBB, MBBI, NextMBBI);
}
return false;
}
Expand Down Expand Up @@ -267,6 +272,52 @@ bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSGD(
SecondOpcode, LoongArchII::MO_GOT_PC_LO);
}

bool LoongArchPreRAExpandPseudo::expandLoadAddressTLSDesc(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI) {
// Code Sequence:
// pcalau12i $a0, %desc_pc_hi20(sym)
// addi.w/d $a0, $a0, %desc_pc_lo12(sym)
// ld.w/d $ra, $a0, %desc_ld(sym)
// jirl $ra, $ra, %desc_ld(sym)
// add.d $dst, $a0, $tp
MachineFunction *MF = MBB.getParent();
MachineInstr &MI = *MBBI;
DebugLoc DL = MI.getDebugLoc();

const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
unsigned ADD = STI.is64Bit() ? LoongArch::ADD_D : LoongArch::ADD_W;
unsigned ADDI = STI.is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
unsigned LD = STI.is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;

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::PCALAU12I), ScratchReg)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);

BuildMI(MBB, MBBI, DL, TII->get(ADDI), LoongArch::R4)
.addReg(ScratchReg)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);

BuildMI(MBB, MBBI, DL, TII->get(LD), LoongArch::R1)
.addReg(LoongArch::R4)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);

BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
.addReg(LoongArch::R1)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);

BuildMI(MBB, MBBI, DL, TII->get(ADD), DestReg)
.addReg(LoongArch::R4)
.addReg(LoongArch::R2);

MI.eraseFromParent();
return true;
}

class LoongArchExpandPseudo : public MachineFunctionPass {
public:
const LoongArchInstrInfo *TII;
Expand Down Expand Up @@ -313,6 +364,9 @@ class LoongArchExpandPseudo : public MachineFunctionPass {
bool expandLoadAddressTLSGDLarge(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandLoadAddressTLSDescPcLarge(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandFunctionCALL(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI,
Expand Down Expand Up @@ -361,6 +415,8 @@ bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
return expandLoadAddressTLSLDLarge(MBB, MBBI, NextMBBI);
case LoongArch::PseudoLA_TLS_GD_LARGE:
return expandLoadAddressTLSGDLarge(MBB, MBBI, NextMBBI);
case LoongArch::PseudoLA_TLS_DESC_PC_LARGE:
return expandLoadAddressTLSDescPcLarge(MBB, MBBI, NextMBBI);
case LoongArch::PseudoCALL:
case LoongArch::PseudoCALL_MEDIUM:
case LoongArch::PseudoCALL_LARGE:
Expand Down Expand Up @@ -560,6 +616,58 @@ bool LoongArchExpandPseudo::expandLoadAddressTLSGDLarge(
LoongArchII::MO_GD_PC_HI);
}

bool LoongArchExpandPseudo::expandLoadAddressTLSDescPcLarge(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI) {
// Code Sequence:
//
// pcalau12i $a0, %desc_pc_hi20(sym)
// addi.d $t8, $zero, %desc_pc_lo12(sym)
// lu32i.d $t8, %desc64_pc_lo20(sym)
// lu52i.d $t8, $t8, %desc64_pc_hi12(sym)
// add.d $a0, $a0, $t8
// ld.d $ra, $a0, %desc_ld(sym)
// jirl $ra, $ra, %desc_call(sym)
// add.d $dst, $a0, $tp

MachineInstr &MI = *MBBI;
DebugLoc DL = MI.getDebugLoc();
Register DestReg = MI.getOperand(0).getReg();
MachineOperand &Symbol = MI.getOperand(2);
Register ScratchReg = LoongArch::R20; // $t8

assert(MBB.getParent()->getSubtarget<LoongArchSubtarget>().is64Bit() &&
"Large code model requires LA64");

BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PCALAU12I), LoongArch::R4)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_HI);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADDI_D), ScratchReg)
.addReg(LoongArch::R0)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_PC_LO);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU32I_D), ScratchReg)
.addReg(ScratchReg)
.addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_LO);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU52I_D), ScratchReg)
.addReg(ScratchReg)
.addDisp(Symbol, 0, LoongArchII::MO_DESC64_PC_HI);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), LoongArch::R4)
.addReg(ScratchReg)
.addReg(LoongArch::R4);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LD_D), LoongArch::R1)
.addReg(LoongArch::R4)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_LD);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PseudoDESC_CALL), LoongArch::R1)
.addReg(LoongArch::R1)
.addDisp(Symbol, 0, LoongArchII::MO_DESC_CALL);
BuildMI(MBB, MBBI, DL, TII->get(LoongArch::ADD_D), DestReg)
.addReg(LoongArch::R4)
.addReg(LoongArch::R2);

MI.eraseFromParent();

return true;
}

bool LoongArchExpandPseudo::expandFunctionCALL(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI, bool IsTailCall) {
Expand Down
50 changes: 36 additions & 14 deletions llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,24 @@ SDValue LoongArchTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N,
return LowerCallTo(CLI).first;
}

SDValue LoongArchTargetLowering::getTLSDescAddr(GlobalAddressSDNode *N,
SelectionDAG &DAG, unsigned Opc,
bool Large) const {
SDLoc DL(N);
EVT Ty = getPointerTy(DAG.getDataLayout());
const GlobalValue *GV = N->getGlobal();

// This is not actually used, but is necessary for successfully matching the
// PseudoLA_*_LARGE nodes.
SDValue Tmp = DAG.getConstant(0, DL, Ty);

// Use a PC-relative addressing mode to access the global dynamic GOT address.
// This generates the pattern (PseudoLA_TLS_DESC_PC{,LARGE} sym).
SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0);
return Large ? SDValue(DAG.getMachineNode(Opc, DL, Ty, Tmp, Addr), 0)
: SDValue(DAG.getMachineNode(Opc, DL, Ty, Addr), 0);
}

SDValue
LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
Expand All @@ -916,42 +934,46 @@ LoongArchTargetLowering::lowerGlobalTLSAddress(SDValue Op,
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
assert(N->getOffset() == 0 && "unexpected offset in global node");

SDValue Addr;
bool IsDesc = DAG.getTarget().useTLSDESC();

switch (getTargetMachine().getTLSModel(N->getGlobal())) {
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,
Large ? LoongArch::PseudoLA_TLS_GD_LARGE
: LoongArch::PseudoLA_TLS_GD,
Large);
if (!IsDesc)
return getDynamicTLSAddr(N, DAG,
Large ? LoongArch::PseudoLA_TLS_GD_LARGE
: LoongArch::PseudoLA_TLS_GD,
Large);
break;
case TLSModel::LocalDynamic:
// Same as GeneralDynamic, except for assembly modifiers and relocation
// records.
Addr = getDynamicTLSAddr(N, DAG,
Large ? LoongArch::PseudoLA_TLS_LD_LARGE
: LoongArch::PseudoLA_TLS_LD,
Large);
if (!IsDesc)
return getDynamicTLSAddr(N, DAG,
Large ? LoongArch::PseudoLA_TLS_LD_LARGE
: LoongArch::PseudoLA_TLS_LD,
Large);
break;
case TLSModel::InitialExec:
// This model uses the GOT to resolve TLS offsets.
Addr = getStaticTLSAddr(N, DAG,
return getStaticTLSAddr(N, DAG,
Large ? LoongArch::PseudoLA_TLS_IE_LARGE
: LoongArch::PseudoLA_TLS_IE,
Large);
break;
case TLSModel::LocalExec:
// This model is used when static linking as the TLS offsets are resolved
// during program linking.
//
// This node doesn't need an extra argument for the large code model.
Addr = getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
break;
return getStaticTLSAddr(N, DAG, LoongArch::PseudoLA_TLS_LE);
}

return Addr;
return getTLSDescAddr(N, DAG,
Large ? LoongArch::PseudoLA_TLS_DESC_PC_LARGE
: LoongArch::PseudoLA_TLS_DESC_PC,
Large);
}

template <unsigned N>
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ class LoongArchTargetLowering : public TargetLowering {
unsigned Opc, bool Large = false) const;
SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
unsigned Opc, bool Large = false) const;
SDValue getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG,
unsigned Opc, bool Large = false) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerJumpTable(SDValue Op, SelectionDAG &DAG) const;
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,12 @@ LoongArchInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
{MO_IE_PC_LO, "loongarch-ie-pc-lo"},
{MO_IE_PC64_LO, "loongarch-ie-pc64-lo"},
{MO_IE_PC64_HI, "loongarch-ie-pc64-hi"},
{MO_DESC_PC_HI, "loongarch-desc-pc-hi"},
{MO_DESC_PC_LO, "loongarch-desc-pc-lo"},
{MO_DESC64_PC_LO, "loongarch-desc64-pc-lo"},
{MO_DESC64_PC_HI, "loongarch-desc64-pc-hi"},
{MO_DESC_LD, "loongarch-desc-ld"},
{MO_DESC_CALL, "loongarch-desc-call"},
{MO_LD_PC_HI, "loongarch-ld-pc-hi"},
{MO_GD_PC_HI, "loongarch-gd-pc-hi"}};
return ArrayRef(TargetFlags);
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,13 @@ def PseudoLA_TLS_GD_LARGE : Pseudo<(outs GPR:$dst),
} // Defs = [R20], Size = 20
}

// Used for expand PseudoLA_TLS_DESC_* instructions.
let isCall = 1, isBarrier = 1, hasSideEffects = 0, mayStore = 0, mayLoad = 0,
Defs = [R4], Uses = [R4] in
def PseudoDESC_CALL : Pseudo<(outs GPR:$rd), (ins GPR:$rj, simm16_lsl2:$imm16)>,
PseudoInstExpansion<(JIRL GPR:$rd, GPR:$rj,
simm16_lsl2:$imm16)>;

// TLSDESC
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
isAsmParserOnly = 1, Defs = [R1] in {
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchMCInstLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
case LoongArchII::MO_CALL36:
Kind = LoongArchMCExpr::VK_LoongArch_CALL36;
break;
case LoongArchII::MO_DESC_PC_HI:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20;
break;
case LoongArchII::MO_DESC_PC_LO:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12;
break;
case LoongArchII::MO_DESC64_PC_LO:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20;
break;
case LoongArchII::MO_DESC64_PC_HI:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12;
break;
case LoongArchII::MO_DESC_LD:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD;
break;
case LoongArchII::MO_DESC_CALL:
Kind = LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL;
break;
// TODO: Handle more target-flags.
}

Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ enum {
MO_IE_PC64_HI,
MO_LD_PC_HI,
MO_GD_PC_HI,
MO_CALL36
MO_CALL36,
MO_DESC_PC_HI,
MO_DESC_PC_LO,
MO_DESC64_PC_HI,
MO_DESC64_PC_LO,
MO_DESC_LD,
MO_DESC_CALL,
// TODO: Add more flags.
};
} // end namespace LoongArchII
Expand Down
Loading

0 comments on commit eb148ae

Please sign in to comment.