[clang] [CIR] Use declarative TableGen constraints for overflow flag verification (PR #195476)
Henrich Lauko via cfe-commits
cfe-commits at lists.llvm.org
Sat May 2 11:50:51 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/195476
>From 34197a96d7249993ac87473badd557c7688d6e19 Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Sat, 2 May 2026 20:33:36 +0200
Subject: [PATCH] [CIR] Use declarative TableGen constraints for overflow flag
verification
Replace hand-written C++ verifiers with PredOpTrait-based constraints
(FlagRequiresIntType, HasAtMostOneOfAttrs). Introduce CIR_SaturatableBinaryOp
base class and use append/prepend ODS directives to compose arguments, format,
and traits across the op hierarchy. Fix HasAtMostOneOfAttrsPred to use
accessor methods instead of dollar-sign references. Add Commutative trait
to AddOp and MulOp.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 85 ++++++++++++--------
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 39 ---------
2 files changed, 50 insertions(+), 74 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 97d623ba5e6d9..7a450d3267f7c 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -114,12 +114,20 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
//===----------------------------------------------------------------------===//
class HasAtMostOneOfAttrsPred<list<string> names> :
- CPred<!foldl("0", names, acc, name, acc # " + (" # name # " ? 1 : 0)")
+ CPred<!foldl("0", names, acc, name,
+ acc # " + (this->get" # snakeCaseToCamelCase<name>.ret # "() ? 1 : 0)")
# " <= 1">;
class HasAtMostOneOfAttrs<list<string> names> : PredOpTrait<
"has only one of the optional attributes: " # !interleave(names, ", "),
- HasAtMostOneOfAttrsPred<!foreach(name, names, "$" # name)>
+ HasAtMostOneOfAttrsPred<names>
+>;
+
+// Requires that a boolean flag attribute implies integer result type.
+class FlagRequiresIntType<string flag> : PredOpTrait<
+ "only operations on integer values may have the " # flag # " flag",
+ Or<[Neg<CPred<"this->get" # snakeCaseToCamelCase<flag>.ret # "()">>,
+ CPred<"::mlir::isa<::cir::IntType>(this->getResult().getType())">]>
>;
//===----------------------------------------------------------------------===//
@@ -1819,11 +1827,12 @@ class CIR_UnaryOpWithOverflowFlag<string mnemonic, Type type,
list<Trait> traits = []>
: CIR_UnaryOp<mnemonic, type, traits>
{
- let arguments = (ins type:$input, UnitProp:$no_signed_wrap);
+ let append traits = [NSWFlagIntOnly];
- let assemblyFormat = [{
+ let append arguments = (ins UnitProp:$no_signed_wrap);
+
+ let prepend assemblyFormat = [{
(`nsw` $no_signed_wrap^)?
- $input `:` type($input) attr-dict
}];
}
@@ -2366,34 +2375,52 @@ class CIR_BinaryOp<string mnemonic, Type type, list<Trait> traits = []>
}];
}
-// Base class for binary ops that support integer overflow flags (nsw/nuw)
-// and saturated arithmetic.
-class CIR_BinaryOpWithOverflowFlags<string mnemonic, Type type,
- list<Trait> traits = []>
- : CIR_BinaryOp<mnemonic, type, !listconcat([Pure], traits)>
+def NSWFlagIntOnly : FlagRequiresIntType<"no_signed_wrap">;
+def NUWFlagIntOnly : FlagRequiresIntType<"no_unsigned_wrap">;
+
+// Base class for binary ops that support integer overflow flags (nsw/nuw).
+class CIR_BinaryOpWithOverflowFlags<string mnemonic, Type type>
+ : CIR_BinaryOp<mnemonic, type>
{
- let arguments = (ins
- type:$lhs, type:$rhs,
+ let append traits = [Pure, NSWFlagIntOnly, NUWFlagIntOnly];
+
+ let append arguments = (ins
UnitProp:$no_signed_wrap,
- UnitProp:$no_unsigned_wrap,
- UnitProp:$saturated
+ UnitProp:$no_unsigned_wrap
);
- let assemblyFormat = [{
+ let prepend assemblyFormat = [{
(`nsw` $no_signed_wrap^)?
(`nuw` $no_unsigned_wrap^)?
- (`sat` $saturated^)?
- $lhs `,` $rhs `:` type($lhs) attr-dict
}];
+}
- let hasVerifier = 1;
+def SatFlagIntOnly : FlagRequiresIntType<"saturated">;
+
+// Extends CIR_BinaryOpWithOverflowFlags with saturated arithmetic support.
+class CIR_SaturatableBinaryOp<string mnemonic, Type type>
+ : CIR_BinaryOpWithOverflowFlags<mnemonic, type>
+{
+ let append traits = [
+ SatFlagIntOnly,
+ HasAtMostOneOfAttrs<["saturated", "no_signed_wrap"]>,
+ HasAtMostOneOfAttrs<["saturated", "no_unsigned_wrap"]>
+ ];
+
+ let append arguments = (ins UnitProp:$saturated);
+
+ let prepend assemblyFormat = [{
+ (`sat` $saturated^)?
+ }];
}
//===----------------------------------------------------------------------===//
// AddOp
//===----------------------------------------------------------------------===//
-def CIR_AddOp : CIR_BinaryOpWithOverflowFlags<"add", CIR_AnyArithType> {
+def CIR_AddOp : CIR_SaturatableBinaryOp<"add", CIR_AnyArithType> {
+ let append traits = [Commutative];
+
let summary = "Integer or floating-point addition";
let description = [{
The `cir.add` operation performs addition on integer or floating-point
@@ -2421,7 +2448,7 @@ def CIR_AddOp : CIR_BinaryOpWithOverflowFlags<"add", CIR_AnyArithType> {
// SubOp
//===----------------------------------------------------------------------===//
-def CIR_SubOp : CIR_BinaryOpWithOverflowFlags<"sub", CIR_AnyArithType> {
+def CIR_SubOp : CIR_SaturatableBinaryOp<"sub", CIR_AnyArithType> {
let summary = "Integer or floating-point subtraction";
let description = [{
The `cir.sub` operation performs subtraction on integer or floating-point
@@ -2448,7 +2475,9 @@ def CIR_SubOp : CIR_BinaryOpWithOverflowFlags<"sub", CIR_AnyArithType> {
// MulOp
//===----------------------------------------------------------------------===//
-def CIR_MulOp : CIR_BinaryOp<"mul", CIR_AnyArithType> {
+def CIR_MulOp : CIR_BinaryOpWithOverflowFlags<"mul", CIR_AnyArithType> {
+ let append traits = [Commutative];
+
let summary = "Integer or floating-point multiplication";
let description = [{
The `cir.mul` operation performs multiplication on integer or floating-point
@@ -2467,20 +2496,6 @@ def CIR_MulOp : CIR_BinaryOp<"mul", CIR_AnyArithType> {
%3 = cir.mul %a, %b : !cir.float
```
}];
-
- let arguments = (ins
- CIR_AnyArithType:$lhs, CIR_AnyArithType:$rhs,
- UnitProp:$no_signed_wrap,
- UnitProp:$no_unsigned_wrap
- );
-
- let assemblyFormat = [{
- (`nsw` $no_signed_wrap^)?
- (`nuw` $no_unsigned_wrap^)?
- $lhs `,` $rhs `:` type($lhs) attr-dict
- }];
-
- let hasVerifier = 1;
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7386819d8fce9..05aff42f7c148 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2708,45 +2708,6 @@ mlir::LogicalResult cir::FuncOp::verify() {
return success();
}
-//===----------------------------------------------------------------------===//
-// AddOp / SubOp / MulOp
-//===----------------------------------------------------------------------===//
-
-static LogicalResult verifyBinaryOverflowOp(mlir::Operation *op,
- bool noSignedWrap,
- bool noUnsignedWrap, bool saturated,
- bool hasSat) {
- bool noWrap = noSignedWrap || noUnsignedWrap;
- if (!isa<cir::IntType>(op->getResultTypes()[0]) && noWrap)
- return op->emitError()
- << "only operations on integer values may have nsw/nuw flags";
- if (hasSat && saturated && !isa<cir::IntType>(op->getResultTypes()[0]))
- return op->emitError()
- << "only operations on integer values may have sat flag";
- if (hasSat && noWrap && saturated)
- return op->emitError()
- << "the nsw/nuw flags and the saturated flag are mutually exclusive";
- return mlir::success();
-}
-
-LogicalResult cir::AddOp::verify() {
- return verifyBinaryOverflowOp(getOperation(), getNoSignedWrap(),
- getNoUnsignedWrap(), getSaturated(),
- /*hasSat=*/true);
-}
-
-LogicalResult cir::SubOp::verify() {
- return verifyBinaryOverflowOp(getOperation(), getNoSignedWrap(),
- getNoUnsignedWrap(), getSaturated(),
- /*hasSat=*/true);
-}
-
-LogicalResult cir::MulOp::verify() {
- return verifyBinaryOverflowOp(getOperation(), getNoSignedWrap(),
- getNoUnsignedWrap(), /*saturated=*/false,
- /*hasSat=*/false);
-}
-
//===----------------------------------------------------------------------===//
// TernaryOp
//===----------------------------------------------------------------------===//
More information about the cfe-commits
mailing list