diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 4250950a917299..7d42481db57fa9 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -199,6 +199,8 @@ class RISCVAsmParser : public MCTargetAsmParser { ParseStatus parseInsnDirectiveOpcode(OperandVector &Operands); ParseStatus parseInsnCDirectiveOpcode(OperandVector &Operands); ParseStatus parseGPRAsFPR(OperandVector &Operands); + template ParseStatus parseGPRPair(OperandVector &Operands); + ParseStatus parseGPRPair(OperandVector &Operands, bool IsRV64Inst); ParseStatus parseFRMArg(OperandVector &Operands); ParseStatus parseFenceArg(OperandVector &Operands); ParseStatus parseReglist(OperandVector &Operands); @@ -466,6 +468,12 @@ struct RISCVOperand final : public MCParsedAsmOperand { bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; } + bool isGPRPair() const { + return Kind == KindTy::Register && + RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains( + Reg.RegNum); + } + static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm, RISCVMCExpr::VariantKind &VK) { if (auto *RE = dyn_cast(Expr)) { @@ -1300,6 +1308,10 @@ unsigned RISCVAsmParser::checkTargetMatchPredicate(MCInst &Inst) { assert(Op.isReg()); MCRegister Reg = Op.getReg(); + if (RISCVMCRegisterClasses[RISCV::GPRPairRegClassID].contains(Reg)) + continue; + + // FIXME: We should form a paired register during parsing/matching. if (((Reg.id() - RISCV::X0) & 1) != 0) return Match_RequiresEvenGPRs; } @@ -2222,6 +2234,48 @@ ParseStatus RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) { return ParseStatus::Success; } +template +ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands) { + return parseGPRPair(Operands, IsRV64); +} + +ParseStatus RISCVAsmParser::parseGPRPair(OperandVector &Operands, + bool IsRV64Inst) { + // If this is not an RV64 GPRPair instruction, don't parse as a GPRPair on + // RV64 as it will prevent matching the RV64 version of the same instruction + // that doesn't use a GPRPair. + // If this is an RV64 GPRPair instruction, there is no RV32 version so we can + // still parse as a pair. + if (!IsRV64Inst && isRV64()) + return ParseStatus::NoMatch; + + if (getLexer().isNot(AsmToken::Identifier)) + return ParseStatus::NoMatch; + + StringRef Name = getLexer().getTok().getIdentifier(); + MCRegister RegNo = matchRegisterNameHelper(isRVE(), Name); + + if (!RegNo) + return ParseStatus::NoMatch; + + if (!RISCVMCRegisterClasses[RISCV::GPRRegClassID].contains(RegNo)) + return ParseStatus::NoMatch; + + if ((RegNo - RISCV::X0) & 1) + return TokError("register must be even"); + + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); + getLexer().Lex(); + + const MCRegisterInfo *RI = getContext().getRegisterInfo(); + unsigned Pair = RI->getMatchingSuperReg( + RegNo, RISCV::sub_gpr_even, + &RISCVMCRegisterClasses[RISCV::GPRPairRegClassID]); + Operands.push_back(RISCVOperand::createReg(Pair, S, E)); + return ParseStatus::Success; +} + ParseStatus RISCVAsmParser::parseFRMArg(OperandVector &Operands) { if (getLexer().isNot(AsmToken::Identifier)) return TokError( @@ -3335,27 +3389,6 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst, return Error(Loc, "Operand must be constant 4."); } - bool IsAMOCAS_D = Opcode == RISCV::AMOCAS_D || Opcode == RISCV::AMOCAS_D_AQ || - Opcode == RISCV::AMOCAS_D_RL || - Opcode == RISCV::AMOCAS_D_AQ_RL; - bool IsAMOCAS_Q = Opcode == RISCV::AMOCAS_Q || Opcode == RISCV::AMOCAS_Q_AQ || - Opcode == RISCV::AMOCAS_Q_RL || - Opcode == RISCV::AMOCAS_Q_AQ_RL; - if ((!isRV64() && IsAMOCAS_D) || IsAMOCAS_Q) { - unsigned Rd = Inst.getOperand(0).getReg(); - unsigned Rs2 = Inst.getOperand(2).getReg(); - assert(Rd >= RISCV::X0 && Rd <= RISCV::X31); - if ((Rd - RISCV::X0) % 2 != 0) { - SMLoc Loc = Operands[1]->getStartLoc(); - return Error(Loc, "The destination register must be even."); - } - assert(Rs2 >= RISCV::X0 && Rs2 <= RISCV::X31); - if ((Rs2 - RISCV::X0) % 2 != 0) { - SMLoc Loc = Operands[2]->getStartLoc(); - return Error(Loc, "The source register must be even."); - } - } - const MCInstrDesc &MCID = MII.get(Opcode); if (!(MCID.TSFlags & RISCVII::ConstraintMask)) return false; diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index bc65cf2403b262..4dd039159e29dc 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -546,6 +546,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, !STI.hasFeature(RISCV::Feature64Bit), DecoderTableRV32Zdinx32, "RV32Zdinx table (Double in Integer and rv32)"); + TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZacas) && + !STI.hasFeature(RISCV::Feature64Bit), + DecoderTableRV32Zacas32, + "RV32Zacas table (Compare-And-Swap and rv32)"); TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32, "RVZfinx table (Float in Integer)"); TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td index a09f5715b24ff5..ea8046d119d042 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td @@ -17,13 +17,54 @@ // Zacas (Atomic Compare-and-Swap) //===----------------------------------------------------------------------===// +def GPRPairRV32Operand : AsmOperandClass { + let Name = "GPRPairRV32"; + let ParserMethod = "parseGPRPair"; + let PredicateMethod = "isGPRPair"; + let RenderMethod = "addRegOperands"; +} + +def GPRPairRV64Operand : AsmOperandClass { + let Name = "GPRPairRV64"; + let ParserMethod = "parseGPRPair"; + let PredicateMethod = "isGPRPair"; + let RenderMethod = "addRegOperands"; +} + +def GPRPairRV32 : RegisterOperand { + let ParserMatchClass = GPRPairRV32Operand; +} + +def GPRPairRV64 : RegisterOperand { + let ParserMatchClass = GPRPairRV64Operand; +} + +let hasSideEffects = 0, mayLoad = 1, mayStore = 1, Constraints = "$rd = $rd_wb" in +class AMO_cas funct5, bit aq, bit rl, bits<3> funct3, string opcodestr, + DAGOperand RC> + : RVInstRAtomic; + +multiclass AMO_cas_aq_rl funct5, bits<3> funct3, string opcodestr, + DAGOperand RC> { + def "" : AMO_cas; + def _AQ : AMO_cas; + def _RL : AMO_cas; + def _AQ_RL : AMO_cas; +} + let Predicates = [HasStdExtZacas] in { -defm AMOCAS_W : AMO_rr_aq_rl<0b00101, 0b010, "amocas.w">; -defm AMOCAS_D : AMO_rr_aq_rl<0b00101, 0b011, "amocas.d">; +defm AMOCAS_W : AMO_cas_aq_rl<0b00101, 0b010, "amocas.w", GPR>; } // Predicates = [HasStdExtZacas] +let Predicates = [HasStdExtZacas, IsRV32], DecoderNamespace = "RV32Zacas" in { +defm AMOCAS_D_RV32 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPRPairRV32>; +} // Predicates = [HasStdExtZacas, IsRV32] + let Predicates = [HasStdExtZacas, IsRV64] in { -defm AMOCAS_Q : AMO_rr_aq_rl<0b00101, 0b100, "amocas.q">; +defm AMOCAS_D_RV64 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPR>; +defm AMOCAS_Q : AMO_cas_aq_rl<0b00101, 0b100, "amocas.q", GPRPairRV64>; } // Predicates = [HasStdExtZacas, IsRV64] //===----------------------------------------------------------------------===// diff --git a/llvm/test/MC/RISCV/rv32zacas-invalid.s b/llvm/test/MC/RISCV/rv32zacas-invalid.s index f6a5858d9b3ee9..b86246ca2ed180 100644 --- a/llvm/test/MC/RISCV/rv32zacas-invalid.s +++ b/llvm/test/MC/RISCV/rv32zacas-invalid.s @@ -2,17 +2,17 @@ # Non-zero offsets not supported for the third operand (rs1). amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 -amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amocas.d a0, a2, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 # First and second operands (rd and rs2) of amocas.d must be even for RV32. -amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even. -amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even. -amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even. -amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even. -amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even. -amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even. -amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even. -amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even. +amocas.d a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even +amocas.d a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even +amocas.d.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even +amocas.d.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even +amocas.d.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even +amocas.d.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even +amocas.d.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even +amocas.d.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even # amocas.q is not supported for RV32. -amocas.q a1, a1, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}} +amocas.q a0, a0, (a1) # CHECK: :[[@LINE]]:1: error: instruction requires the following: RV64I Base Instruction Set{{$}} diff --git a/llvm/test/MC/RISCV/rv64zacas-invalid.s b/llvm/test/MC/RISCV/rv64zacas-invalid.s index feb570a2952784..e6a4e4007e9787 100644 --- a/llvm/test/MC/RISCV/rv64zacas-invalid.s +++ b/llvm/test/MC/RISCV/rv64zacas-invalid.s @@ -3,14 +3,14 @@ # Non-zero offsets not supported for the third operand (rs1). amocas.w a1, a3, 1(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 amocas.d a1, a3, 2(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 -amocas.q a1, a3, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 +amocas.q a0, a2, 3(a5) # CHECK: :[[@LINE]]:18: error: optional integer offset must be 0 # First and second operands (rd and rs2) of amocas.q must be even. -amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: The destination register must be even. -amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: The source register must be even. -amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even. -amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even. -amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: The destination register must be even. -amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: The source register must be even. -amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: The destination register must be even. -amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: The source register must be even. +amocas.q a1, a2, (a1) # CHECK: :[[@LINE]]:10: error: register must be even +amocas.q a0, a1, (a1) # CHECK: :[[@LINE]]:14: error: register must be even +amocas.q.aq a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even +amocas.q.aq a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even +amocas.q.rl a1, a2, (a1) # CHECK: :[[@LINE]]:13: error: register must be even +amocas.q.rl a0, a1, (a1) # CHECK: :[[@LINE]]:17: error: register must be even +amocas.q.aqrl a1, a2, (a1) # CHECK: :[[@LINE]]:15: error: register must be even +amocas.q.aqrl a0, a1, (a1) # CHECK: :[[@LINE]]:19: error: register must be even