================
@@ -2119,76 +2119,261 @@ def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow",
[Pure, SameTypeOperands]> {
//===----------------------------------------------------------------------===//
-// BinOp
-//===----------------------------------------------------------------------===//
-
-// FIXME: represent Commutative, Idempotent traits for appropriate binops
-def CIR_BinOpKind : CIR_I32EnumAttr<
- "BinOpKind", "binary operation (arith and logic) kind", [
- I32EnumAttrCase<"Mul", 0, "mul">,
- I32EnumAttrCase<"Div", 1, "div">,
- I32EnumAttrCase<"Rem", 2, "rem">,
- I32EnumAttrCase<"Add", 3, "add">,
- I32EnumAttrCase<"Sub", 4, "sub">,
- I32EnumAttrCase<"And", 5, "and">,
- I32EnumAttrCase<"Xor", 6, "xor">,
- I32EnumAttrCase<"Or", 7, "or">,
- I32EnumAttrCase<"Max", 8, "max">
-]>;
+// Binary Arithmetic and Logic Operations
+//===----------------------------------------------------------------------===//
-def CIR_BinOp : CIR_Op<"binop", [
- Pure, SameTypeOperands, SameOperandsAndResultType
-]> {
- let summary = "Binary operations (arith and logic)";
+// Base class for all CIR binary arithmetic/logic operations.
+// `type` constrains the lhs/rhs/result type.
+class CIR_BinaryOp<string mnemonic, Type type, list<Trait> traits = []>
+ : CIR_Op<mnemonic, !listconcat([
+ NoMemoryEffect, SameOperandsAndResultType,
+ DeclareOpInterfaceMethods<CIR_BinaryOpInterface>
+ ], traits)>
+{
+ let arguments = (ins
+ type:$lhs,
+ type:$rhs
+ );
+
+ let results = (outs type:$result);
+
+ let assemblyFormat = [{
+ $lhs `,` $rhs `:` type($lhs) attr-dict
+ }];
+}
+
+// Base class for binary ops that support integer overflow flags (nsw/nuw)
+// and saturated arithmetic.
+class CIR_BinaryOverflowOp<string mnemonic, Type type, list<Trait> traits = []>
+ : CIR_BinaryOp<mnemonic, type, !listconcat([Pure], traits)>
+{
+ let arguments = (ins
+ type:$lhs, type:$rhs,
+ UnitProp:$no_signed_wrap,
+ UnitProp:$no_unsigned_wrap,
+ UnitProp:$saturated
+ );
+
+ let assemblyFormat = [{
+ (`nsw` $no_signed_wrap^)?
+ (`nuw` $no_unsigned_wrap^)?
+ (`sat` $saturated^)?
+ $lhs `,` $rhs `:` type($lhs) attr-dict
+ }];
+
+ let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// AddOp
+//===----------------------------------------------------------------------===//
+
+def CIR_AddOp : CIR_BinaryOverflowOp<"add", CIR_AnyArithType> {
+ let summary = "Integer or floating-point addition";
let description = [{
- cir.binop performs the binary operation according to
- the specified opcode kind: [mul, div, rem, add, sub,
- and, xor, or, max].
+ The `cir.add` operation performs addition on integer or floating-point
+ operands. Both operands and the result must have the same type.
- It requires two input operands and has one result, all types
- should be the same.
+ For integer types, the optional `nsw` (no signed wrap) and `nuw` (no
+ unsigned wrap) unit attributes indicate that the result is poison if signed
+ or unsigned overflow occurs, respectively. The optional `sat` (saturated)
+ attribute clamps the result to the type's representable range instead of
+ wrapping. The `nsw`/`nuw` flags and `sat` are mutually exclusive.
+
+ Example:
- If the `nsw` (no signed wrap) or `nuw` (no unsigned wrap) attributes are
- present, the result is poison if signed or unsigned overflow occurs
- (respectively).
+ ```mlir
+ %0 = cir.add %a, %b : !s32i
+ %1 = cir.add nsw %a, %b : !s32i
+ %2 = cir.add nuw %a, %b : !u32i
+ %3 = cir.add sat %a, %b : !s32i
+ %4 = cir.add %a, %b : !cir.float
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// SubOp
+//===----------------------------------------------------------------------===//
+
+def CIR_SubOp : CIR_BinaryOverflowOp<"sub", CIR_AnyArithType> {
+ let summary = "Integer or floating-point subtraction";
+ let description = [{
+ The `cir.sub` operation performs subtraction on integer or floating-point
+ operands. Both operands and the result must have the same type.
- If the `sat` (saturated) attribute is present, the result is clamped to
- the maximum value representatable by the type if it would otherwise
- exceed that value and is clamped to the minimum representable value if
- it would otherwise be below that value.
+ For integer types, the optional `nsw` (no signed wrap) and `nuw` (no
+ unsigned wrap) unit attributes indicate that the result is poison if signed
+ or unsigned overflow occurs, respectively. The optional `sat` (saturated)
+ attribute clamps the result to the type's representable range. The
+ `nsw`/`nuw` flags and `sat` are mutually exclusive.
+
+ Example:
```mlir
- %5 = cir.binop(add, %1, %2) : !s32i
- %6 = cir.binop(mul, %1, %2) : !u8i
- %7 = cir.binop(add, %1, %2) nsw : !s32i
- %8 = cir.binop(add, %3, %4) nuw : !u32i
- %9 = cir.binop(add, %1, %2) sat : !s32i
+ %0 = cir.sub %a, %b : !s32i
+ %1 = cir.sub nsw %a, %b : !s32i
+ %2 = cir.sub sat %a, %b : !s32i
+ %3 = cir.sub %a, %b : !cir.float
```
}];
+}
+
+//===----------------------------------------------------------------------===//
+// MulOp
+//===----------------------------------------------------------------------===//
+
+def CIR_MulOp : CIR_BinaryOp<"mul", CIR_AnyArithType> {
+ let summary = "Integer or floating-point multiplication";
+ let description = [{
+ The `cir.mul` operation performs multiplication on integer or
floating-point
+ operands. Both operands and the result must have the same type.
+
+ For integer types, the optional `nsw` (no signed wrap) and `nuw` (no
+ unsigned wrap) unit attributes indicate that the result is poison if signed
+ or unsigned overflow occurs, respectively.
+ Example:
+
+ ```mlir
+ %0 = cir.mul %a, %b : !s32i
+ %1 = cir.mul nsw %a, %b : !s32i
+ %2 = cir.mul nuw %a, %b : !u32i
+ %3 = cir.mul %a, %b : !cir.float
+ ```
+ }];
+
let arguments = (ins
- CIR_BinOpKind:$kind,
- CIR_AnyType:$lhs, CIR_AnyType:$rhs,
- UnitAttr:$no_unsigned_wrap,
- UnitAttr:$no_signed_wrap,
- UnitAttr:$saturated
+ CIR_AnyArithType:$lhs, CIR_AnyArithType:$rhs,
+ UnitProp:$no_signed_wrap,
+ UnitProp:$no_unsigned_wrap
);
- // TODO: get more accurate than CIR_AnyType
- let results = (outs CIR_AnyType:$result);
-
let assemblyFormat = [{
- `(` $kind `,` $lhs `,` $rhs `)`
(`nsw` $no_signed_wrap^)?
(`nuw` $no_unsigned_wrap^)?
- (`sat` $saturated^)?
- `:` type($lhs) attr-dict
+ $lhs `,` $rhs `:` type($lhs) attr-dict
}];
let hasVerifier = 1;
+}
- let extraLLVMLoweringPatternDecl = [{
- mlir::LLVM::IntegerOverflowFlags getIntOverflowFlag(cir::BinOp op) const;
+//===----------------------------------------------------------------------===//
+// DivOp
+//===----------------------------------------------------------------------===//
+
+def CIR_DivOp : CIR_BinaryOp<"div", CIR_AnyArithType> {
+ let summary = "Integer or floating-point division";
+ let description = [{
+ The `cir.div` operation performs division on integer or floating-point
+ operands. Both operands and the result must have the same type.
+
+ Example:
+
+ ```mlir
+ %0 = cir.div %a, %b : !s32i
+ %1 = cir.div %a, %b : !u32i
+ %2 = cir.div %a, %b : !cir.float
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// RemOp
+//===----------------------------------------------------------------------===//
+
+def CIR_RemOp : CIR_BinaryOp<"rem", CIR_AnyArithType> {
+ let summary = "Integer or floating-point remainder";
+ let description = [{
+ The `cir.rem` operation computes the remainder of division on integer or
+ floating-point operands. Both operands and the result must have the same
+ type.
+
+ Example:
+
+ ```mlir
+ %0 = cir.rem %a, %b : !s32i
+ %1 = cir.rem %a, %b : !u32i
+ %2 = cir.rem %a, %b : !cir.float
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// AndOp
+//===----------------------------------------------------------------------===//
+
+// FIXME: Commutative, Idempotent traits
+def CIR_AndOp : CIR_BinaryOp<"and", CIR_AnyBitwiseType> {
+ let summary = "Bitwise AND";
+ let description = [{
+ The `cir.and` operation performs a bitwise AND on integer operands.
+ Both operands and the result must have the same integer type.
+
+ Example:
+
+ ```mlir
+ %0 = cir.and %a, %b : !s32i
+ %1 = cir.and %a, %b : !cir.bool
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// OrOp
+//===----------------------------------------------------------------------===//
+
+// FIXME: Commutative, Idempotent traits
+def CIR_OrOp : CIR_BinaryOp<"or", CIR_AnyBitwiseType> {
+ let summary = "Bitwise OR";
+ let description = [{
+ The `cir.or` operation performs a bitwise OR on integer operands.
+ Both operands and the result must have the same integer type.
+
+ Example:
+
+ ```mlir
+ %0 = cir.or %a, %b : !s32i
+ %1 = cir.or %a, %b : !cir.bool
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// XorOp
+//===----------------------------------------------------------------------===//
+
+def CIR_XorOp : CIR_BinaryOp<"xor", CIR_AnyBitwiseType> {
+ let summary = "Bitwise XOR";
+ let description = [{
+ The `cir.xor` operation performs a bitwise XOR on integer operands.
+ Both operands and the result must have the same integer type.
+
+ Example:
+
+ ```mlir
+ %0 = cir.xor %a, %b : !s32i
+ %1 = cir.xor %a, %b : !cir.bool
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// MaxOp
+//===----------------------------------------------------------------------===//
+
+def CIR_MaxOp : CIR_BinaryOp<"max", CIR_AnyIntOrVecOfIntType> {
----------------
andykaylor wrote:
Is there a reason that we have `max` but not `min`?
https://github.com/llvm/llvm-project/pull/184227
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits