diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -78,6 +78,7 @@ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; + unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, Twine Msg); @@ -229,6 +230,7 @@ public: enum RISCVMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresEvenGPRs, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "RISCVGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -285,7 +287,6 @@ struct RegOp { MCRegister RegNum; - bool IsRV64; bool IsGPRAsFPR; }; @@ -373,12 +374,9 @@ bool isGPRAsFPR() const { return isGPR() && Reg.IsGPRAsFPR; } - bool isGPRF64AsFPR() const { return isGPR() && Reg.IsGPRAsFPR && Reg.IsRV64; } + bool isGPRF64AsFPR() const { return isGPR() && Reg.IsGPRAsFPR; } - bool isGPRPF64AsFPR() const { - return isGPR() && Reg.IsGPRAsFPR && !Reg.IsRV64 && - !((Reg.RegNum - RISCV::X0) & 1); - } + bool isGPRPF64AsFPR() const { return isGPR() && Reg.IsGPRAsFPR; } static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm, RISCVMCExpr::VariantKind &VK) { @@ -854,12 +852,10 @@ return Op; } - static std::unique_ptr createReg(unsigned RegNo, SMLoc S, - SMLoc E, bool IsRV64, - bool IsGPRAsFPR = false) { + static std::unique_ptr + createReg(unsigned RegNo, SMLoc S, SMLoc E, bool IsGPRAsFPR = false) { auto Op = std::make_unique(KindTy::Register); Op->Reg.RegNum = RegNo; - Op->Reg.IsRV64 = IsRV64; Op->Reg.IsGPRAsFPR = IsGPRAsFPR; Op->StartLoc = S; Op->EndLoc = E; @@ -1037,6 +1033,23 @@ return Match_InvalidOperand; } +unsigned RISCVAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + const MCInstrDesc &MCID = MII.get(Inst.getOpcode()); + + for (unsigned I = 0; I < MCID.NumOperands; ++I) { + if (MCID.operands()[I].RegClass == RISCV::GPRPF64RegClassID) { + const auto &Op = Inst.getOperand(I); + assert(Op.isReg()); + + MCRegister Reg = Op.getReg(); + if (((Reg.id() - RISCV::X0) & 1) != 0) + return Match_RequiresEvenGPRs; + } + } + + return Match_Success; +} + bool RISCVAsmParser::generateImmOutOfRangeError( OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, Twine Msg = "immediate must be an integer in the range") { @@ -1106,6 +1119,10 @@ switch (Result) { default: break; + case Match_RequiresEvenGPRs: + return Error(IDLoc, + "double precision floating point operands must use even " + "numbered X register"); case Match_InvalidImmXLenLI: if (isRV64()) { SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); @@ -1342,7 +1359,7 @@ SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); - Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); + Operands.push_back(RISCVOperand::createReg(RegNo, S, E)); } if (HadParens) { @@ -1775,7 +1792,7 @@ SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); - Operands.push_back(RISCVOperand::createReg(RegNo, S, E, isRV64())); + Operands.push_back(RISCVOperand::createReg(RegNo, S, E)); return MatchOperand_Success; } @@ -1793,7 +1810,7 @@ SMLoc E = SMLoc::getFromPointer(S.getPointer() + Name.size()); getLexer().Lex(); Operands.push_back(RISCVOperand::createReg( - RegNo, S, E, isRV64(), !getSTI().hasFeature(RISCV::FeatureStdExtF))); + RegNo, S, E, !getSTI().hasFeature(RISCV::FeatureStdExtF))); return MatchOperand_Success; } @@ -2637,7 +2654,7 @@ std::unique_ptr RISCVAsmParser::defaultMaskRegOp() const { return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(), - llvm::SMLoc(), isRV64()); + llvm::SMLoc()); } std::unique_ptr RISCVAsmParser::defaultFRMArgOp() const { diff --git a/llvm/test/MC/RISCV/rv32zdinx-invalid.s b/llvm/test/MC/RISCV/rv32zdinx-invalid.s --- a/llvm/test/MC/RISCV/rv32zdinx-invalid.s +++ b/llvm/test/MC/RISCV/rv32zdinx-invalid.s @@ -1,7 +1,7 @@ # RUN: not llvm-mc -triple riscv32 -mattr=+zdinx %s 2>&1 | FileCheck %s # Unsupport Odd Registers in RV32 -fadd.d a0, a1, a2 # CHECK: :[[@LINE]]:12: error: invalid operand for instruction +fadd.d a0, a1, a2 # CHECK: :[[@LINE]]:1: error: double precision floating point operands must use even numbered X register # Not support float registers flw fa4, 12(sp) # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'F' (Single-Precision Floating-Point){{$}} diff --git a/llvm/test/MC/RISCV/rv32zfinx-invalid.s b/llvm/test/MC/RISCV/rv32zfinx-invalid.s --- a/llvm/test/MC/RISCV/rv32zfinx-invalid.s +++ b/llvm/test/MC/RISCV/rv32zfinx-invalid.s @@ -22,4 +22,4 @@ fnmsub.s x18, x19, x20, x21, 0b111 # CHECK: :[[@LINE]]:30: error: operand must be a valid floating point rounding mode mnemonic # Using 'Zdinx' instructions for an 'Zfinx'-only target -fadd.d t0, t1, t2 # CHECK: :[[@LINE]]:8: error: invalid operand for instruction +fadd.d t0, t1, t2 # CHECK: :[[@LINE]]:1: error: instruction requires the following: 'Zdinx' (Double in Integer){{$}} diff --git a/llvm/test/MC/RISCV/rv64zdinx-valid.s b/llvm/test/MC/RISCV/rv64zdinx-valid.s --- a/llvm/test/MC/RISCV/rv64zdinx-valid.s +++ b/llvm/test/MC/RISCV/rv64zdinx-valid.s @@ -9,35 +9,35 @@ # CHECK-ASM-AND-OBJ: fcvt.l.d a0, t0, dyn # CHECK-ASM: encoding: [0x53,0xf5,0x22,0xc2] -# CHECK-RV32: :[[#@LINE+1]]:14: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.l.d a0, t0, dyn # CHECK-ASM-AND-OBJ: fcvt.lu.d a1, t1, dyn # CHECK-ASM: encoding: [0xd3,0x75,0x33,0xc2] -# CHECK-RV32: :[[#@LINE+1]]:15: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.lu.d a1, t1, dyn # CHECK-ASM-AND-OBJ: fcvt.d.l t3, a3, dyn # CHECK-ASM: encoding: [0x53,0xfe,0x26,0xd2] -# CHECK-RV32: :[[#@LINE+1]]:10: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.d.l t3, a3, dyn # CHECK-ASM-AND-OBJ: fcvt.d.lu t4, a4, dyn # CHECK-ASM: encoding: [0xd3,0x7e,0x37,0xd2] -# CHECK-RV32: :[[#@LINE+1]]:11: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.d.lu t4, a4, dyn # Rounding modes # CHECK-ASM-AND-OBJ: fcvt.d.l t3, a3, rne # CHECK-ASM: encoding: [0x53,0x8e,0x26,0xd2] -# CHECK-RV32: :[[#@LINE+1]]:10: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.d.l t3, a3, rne # CHECK-ASM-AND-OBJ: fcvt.d.lu t4, a4, rtz # CHECK-ASM: encoding: [0xd3,0x1e,0x37,0xd2] -# CHECK-RV32: :[[#@LINE+1]]:11: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.d.lu t4, a4, rtz # CHECK-ASM-AND-OBJ: fcvt.l.d a0, t0, rdn # CHECK-ASM: encoding: [0x53,0xa5,0x22,0xc2] -# CHECK-RV32: :[[#@LINE+1]]:14: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.l.d a0, t0, rdn # CHECK-ASM-AND-OBJ: fcvt.lu.d a1, t1, rup # CHECK-ASM: encoding: [0xd3,0x35,0x33,0xc2] -# CHECK-RV32: :[[#@LINE+1]]:15: error: invalid operand for instruction +# CHECK-RV32: :[[#@LINE+1]]:1: error: instruction requires the following: RV64I Base Instruction Set fcvt.lu.d a1, t1, rup