[llvm] [RISCV] Make RISCVInstrInfo::verifyInstruction stricter for immediate-only operands (PR #170736)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 13:19:52 PST 2025


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/170736

>From fd397255ecef4da3c8452b70f5560dcd045aaf0b Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Thu, 4 Dec 2025 11:41:31 -0800
Subject: [PATCH] [RISCV] Make RISCVInstrInfo::verifyInstruction stricter for
 immediate-only operands

Most of the immediate operands can only be an immediate, but we were
allowing any non-register operand.

Split the immediate-only from the immediate or non-register operands.
The non-register cases could be made even stricter, but I'll leave that
as a TODO.
---
 .../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h |  12 +-
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp      | 392 ++++++++++--------
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       |   3 +
 3 files changed, 221 insertions(+), 186 deletions(-)

diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index d8dcd963050b5..dbf5cfe6ef463 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -393,7 +393,6 @@ enum OperandType : unsigned {
   OPERAND_UIMM14_LSB00,
   OPERAND_UIMM16,
   OPERAND_UIMM16_NONZERO,
-  OPERAND_UIMM20,
   OPERAND_UIMMLOG2XLEN,
   OPERAND_UIMMLOG2XLEN_NONZERO,
   OPERAND_UIMM32,
@@ -412,13 +411,11 @@ enum OperandType : unsigned {
   OPERAND_SIMM10_LSB0000_NONZERO,
   OPERAND_SIMM10_UNSIGNED,
   OPERAND_SIMM11,
-  OPERAND_SIMM12,
   OPERAND_SIMM12_LSB00000,
   OPERAND_SIMM16,
   OPERAND_SIMM16_NONZERO,
   OPERAND_SIMM20_LI,
   OPERAND_SIMM26,
-  OPERAND_BARE_SIMM32,
   OPERAND_CLUI_IMM,
   OPERAND_VTYPEI10,
   OPERAND_VTYPEI11,
@@ -447,6 +444,15 @@ enum OperandType : unsigned {
   // Vtype operand for XSfmm extension.
   OPERAND_XSFMM_VTYPE,
   OPERAND_LAST_RISCV_IMM = OPERAND_XSFMM_VTYPE,
+
+  OPERAND_UIMM20_LUI,
+  OPERAND_UIMM20_AUIPC,
+
+  // Simm12 or constant pool, global, basicblock, etc.
+  OPERAND_SIMM12_LO,
+
+  OPERAND_BARE_SIMM32,
+
   // Operand is either a register or uimm5, this is used by V extension pseudo
   // instructions to represent a value that be passed as AVL to either vsetvli
   // or vsetivli.
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 2bd63e75d060b..ee327f3d61a62 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2850,22 +2850,21 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
   MCInstrDesc const &Desc = MI.getDesc();
 
   for (const auto &[Index, Operand] : enumerate(Desc.operands())) {
+    const MachineOperand &MO = MI.getOperand(Index);
     unsigned OpType = Operand.OperandType;
     if (OpType >= RISCVOp::OPERAND_FIRST_RISCV_IMM &&
         OpType <= RISCVOp::OPERAND_LAST_RISCV_IMM) {
-      const MachineOperand &MO = MI.getOperand(Index);
-      if (MO.isReg()) {
-        ErrInfo = "Expected a non-register operand.";
+      if (!MO.isImm()) {
+        ErrInfo = "Expected an immediate operand.";
         return false;
       }
-      if (MO.isImm()) {
-        int64_t Imm = MO.getImm();
-        bool Ok;
-        switch (OpType) {
-        default:
-          llvm_unreachable("Unexpected operand type");
+      int64_t Imm = MO.getImm();
+      bool Ok;
+      switch (OpType) {
+      default:
+        llvm_unreachable("Unexpected operand type");
 
-          // clang-format off
+        // clang-format off
 #define CASE_OPERAND_UIMM(NUM)                                                 \
   case RISCVOp::OPERAND_UIMM##NUM:                                             \
     Ok = isUInt<NUM>(Imm);                                                     \
@@ -2874,181 +2873,208 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
   case RISCVOp::OPERAND_SIMM##NUM:                                             \
     Ok = isInt<NUM>(Imm);                                                      \
     break;
-        CASE_OPERAND_UIMM(1)
-        CASE_OPERAND_UIMM(2)
-        CASE_OPERAND_UIMM(3)
-        CASE_OPERAND_UIMM(4)
-        CASE_OPERAND_UIMM(5)
-        CASE_OPERAND_UIMM(6)
-        CASE_OPERAND_UIMM(7)
-        CASE_OPERAND_UIMM(8)
-        CASE_OPERAND_UIMM(9)
-        CASE_OPERAND_UIMM(10)
-        CASE_OPERAND_UIMM(12)
-        CASE_OPERAND_UIMM(16)
-        CASE_OPERAND_UIMM(20)
-        CASE_OPERAND_UIMM(32)
-        CASE_OPERAND_UIMM(48)
-        CASE_OPERAND_UIMM(64)
-          // clang-format on
-        case RISCVOp::OPERAND_UIMM2_LSB0:
-          Ok = isShiftedUInt<1, 1>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM5_LSB0:
-          Ok = isShiftedUInt<4, 1>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM5_NONZERO:
-          Ok = isUInt<5>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_UIMM5_GT3:
-          Ok = isUInt<5>(Imm) && (Imm > 3);
-          break;
-        case RISCVOp::OPERAND_UIMM5_PLUS1:
-          Ok = Imm >= 1 && Imm <= 32;
-          break;
-        case RISCVOp::OPERAND_UIMM6_LSB0:
-          Ok = isShiftedUInt<5, 1>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM7_LSB00:
-          Ok = isShiftedUInt<5, 2>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM7_LSB000:
-          Ok = isShiftedUInt<4, 3>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM8_LSB00:
-          Ok = isShiftedUInt<6, 2>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM8_LSB000:
-          Ok = isShiftedUInt<5, 3>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMM8_GE32:
-          Ok = isUInt<8>(Imm) && Imm >= 32;
-          break;
-        case RISCVOp::OPERAND_UIMM9_LSB000:
-          Ok = isShiftedUInt<6, 3>(Imm);
-          break;
-        case RISCVOp::OPERAND_SIMM8_UNSIGNED:
-          Ok = isInt<8>(Imm);
-          break;
-        case RISCVOp::OPERAND_SIMM10_LSB0000_NONZERO:
-          Ok = isShiftedInt<6, 4>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_UIMM10_LSB00_NONZERO:
-          Ok = isShiftedUInt<8, 2>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_UIMM16_NONZERO:
-          Ok = isUInt<16>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_THREE:
-          Ok = Imm == 3;
-          break;
-        case RISCVOp::OPERAND_FOUR:
-          Ok = Imm == 4;
-          break;
-        case RISCVOp::OPERAND_IMM5_ZIBI:
-          Ok = (isUInt<5>(Imm) && Imm != 0) || Imm == -1;
-          break;
-          // clang-format off
-        CASE_OPERAND_SIMM(5)
-        CASE_OPERAND_SIMM(6)
-        CASE_OPERAND_SIMM(10)
-        CASE_OPERAND_SIMM(11)
-        CASE_OPERAND_SIMM(12)
-        CASE_OPERAND_SIMM(26)
+      CASE_OPERAND_UIMM(1)
+      CASE_OPERAND_UIMM(2)
+      CASE_OPERAND_UIMM(3)
+      CASE_OPERAND_UIMM(4)
+      CASE_OPERAND_UIMM(5)
+      CASE_OPERAND_UIMM(6)
+      CASE_OPERAND_UIMM(7)
+      CASE_OPERAND_UIMM(8)
+      CASE_OPERAND_UIMM(9)
+      CASE_OPERAND_UIMM(10)
+      CASE_OPERAND_UIMM(12)
+      CASE_OPERAND_UIMM(16)
+      CASE_OPERAND_UIMM(32)
+      CASE_OPERAND_UIMM(48)
+      CASE_OPERAND_UIMM(64)
         // clang-format on
-        case RISCVOp::OPERAND_SIMM5_PLUS1:
-          Ok = Imm >= -15 && Imm <= 16;
-          break;
-        case RISCVOp::OPERAND_SIMM5_NONZERO:
-          Ok = isInt<5>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_SIMM6_NONZERO:
-          Ok = Imm != 0 && isInt<6>(Imm);
-          break;
-        case RISCVOp::OPERAND_VTYPEI10:
-          Ok = isUInt<10>(Imm);
-          break;
-        case RISCVOp::OPERAND_VTYPEI11:
-          Ok = isUInt<11>(Imm);
-          break;
-        case RISCVOp::OPERAND_SIMM12_LSB00000:
-          Ok = isShiftedInt<7, 5>(Imm);
-          break;
-        case RISCVOp::OPERAND_SIMM16_NONZERO:
-          Ok = isInt<16>(Imm) && (Imm != 0);
-          break;
-        case RISCVOp::OPERAND_SIMM20_LI:
-          Ok = isInt<20>(Imm);
-          break;
-        case RISCVOp::OPERAND_BARE_SIMM32:
-          Ok = isInt<32>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMMLOG2XLEN:
-          Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
-          break;
-        case RISCVOp::OPERAND_UIMMLOG2XLEN_NONZERO:
-          Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
-          Ok = Ok && Imm != 0;
-          break;
-        case RISCVOp::OPERAND_CLUI_IMM:
-          Ok = (isUInt<5>(Imm) && Imm != 0) ||
-               (Imm >= 0xfffe0 && Imm <= 0xfffff);
-          break;
-        case RISCVOp::OPERAND_RVKRNUM:
-          Ok = Imm >= 0 && Imm <= 10;
-          break;
-        case RISCVOp::OPERAND_RVKRNUM_0_7:
-          Ok = Imm >= 0 && Imm <= 7;
-          break;
-        case RISCVOp::OPERAND_RVKRNUM_1_10:
-          Ok = Imm >= 1 && Imm <= 10;
-          break;
-        case RISCVOp::OPERAND_RVKRNUM_2_14:
-          Ok = Imm >= 2 && Imm <= 14;
-          break;
-        case RISCVOp::OPERAND_RLIST:
-          Ok = Imm >= RISCVZC::RA && Imm <= RISCVZC::RA_S0_S11;
-          break;
-        case RISCVOp::OPERAND_RLIST_S0:
-          Ok = Imm >= RISCVZC::RA_S0 && Imm <= RISCVZC::RA_S0_S11;
-          break;
-        case RISCVOp::OPERAND_STACKADJ:
-          Ok = Imm >= 0 && Imm <= 48 && Imm % 16 == 0;
-          break;
-        case RISCVOp::OPERAND_FRMARG:
+      case RISCVOp::OPERAND_UIMM2_LSB0:
+        Ok = isShiftedUInt<1, 1>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM5_LSB0:
+        Ok = isShiftedUInt<4, 1>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM5_NONZERO:
+        Ok = isUInt<5>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_UIMM5_GT3:
+        Ok = isUInt<5>(Imm) && (Imm > 3);
+        break;
+      case RISCVOp::OPERAND_UIMM5_PLUS1:
+        Ok = Imm >= 1 && Imm <= 32;
+        break;
+      case RISCVOp::OPERAND_UIMM6_LSB0:
+        Ok = isShiftedUInt<5, 1>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM7_LSB00:
+        Ok = isShiftedUInt<5, 2>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM7_LSB000:
+        Ok = isShiftedUInt<4, 3>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM8_LSB00:
+        Ok = isShiftedUInt<6, 2>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM8_LSB000:
+        Ok = isShiftedUInt<5, 3>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMM8_GE32:
+        Ok = isUInt<8>(Imm) && Imm >= 32;
+        break;
+      case RISCVOp::OPERAND_UIMM9_LSB000:
+        Ok = isShiftedUInt<6, 3>(Imm);
+        break;
+      case RISCVOp::OPERAND_SIMM8_UNSIGNED:
+        Ok = isInt<8>(Imm);
+        break;
+      case RISCVOp::OPERAND_SIMM10_LSB0000_NONZERO:
+        Ok = isShiftedInt<6, 4>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_UIMM10_LSB00_NONZERO:
+        Ok = isShiftedUInt<8, 2>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_UIMM16_NONZERO:
+        Ok = isUInt<16>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_THREE:
+        Ok = Imm == 3;
+        break;
+      case RISCVOp::OPERAND_FOUR:
+        Ok = Imm == 4;
+        break;
+      case RISCVOp::OPERAND_IMM5_ZIBI:
+        Ok = (isUInt<5>(Imm) && Imm != 0) || Imm == -1;
+        break;
+        // clang-format off
+      CASE_OPERAND_SIMM(5)
+      CASE_OPERAND_SIMM(6)
+      CASE_OPERAND_SIMM(10)
+      CASE_OPERAND_SIMM(11)
+      CASE_OPERAND_SIMM(26)
+      // clang-format on
+      case RISCVOp::OPERAND_SIMM5_PLUS1:
+        Ok = Imm >= -15 && Imm <= 16;
+        break;
+      case RISCVOp::OPERAND_SIMM5_NONZERO:
+        Ok = isInt<5>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_SIMM6_NONZERO:
+        Ok = Imm != 0 && isInt<6>(Imm);
+        break;
+      case RISCVOp::OPERAND_VTYPEI10:
+        Ok = isUInt<10>(Imm);
+        break;
+      case RISCVOp::OPERAND_VTYPEI11:
+        Ok = isUInt<11>(Imm);
+        break;
+      case RISCVOp::OPERAND_SIMM12_LSB00000:
+        Ok = isShiftedInt<7, 5>(Imm);
+        break;
+      case RISCVOp::OPERAND_SIMM16_NONZERO:
+        Ok = isInt<16>(Imm) && (Imm != 0);
+        break;
+      case RISCVOp::OPERAND_SIMM20_LI:
+        Ok = isInt<20>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMMLOG2XLEN:
+        Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
+        break;
+      case RISCVOp::OPERAND_UIMMLOG2XLEN_NONZERO:
+        Ok = STI.is64Bit() ? isUInt<6>(Imm) : isUInt<5>(Imm);
+        Ok = Ok && Imm != 0;
+        break;
+      case RISCVOp::OPERAND_CLUI_IMM:
+        Ok = (isUInt<5>(Imm) && Imm != 0) || (Imm >= 0xfffe0 && Imm <= 0xfffff);
+        break;
+      case RISCVOp::OPERAND_RVKRNUM:
+        Ok = Imm >= 0 && Imm <= 10;
+        break;
+      case RISCVOp::OPERAND_RVKRNUM_0_7:
+        Ok = Imm >= 0 && Imm <= 7;
+        break;
+      case RISCVOp::OPERAND_RVKRNUM_1_10:
+        Ok = Imm >= 1 && Imm <= 10;
+        break;
+      case RISCVOp::OPERAND_RVKRNUM_2_14:
+        Ok = Imm >= 2 && Imm <= 14;
+        break;
+      case RISCVOp::OPERAND_RLIST:
+        Ok = Imm >= RISCVZC::RA && Imm <= RISCVZC::RA_S0_S11;
+        break;
+      case RISCVOp::OPERAND_RLIST_S0:
+        Ok = Imm >= RISCVZC::RA_S0 && Imm <= RISCVZC::RA_S0_S11;
+        break;
+      case RISCVOp::OPERAND_STACKADJ:
+        Ok = Imm >= 0 && Imm <= 48 && Imm % 16 == 0;
+        break;
+      case RISCVOp::OPERAND_FRMARG:
+        Ok = RISCVFPRndMode::isValidRoundingMode(Imm);
+        break;
+      case RISCVOp::OPERAND_RTZARG:
+        Ok = Imm == RISCVFPRndMode::RTZ;
+        break;
+      case RISCVOp::OPERAND_COND_CODE:
+        Ok = Imm >= 0 && Imm < RISCVCC::COND_INVALID;
+        break;
+      case RISCVOp::OPERAND_VEC_POLICY:
+        Ok = (Imm & (RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC)) ==
+             Imm;
+        break;
+      case RISCVOp::OPERAND_SEW:
+        Ok = (isUInt<5>(Imm) && RISCVVType::isValidSEW(1 << Imm));
+        break;
+      case RISCVOp::OPERAND_SEW_MASK:
+        Ok = Imm == 0;
+        break;
+      case RISCVOp::OPERAND_VEC_RM:
+        assert(RISCVII::hasRoundModeOp(Desc.TSFlags));
+        if (RISCVII::usesVXRM(Desc.TSFlags))
+          Ok = isUInt<2>(Imm);
+        else
           Ok = RISCVFPRndMode::isValidRoundingMode(Imm);
-          break;
-        case RISCVOp::OPERAND_RTZARG:
-          Ok = Imm == RISCVFPRndMode::RTZ;
-          break;
-        case RISCVOp::OPERAND_COND_CODE:
-          Ok = Imm >= 0 && Imm < RISCVCC::COND_INVALID;
-          break;
-        case RISCVOp::OPERAND_VEC_POLICY:
-          Ok = (Imm &
-                (RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC)) == Imm;
-          break;
-        case RISCVOp::OPERAND_SEW:
-          Ok = (isUInt<5>(Imm) && RISCVVType::isValidSEW(1 << Imm));
-          break;
-        case RISCVOp::OPERAND_SEW_MASK:
-          Ok = Imm == 0;
-          break;
-        case RISCVOp::OPERAND_VEC_RM:
-          assert(RISCVII::hasRoundModeOp(Desc.TSFlags));
-          if (RISCVII::usesVXRM(Desc.TSFlags))
-            Ok = isUInt<2>(Imm);
-          else
-            Ok = RISCVFPRndMode::isValidRoundingMode(Imm);
-          break;
-        case RISCVOp::OPERAND_XSFMM_VTYPE:
-          Ok = RISCVVType::isValidXSfmmVType(Imm);
-          break;
-        }
-        if (!Ok) {
-          ErrInfo = "Invalid immediate";
-          return false;
-        }
+        break;
+      case RISCVOp::OPERAND_XSFMM_VTYPE:
+        Ok = RISCVVType::isValidXSfmmVType(Imm);
+        break;
+      }
+      if (!Ok) {
+        ErrInfo = "Invalid immediate";
+        return false;
+      }
+    } else if (OpType == RISCVOp::OPERAND_SIMM12_LO) {
+      // TODO: We could be stricter about what non-register operands are
+      // allowed.
+      if (MO.isReg()) {
+        ErrInfo = "Expected a non-register operand.";
+        return false;
+      }
+      if (MO.isImm() && !isInt<12>(MO.getImm())) {
+        ErrInfo = "Invalid immediate";
+        return false;
+      }
+    } else if (OpType == RISCVOp::OPERAND_UIMM20_LUI ||
+               OpType == RISCVOp::OPERAND_UIMM20_AUIPC) {
+      // TODO: We could be stricter about what non-register operands are
+      // allowed.
+      if (MO.isReg()) {
+        ErrInfo = "Expected a non-register operand.";
+        return false;
+      }
+      if (MO.isImm() && !isUInt<20>(MO.getImm())) {
+        ErrInfo = "Invalid immediate";
+        return false;
+      }
+    } else if (OpType == RISCVOp::OPERAND_BARE_SIMM32) {
+      // TODO: We could be stricter about what non-register operands are
+      // allowed.
+      if (MO.isReg()) {
+        ErrInfo = "Expected a non-register operand.";
+        return false;
+      }
+      if (MO.isImm() && !isInt<32>(MO.getImm())) {
+        ErrInfo = "Invalid immediate";
+        return false;
       }
     }
   }
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index a27c46ebf3a99..9a4eb12ca0eb0 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -349,6 +349,7 @@ def simm12_lo : RISCVSImmLeafOp<12> {
       return isInt<12>(Imm);
     return MCOp.isBareSymbolRef();
   }];
+  let OperandType = "OPERAND_SIMM12_LO";
 }
 
 // A 12-bit signed immediate which cannot fit in 6-bit signed immediate,
@@ -394,9 +395,11 @@ class UImm20OperandMaybeSym : RISCVUImmOp<20> {
 
 def uimm20_lui : UImm20OperandMaybeSym {
   let ParserMatchClass = UImmAsmOperand<20, "LUI">;
+  let OperandType = "OPERAND_UIMM20_LUI";
 }
 def uimm20_auipc : UImm20OperandMaybeSym {
   let ParserMatchClass = UImmAsmOperand<20, "AUIPC">;
+  let OperandType = "OPERAND_UIMM20_AUIPC";
 }
 
 def uimm20 : RISCVUImmOp<20>;



More information about the llvm-commits mailing list