Skip to content

Commit

Permalink
[LoongArch] Support parsing la.tls.desc pseudo instruction
Browse files Browse the repository at this point in the history
Simultaneously implemented parsing support for the `%desc_*` modifiers.

Reviewers: SixWeining, heiher, xen0n

Reviewed By: xen0n, SixWeining

Pull Request: #90158
  • Loading branch information
wangleiat committed Apr 30, 2024
1 parent 2524146 commit 4a84d8e
Show file tree
Hide file tree
Showing 10 changed files with 398 additions and 7 deletions.
170 changes: 163 additions & 7 deletions llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ class LoongArchAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo instruction "la.tls.gd $rd, $rj, sym".
void emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "la.tls.desc $rd, sym".
void emitLoadAddressTLSDescAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
void emitLoadAddressTLSDescPcrel(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);
// Helper to emit pseudo instruction "la.tls.desc $rd, $rj, sym".
void emitLoadAddressTLSDescPcrelLarge(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out);

// Helper to emit pseudo instruction "li.w/d $rd, $imm".
void emitLoadImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

Expand All @@ -132,6 +139,7 @@ class LoongArchAsmParser : public MCTargetAsmParser {
Match_RequiresOpnd2NotR0R1,
Match_RequiresAMORdDifferRkRj,
Match_RequiresLAORdDifferRj,
Match_RequiresLAORdR4,
#define GET_OPERAND_DIAGNOSTIC_TYPES
#include "LoongArchGenAsmMatcher.inc"
#undef GET_OPERAND_DIAGNOSTIC_TYPES
Expand Down Expand Up @@ -267,7 +275,9 @@ class LoongArchOperand : public MCParsedAsmOperand {
bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD;
return IsConstantImm
? isInt<12>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -288,7 +298,9 @@ class LoongArchOperand : public MCParsedAsmOperand {
VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12;
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_HI12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12;
return IsConstantImm
? isInt<12>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -311,7 +323,8 @@ class LoongArchOperand : public MCParsedAsmOperand {
VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12;
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LO12;
return IsConstantImm
? isUInt<12>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -334,7 +347,8 @@ class LoongArchOperand : public MCParsedAsmOperand {
bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK);
bool IsValidKind = VK == LoongArchMCExpr::VK_LoongArch_None ||
VK == LoongArchMCExpr::VK_LoongArch_B16 ||
VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12;
VK == LoongArchMCExpr::VK_LoongArch_PCALA_LO12 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL;
return IsConstantImm
? isShiftedInt<16, 2>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -355,7 +369,8 @@ class LoongArchOperand : public MCParsedAsmOperand {
VK == LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20;
VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20;
return IsConstantImm
? isInt<20>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -375,7 +390,8 @@ class LoongArchOperand : public MCParsedAsmOperand {
VK == LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20;
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20;
return IsConstantImm
? isInt<20>(Imm) && IsValidKind
: LoongArchAsmParser::classifySymbolRef(getImm(), VK) &&
Expand All @@ -396,7 +412,9 @@ class LoongArchOperand : public MCParsedAsmOperand {
VK == LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20;
VK == LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20 ||
VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC64_LO20;

return IsConstantImm
? isInt<20>(Imm) && IsValidKind
Expand Down Expand Up @@ -801,6 +819,13 @@ void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addImm(0),
getSTI());
continue;
} else if (VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD) {
Out.emitInstruction(MCInstBuilder(Opc)
.addReg(LoongArch::R1)
.addReg(DestReg)
.addExpr(LE),
getSTI());
continue;
}
Out.emitInstruction(
MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addExpr(LE),
Expand Down Expand Up @@ -833,6 +858,13 @@ void LoongArchAsmParser::emitLAInstSeq(MCRegister DestReg, MCRegister TmpReg,
MCInstBuilder(Opc).addReg(DestReg).addReg(DestReg).addReg(TmpReg),
getSTI());
break;
case LoongArch::JIRL:
Out.emitInstruction(MCInstBuilder(Opc)
.addReg(LoongArch::R1)
.addReg(LoongArch::R1)
.addExpr(LE),
getSTI());
break;
}
}
}
Expand Down Expand Up @@ -1116,6 +1148,109 @@ void LoongArchAsmParser::emitLoadAddressTLSGDLarge(MCInst &Inst, SMLoc IDLoc,
emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
}

void LoongArchAsmParser::emitLoadAddressTLSDescAbs(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// `la.tls.desc $rd, sym` with `la-global-with-abs` feature
// for la32 expands to:
// lu12i.w $rd, %desc_hi20(sym)
// ori $rd, $rd, %desc_lo12(sym)
// ld.w $ra, $rd, %desc_ld(sym)
// jirl $ra, $ra, %desc_call(sym)
//
// for la64 expands to:
// lu12i.w $rd, %desc_hi20(sym)
// ori $rd, $rd, %desc_lo12(sym)
// lu32i.d $rd, %desc64_lo20(sym)
// lu52i.d $rd, $rd, %desc64_hi12(sym)
// ld.d $ra, $rd, %desc_ld(sym)
// jirl $ra, $ra, %desc_call(sym)
MCRegister DestReg = Inst.getOperand(0).getReg();
const MCExpr *Symbol = Inst.getOpcode() == LoongArch::PseudoLA_TLS_DESC_ABS
? Inst.getOperand(1).getExpr()
: Inst.getOperand(2).getExpr();
unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
InstSeq Insts;

Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LU12I_W, LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::ORI, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LO12));

if (is64Bit()) {
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_LO20));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_HI12));
}

Insts.push_back(
LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL));

emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
}

void LoongArchAsmParser::emitLoadAddressTLSDescPcrel(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// la.tls.desc $rd, sym
// expands to:
// pcalau12i $rd, %desc_pc_hi20(sym)
// addi.w/d $rd, $rd, %desc_pc_lo12(sym)
// ld.w/d $ra, $rd, %desc_ld(sym)
// jirl $ra, $ra, %desc_call(sym)
MCRegister DestReg = Inst.getOperand(0).getReg();
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
unsigned ADDI = is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
unsigned LD = is64Bit() ? LoongArch::LD_D : LoongArch::LD_W;
InstSeq Insts;

Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20));
Insts.push_back(LoongArchAsmParser::Inst(
ADDI, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12));
Insts.push_back(
LoongArchAsmParser::Inst(LD, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL));

emitLAInstSeq(DestReg, DestReg, Symbol, Insts, IDLoc, Out);
}

void LoongArchAsmParser::emitLoadAddressTLSDescPcrelLarge(MCInst &Inst,
SMLoc IDLoc,
MCStreamer &Out) {
// la.tls.desc $rd, $rj, sym
// expands to:
// pcalau12i $rd, %desc_pc_hi20(sym)
// addi.d $rj, $r0, %desc_pc_lo12(sym)
// lu32i.d $rj, %desc64_pc_lo20(sym)
// lu52i.d $rj, $rj, %desc64_pc_hi12(sym)
// add.d $rd, $rd, $rj
// ld.w/d $ra, $rd, %desc_ld(sym)
// jirl $ra, $ra, %desc_call(sym)
MCRegister DestReg = Inst.getOperand(0).getReg();
MCRegister TmpReg = Inst.getOperand(1).getReg();
const MCExpr *Symbol = Inst.getOperand(2).getExpr();
InstSeq Insts;

Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::PCALAU12I, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::ADDI_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LU32I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LU52I_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12));
Insts.push_back(LoongArchAsmParser::Inst(LoongArch::ADD_D));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::LD_D, LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD));
Insts.push_back(LoongArchAsmParser::Inst(
LoongArch::JIRL, LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL));

emitLAInstSeq(DestReg, TmpReg, Symbol, Insts, IDLoc, Out);
}

void LoongArchAsmParser::emitLoadImm(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
MCRegister DestReg = Inst.getOperand(0).getReg();
Expand Down Expand Up @@ -1211,6 +1346,16 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
case LoongArch::PseudoLA_TLS_GD_LARGE:
emitLoadAddressTLSGDLarge(Inst, IDLoc, Out);
return false;
case LoongArch::PseudoLA_TLS_DESC_ABS:
case LoongArch::PseudoLA_TLS_DESC_ABS_LARGE:
emitLoadAddressTLSDescAbs(Inst, IDLoc, Out);
return false;
case LoongArch::PseudoLA_TLS_DESC_PC:
emitLoadAddressTLSDescPcrel(Inst, IDLoc, Out);
return false;
case LoongArch::PseudoLA_TLS_DESC_PC_LARGE:
emitLoadAddressTLSDescPcrelLarge(Inst, IDLoc, Out);
return false;
case LoongArch::PseudoLI_W:
case LoongArch::PseudoLI_D:
emitLoadImm(Inst, IDLoc, Out);
Expand Down Expand Up @@ -1238,6 +1383,15 @@ unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
return Match_RequiresAMORdDifferRkRj;
}
break;
case LoongArch::PseudoLA_TLS_DESC_ABS:
case LoongArch::PseudoLA_TLS_DESC_ABS_LARGE:
case LoongArch::PseudoLA_TLS_DESC_PC:
case LoongArch::PseudoLA_TLS_DESC_PC_LARGE: {
unsigned Rd = Inst.getOperand(0).getReg();
if (Rd != LoongArch::R4)
return Match_RequiresLAORdR4;
break;
}
case LoongArch::PseudoLA_PCREL_LARGE:
case LoongArch::PseudoLA_GOT_LARGE:
case LoongArch::PseudoLA_TLS_IE_LARGE:
Expand Down Expand Up @@ -1376,6 +1530,8 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
"$rd must be different from both $rk and $rj");
case Match_RequiresLAORdDifferRj:
return Error(Operands[1]->getStartLoc(), "$rd must be different from $rj");
case Match_RequiresLAORdR4:
return Error(Operands[1]->getStartLoc(), "$rd must be $r4");
case Match_InvalidUImm1:
return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
/*Upper=*/(1 << 1) - 1);
Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,27 @@ def PseudoLA_TLS_GD_LARGE : Pseudo<(outs GPR:$dst),
} // Defs = [R20], Size = 20
}

// TLSDESC
let hasSideEffects = 0, mayLoad = 1, mayStore = 0, isCodeGenOnly = 0,
isAsmParserOnly = 1, Defs = [R1] in {
def PseudoLA_TLS_DESC_ABS : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src),
[], "la.tls.desc", "$dst, $src">,
Requires<[IsLA32, HasLaGlobalWithAbs]>;
def PseudoLA_TLS_DESC_ABS_LARGE : Pseudo<(outs GPR:$dst),
(ins GPR:$tmp, bare_symbol:$src), [],
"la.tls.desc", "$dst, $src">,
Requires<[IsLA64, HasLaGlobalWithAbs]>;
def PseudoLA_TLS_DESC_PC : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
"la.tls.desc", "$dst, $src">;
}

let isCall = 1, isBarrier = 1, hasSideEffects = 0, mayStore = 0, mayLoad = 0,
isCodeGenOnly = 0, isAsmParserOnly = 1, Defs = [R1, R4, R20], Size = 32 in
def PseudoLA_TLS_DESC_PC_LARGE : Pseudo<(outs GPR:$dst),
(ins GPR:$tmp, bare_symbol:$src), [],
"la.tls.desc", "$dst, $tmp, $src">,
Requires<[IsLA64]>;

// Load address inst alias: "la", "la.global" and "la.local".
// Default:
// la = la.global = la.got
Expand Down
22 changes: 22 additions & 0 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchFixupKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,28 @@ enum Fixups {
// 36-bit fixup corresponding to %call36(foo) for a pair instructions:
// pcaddu18i+jirl.
fixup_loongarch_call36 = FirstLiteralRelocationKind + ELF::R_LARCH_CALL36,
// 20-bit fixup corresponding to %desc_pc_hi20(foo) for instruction pcalau12i.
fixup_loongarch_tls_desc_pc_hi20 =
FirstLiteralRelocationKind + ELF::R_LARCH_TLS_DESC_PC_HI20,
// 12-bit fixup corresponding to %desc_pc_lo12(foo) for instructions like
// addi.w/d.
fixup_loongarch_tls_desc_pc_lo12,
// 20-bit fixup corresponding to %desc64_pc_lo20(foo) for instruction lu32i.d.
fixup_loongarch_tls_desc64_pc_lo20,
// 12-bit fixup corresponding to %desc64_pc_hi12(foo) for instruction lu52i.d.
fixup_loongarch_tls_desc64_pc_hi12,
// 20-bit fixup corresponding to %desc_hi20(foo) for instruction lu12i.w.
fixup_loongarch_tls_desc_hi20,
// 12-bit fixup corresponding to %desc_lo12(foo) for instruction ori.
fixup_loongarch_tls_desc_lo12,
// 20-bit fixup corresponding to %desc64_lo20(foo) for instruction lu32i.d.
fixup_loongarch_tls_desc64_lo20,
// 12-bit fixup corresponding to %desc64_hi12(foo) for instruction lu52i.d.
fixup_loongarch_tls_desc64_hi12,
// 12-bit fixup corresponding to %desc_ld(foo) for instruction ld.w/d.
fixup_loongarch_tls_desc_ld,
// 12-bit fixup corresponding to %desc_call(foo) for instruction jirl.
fixup_loongarch_tls_desc_call,
};
} // end namespace LoongArch
} // end namespace llvm
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,36 @@ LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
case LoongArchMCExpr::VK_LoongArch_CALL36:
FixupKind = LoongArch::fixup_loongarch_call36;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_HI20:
FixupKind = LoongArch::fixup_loongarch_tls_desc_pc_hi20;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_PC_LO12:
FixupKind = LoongArch::fixup_loongarch_tls_desc_pc_lo12;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_LO20:
FixupKind = LoongArch::fixup_loongarch_tls_desc64_pc_lo20;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC64_PC_HI12:
FixupKind = LoongArch::fixup_loongarch_tls_desc64_pc_hi12;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20:
FixupKind = LoongArch::fixup_loongarch_tls_desc_hi20;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_LO12:
FixupKind = LoongArch::fixup_loongarch_tls_desc_lo12;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC64_LO20:
FixupKind = LoongArch::fixup_loongarch_tls_desc64_lo20;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC64_HI12:
FixupKind = LoongArch::fixup_loongarch_tls_desc64_hi12;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_LD:
FixupKind = LoongArch::fixup_loongarch_tls_desc_ld;
break;
case LoongArchMCExpr::VK_LoongArch_TLS_DESC_CALL:
FixupKind = LoongArch::fixup_loongarch_tls_desc_call;
break;
}
} else if (Kind == MCExpr::SymbolRef &&
cast<MCSymbolRefExpr>(Expr)->getKind() ==
Expand Down

0 comments on commit 4a84d8e

Please sign in to comment.