diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-26 22:04:10 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2024-07-26 22:04:10 +0000 |
| commit | ac9a064cb179f3425b310fa2847f8764ac970a4d (patch) | |
| tree | 6f945cdaa68c2b4c688dcf9fec4f922d35f4d1a4 /llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp | |
| parent | 4df029cc74e5ec124f14a5682e44999ce4f086df (diff) | |
Diffstat (limited to 'llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp')
| -rw-r--r-- | llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp | 202 |
1 files changed, 193 insertions, 9 deletions
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp index 46f63a4103f9..208bd3db8f14 100644 --- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -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); @@ -132,6 +139,7 @@ public: Match_RequiresOpnd2NotR0R1, Match_RequiresAMORdDifferRkRj, Match_RequiresLAORdDifferRj, + Match_RequiresLAORdR4, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "LoongArchGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -237,6 +245,16 @@ public: VK == LoongArchMCExpr::VK_LoongArch_None; } + bool isTPRelAddSymbol() const { + int64_t Imm; + LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; + // Must be of 'immediate' type but not a constant. + if (!isImm() || evaluateConstantImm(getImm(), Imm, VK)) + return false; + return LoongArchAsmParser::classifySymbolRef(getImm(), VK) && + VK == LoongArchMCExpr::VK_LoongArch_TLS_LE_ADD_R; + } + bool isUImm1() const { return isUImm<1>(); } bool isUImm2() const { return isUImm<2>(); } bool isUImm2plus1() const { return isUImm<2, 1>(); } @@ -267,7 +285,10 @@ public: 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_LE_LO12_R || + 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) && @@ -288,7 +309,9 @@ public: 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) && @@ -311,7 +334,8 @@ public: 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) && @@ -334,7 +358,8 @@ public: 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) && @@ -355,7 +380,8 @@ public: 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) && @@ -375,7 +401,9 @@ public: 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_LE_HI20_R || + VK == LoongArchMCExpr::VK_LoongArch_TLS_DESC_HI20; return IsConstantImm ? isInt<20>(Imm) && IsValidKind : LoongArchAsmParser::classifySymbolRef(getImm(), VK) && @@ -396,7 +424,9 @@ public: 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 @@ -453,15 +483,23 @@ public: } bool isImm32() const { return isSImm<32>() || isUImm<32>(); } + bool isImm64() const { + if (!isImm()) + return false; + int64_t Imm; + LoongArchMCExpr::VariantKind VK = LoongArchMCExpr::VK_LoongArch_None; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && VK == LoongArchMCExpr::VK_LoongArch_None; + } /// Gets location of the first token of this operand. SMLoc getStartLoc() const override { return StartLoc; } /// Gets location of the last token of this operand. SMLoc getEndLoc() const override { return EndLoc; } - unsigned getReg() const override { + MCRegister getReg() const override { assert(Kind == KindTy::Register && "Invalid type access!"); - return Reg.RegNum.id(); + return Reg.RegNum; } const MCExpr *getImm() const { @@ -793,6 +831,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), @@ -825,6 +870,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; } } } @@ -1108,6 +1160,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(); @@ -1203,6 +1358,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); @@ -1230,6 +1395,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: @@ -1368,6 +1542,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); @@ -1514,10 +1690,18 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a 32 bit immediate"); } + case Match_InvalidImm64: { + SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be a 64 bit immediate"); + } case Match_InvalidBareSymbol: { SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a bare symbol name"); } + case Match_InvalidTPRelAddSymbol: { + SMLoc ErrorLoc = ((LoongArchOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "operand must be a symbol with %le_add_r modifier"); + } } llvm_unreachable("Unknown match type detected!"); } |
