[RISCV] Move the even register check for rv32zdinx later in the matching process.
authorCraig Topper <craig.topper@sifive.com>
Wed, 1 Feb 2023 18:55:35 +0000 (10:55 -0800)
committerCraig Topper <craig.topper@sifive.com>
Wed, 1 Feb 2023 19:15:06 +0000 (11:15 -0800)
And remove the IsRV64 checks for isGPRAsFPR and isGPRPF64AsFPR.

Overall I think this results in a better diagnostic experience. We
now do a better job of matching Zdinx instructions even if the registers
aren't correct and report an error for missing features like RV64.

Unfortunately, this makes it difficult to recover the error location
for the invalid odd register when we do report it. But to make up
for it, I gave a more specific error message.

It doesn't look like binutils gives any warning or error for odd registers.

Reviewed By: asb

Differential Revision: https://reviews.llvm.org/D142997

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
llvm/test/MC/RISCV/rv32zdinx-invalid.s
llvm/test/MC/RISCV/rv32zfinx-invalid.s
llvm/test/MC/RISCV/rv64zdinx-valid.s

index b43cbe4..c05de22 100644 (file)
@@ -78,6 +78,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
 
   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 @@ class RISCVAsmParser : public MCTargetAsmParser {
 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 RISCVOperand final : public MCParsedAsmOperand {
 
   struct RegOp {
     MCRegister RegNum;
-    bool IsRV64;
     bool IsGPRAsFPR;
   };
 
@@ -373,12 +374,9 @@ public:
 
   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 @@ public:
     return Op;
   }
 
-  static std::unique_ptr<RISCVOperand> createReg(unsigned RegNo, SMLoc S,
-                                                 SMLoc E, bool IsRV64,
-                                                 bool IsGPRAsFPR = false) {
+  static std::unique_ptr<RISCVOperand>
+  createReg(unsigned RegNo, SMLoc S, SMLoc E, bool IsGPRAsFPR = false) {
     auto Op = std::make_unique<RISCVOperand>(KindTy::Register);
     Op->Reg.RegNum = RegNo;
-    Op->Reg.IsRV64 = IsRV64;
     Op->Reg.IsGPRAsFPR = IsGPRAsFPR;
     Op->StartLoc = S;
     Op->EndLoc = E;
@@ -1037,6 +1033,23 @@ unsigned RISCVAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
   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 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   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 @@ OperandMatchResultTy RISCVAsmParser::parseRegister(OperandVector &Operands,
     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 @@ OperandMatchResultTy RISCVAsmParser::parseMaskReg(OperandVector &Operands) {
   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 @@ OperandMatchResultTy RISCVAsmParser::parseGPRAsFPR(OperandVector &Operands) {
   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 @@ bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst,
 
 std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultMaskRegOp() const {
   return RISCVOperand::createReg(RISCV::NoRegister, llvm::SMLoc(),
-                                 llvm::SMLoc(), isRV64());
+                                 llvm::SMLoc());
 }
 
 std::unique_ptr<RISCVOperand> RISCVAsmParser::defaultFRMArgOp() const {
index 7af576d..879157a 100644 (file)
@@ -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){{$}}
index 7b1eb1e..b4675f8 100644 (file)
@@ -22,4 +22,4 @@ fmsub.s x14, x15, x16, x17, 0 # CHECK: :[[@LINE]]:29: error: operand must be a v
 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){{$}}
index 1e6e430..fa603f3 100644 (file)
@@ -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