include "mlir/IR/OpAsmInterface.td"
include "mlir/IR/EnumAttr.td"
-// Base class for Arith dialect ops. Ops in this dialect have no side
+// Base class for Arith dialect ops. Ops in this dialect have no memory
// effects and can be applied element-wise to vectors and tensors.
class Arith_Op<string mnemonic, list<Trait> traits = []> :
- Op<Arith_Dialect, mnemonic, traits # [Pure,
- DeclareOpInterfaceMethods<VectorUnrollOpInterface>] #
- ElementwiseMappable.traits>;
+ Op<Arith_Dialect, mnemonic,
+ traits #
+ [DeclareOpInterfaceMethods<VectorUnrollOpInterface>, NoMemoryEffect] #
+ ElementwiseMappable.traits>;
// Base class for integer and floating point arithmetic ops. All ops have one
// result, require operands and results to be of the same type, and can accept
// Base class for unary arithmetic operations.
class Arith_UnaryOp<string mnemonic, list<Trait> traits = []> :
- Arith_ArithOp<mnemonic, traits> {
+ Arith_ArithOp<mnemonic, traits # [Pure]> {
let assemblyFormat = "$operand attr-dict `:` type($result)";
}
// Base class for ternary arithmetic operations.
class Arith_TernaryOp<string mnemonic, list<Trait> traits = []> :
- Arith_ArithOp<mnemonic, traits> {
+ Arith_ArithOp<mnemonic, traits # [Pure]> {
let assemblyFormat = "$a `,` $b `,` $c attr-dict `:` type($result)";
}
Arguments<(ins SignlessIntegerLike:$lhs, SignlessIntegerLike:$rhs)>,
Results<(outs SignlessIntegerLike:$result)>;
+// Base class for integer binary operations without undefined behavior.
+class Arith_TotalIntBinaryOp<string mnemonic, list<Trait> traits = []> :
+ Arith_IntBinaryOp<mnemonic, traits # [Pure]>;
+
// Base class for floating point unary operations.
class Arith_FloatUnaryOp<string mnemonic, list<Trait> traits = []> :
Arith_UnaryOp<mnemonic,
// Base class for floating point binary operations.
class Arith_FloatBinaryOp<string mnemonic, list<Trait> traits = []> :
Arith_BinaryOp<mnemonic,
- !listconcat([DeclareOpInterfaceMethods<ArithFastMathInterface>],
+ !listconcat([Pure, DeclareOpInterfaceMethods<ArithFastMathInterface>],
traits)>,
Arguments<(ins FloatLike:$lhs, FloatLike:$rhs,
DefaultValuedAttr<Arith_FastMathAttr, "FastMathFlags::none">:$fastmath)>,
// result. If either is a shaped type, then the other must be of the same shape.
class Arith_CastOp<string mnemonic, TypeConstraint From, TypeConstraint To,
list<Trait> traits = []> :
- Arith_Op<mnemonic, traits # [SameOperandsAndResultShape,
+ Arith_Op<mnemonic, traits # [Pure, SameOperandsAndResultShape,
DeclareOpInterfaceMethods<CastOpInterface>]>,
Arguments<(ins From:$in)>,
Results<(outs To:$out)> {
// and returns a single `BoolLike` result. If the operand type is a vector or
// tensor, then the result will be one of `i1` of the same shape.
class Arith_CompareOp<string mnemonic, list<Trait> traits = []> :
- Arith_Op<mnemonic, traits # [SameTypeOperands, TypesMatchWith<
+ Arith_Op<mnemonic, traits # [Pure, SameTypeOperands, TypesMatchWith<
"result type has i1 element type and same shape as operands",
"lhs", "result", "::getI1SameShape($_self)">]> {
let results = (outs BoolLike:$result);
// AddIOp
//===----------------------------------------------------------------------===//
-def Arith_AddIOp : Arith_IntBinaryOp<"addi", [Commutative]> {
+def Arith_AddIOp : Arith_TotalIntBinaryOp<"addi", [Commutative]> {
let summary = "integer addition operation";
let description = [{
The `addi` operation takes two operands and returns one result, each of
}
-def Arith_AddUICarryOp : Arith_Op<"addui_carry", [Commutative,
+def Arith_AddUICarryOp : Arith_Op<"addui_carry", [Pure, Commutative,
AllTypesMatch<["lhs", "rhs", "sum"]>]> {
let summary = "unsigned integer addition operation returning sum and carry";
let description = [{
// SubIOp
//===----------------------------------------------------------------------===//
-def Arith_SubIOp : Arith_IntBinaryOp<"subi"> {
+def Arith_SubIOp : Arith_TotalIntBinaryOp<"subi"> {
let summary = "integer subtraction operation";
let hasFolder = 1;
let hasCanonicalizer = 1;
// MulIOp
//===----------------------------------------------------------------------===//
-def Arith_MulIOp : Arith_IntBinaryOp<"muli", [Commutative]> {
+def Arith_MulIOp : Arith_TotalIntBinaryOp<"muli", [Commutative]> {
let summary = "integer multiplication operation";
let hasFolder = 1;
}
// DivUIOp
//===----------------------------------------------------------------------===//
-def Arith_DivUIOp : Arith_IntBinaryOp<"divui"> {
+def Arith_DivUIOp : Arith_IntBinaryOp<"divui", [ConditionallySpeculatable]> {
let summary = "unsigned integer division operation";
let description = [{
Unsigned integer division. Rounds towards zero. Treats the leading bit as
%x = arith.divui %y, %z : tensor<4x?xi8>
```
}];
+
+ let extraClassDeclaration = [{
+ /// Interface method for ConditionallySpeculatable.
+ Speculation::Speculatability getSpeculatability();
+ }];
+
let hasFolder = 1;
}
// DivSIOp
//===----------------------------------------------------------------------===//
-def Arith_DivSIOp : Arith_IntBinaryOp<"divsi"> {
+def Arith_DivSIOp : Arith_IntBinaryOp<"divsi", [ConditionallySpeculatable]> {
let summary = "signed integer division operation";
let description = [{
Signed integer division. Rounds towards zero. Treats the leading bit as
%x = arith.divsi %y, %z : tensor<4x?xi8>
```
}];
+
+ let extraClassDeclaration = [{
+ /// Interface method for ConditionallySpeculatable.
+ Speculation::Speculatability getSpeculatability();
+ }];
+
let hasFolder = 1;
}
// CeilDivUIOp
//===----------------------------------------------------------------------===//
-def Arith_CeilDivUIOp : Arith_IntBinaryOp<"ceildivui"> {
+def Arith_CeilDivUIOp : Arith_IntBinaryOp<"ceildivui",
+ [ConditionallySpeculatable]> {
let summary = "unsigned ceil integer division operation";
let description = [{
Unsigned integer division. Rounds towards positive infinity. Treats the
%a = arith.ceildivui %b, %c : i64
```
}];
+
+ let extraClassDeclaration = [{
+ /// Interface method for ConditionallySpeculatable.
+ Speculation::Speculatability getSpeculatability();
+ }];
+
let hasFolder = 1;
}
// CeilDivSIOp
//===----------------------------------------------------------------------===//
-def Arith_CeilDivSIOp : Arith_IntBinaryOp<"ceildivsi"> {
+def Arith_CeilDivSIOp : Arith_IntBinaryOp<"ceildivsi",
+ [ConditionallySpeculatable]> {
let summary = "signed ceil integer division operation";
let description = [{
Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`.
%a = arith.ceildivsi %b, %c : i64
```
}];
+
+ let extraClassDeclaration = [{
+ /// Interface method for ConditionallySpeculatable.
+ Speculation::Speculatability getSpeculatability();
+ }];
+
let hasFolder = 1;
}
// FloorDivSIOp
//===----------------------------------------------------------------------===//
-def Arith_FloorDivSIOp : Arith_IntBinaryOp<"floordivsi"> {
+def Arith_FloorDivSIOp : Arith_TotalIntBinaryOp<"floordivsi"> {
let summary = "signed floor integer division operation";
let description = [{
Signed integer division. Rounds towards negative infinity, i.e. `5 / -2 = -3`.
// RemUIOp
//===----------------------------------------------------------------------===//
-def Arith_RemUIOp : Arith_IntBinaryOp<"remui"> {
+def Arith_RemUIOp : Arith_TotalIntBinaryOp<"remui"> {
let summary = "unsigned integer division remainder operation";
let description = [{
Unsigned integer division remainder. Treats the leading bit as the most
// RemSIOp
//===----------------------------------------------------------------------===//
-def Arith_RemSIOp : Arith_IntBinaryOp<"remsi"> {
+def Arith_RemSIOp : Arith_TotalIntBinaryOp<"remsi"> {
let summary = "signed integer division remainder operation";
let description = [{
Signed integer division remainder. Treats the leading bit as sign, i.e. `6 %
// AndIOp
//===----------------------------------------------------------------------===//
-def Arith_AndIOp : Arith_IntBinaryOp<"andi", [Commutative, Idempotent]> {
+def Arith_AndIOp : Arith_TotalIntBinaryOp<"andi", [Commutative, Idempotent]> {
let summary = "integer binary and";
let description = [{
The `andi` operation takes two operands and returns one result, each of
// OrIOp
//===----------------------------------------------------------------------===//
-def Arith_OrIOp : Arith_IntBinaryOp<"ori", [Commutative, Idempotent]> {
+def Arith_OrIOp : Arith_TotalIntBinaryOp<"ori", [Commutative, Idempotent]> {
let summary = "integer binary or";
let description = [{
The `ori` operation takes two operands and returns one result, each of these
// XOrIOp
//===----------------------------------------------------------------------===//
-def Arith_XOrIOp : Arith_IntBinaryOp<"xori", [Commutative]> {
+def Arith_XOrIOp : Arith_TotalIntBinaryOp<"xori", [Commutative]> {
let summary = "integer binary xor";
let description = [{
The `xori` operation takes two operands and returns one result, each of
// ShLIOp
//===----------------------------------------------------------------------===//
-def Arith_ShLIOp : Arith_IntBinaryOp<"shli"> {
+def Arith_ShLIOp : Arith_TotalIntBinaryOp<"shli"> {
let summary = "integer left-shift";
let description = [{
The `shli` operation shifts an integer value to the left by a variable
// ShRUIOp
//===----------------------------------------------------------------------===//
-def Arith_ShRUIOp : Arith_IntBinaryOp<"shrui"> {
+def Arith_ShRUIOp : Arith_TotalIntBinaryOp<"shrui"> {
let summary = "unsigned integer right-shift";
let description = [{
The `shrui` operation shifts an integer value to the right by a variable
// ShRSIOp
//===----------------------------------------------------------------------===//
-def Arith_ShRSIOp : Arith_IntBinaryOp<"shrsi"> {
+def Arith_ShRSIOp : Arith_TotalIntBinaryOp<"shrsi"> {
let summary = "signed integer right-shift";
let description = [{
The `shrsi` operation shifts an integer value to the right by a variable
// MaxSIOp
//===----------------------------------------------------------------------===//
-def Arith_MaxSIOp : Arith_IntBinaryOp<"maxsi", [Commutative]> {
+def Arith_MaxSIOp : Arith_TotalIntBinaryOp<"maxsi", [Commutative]> {
let summary = "signed integer maximum operation";
let hasFolder = 1;
}
// MaxUIOp
//===----------------------------------------------------------------------===//
-def Arith_MaxUIOp : Arith_IntBinaryOp<"maxui", [Commutative]> {
+def Arith_MaxUIOp : Arith_TotalIntBinaryOp<"maxui", [Commutative]> {
let summary = "unsigned integer maximum operation";
let hasFolder = 1;
}
// MinSIOp
//===----------------------------------------------------------------------===//
-def Arith_MinSIOp : Arith_IntBinaryOp<"minsi", [Commutative]> {
+def Arith_MinSIOp : Arith_TotalIntBinaryOp<"minsi", [Commutative]> {
let summary = "signed integer minimum operation";
let hasFolder = 1;
}
// MinUIOp
//===----------------------------------------------------------------------===//
-def Arith_MinUIOp : Arith_IntBinaryOp<"minui", [Commutative]> {
+def Arith_MinUIOp : Arith_TotalIntBinaryOp<"minui", [Commutative]> {
let summary = "unsigned integer minimum operation";
let hasFolder = 1;
}
// SelectOp
//===----------------------------------------------------------------------===//
-def SelectOp : Arith_Op<"select", [
+def SelectOp : Arith_Op<"select", [Pure,
AllTypesMatch<["true_value", "false_value", "result"]>,
DeclareOpInterfaceMethods<InferIntRangeInterface>,
] # ElementwiseMappable.traits> {
return
}
+
+// -----
+
+func.func @no_speculate_divui(
+// CHECK-LABEL: @no_speculate_divui(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.divui
+ %val = arith.divui %num, %denom : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_divsi(
+// CHECK-LABEL: @no_speculate_divsi(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.divsi
+ %val = arith.divsi %num, %denom : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_ceildivui(
+// CHECK-LABEL: @no_speculate_ceildivui(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.ceildivui
+ %val = arith.ceildivui %num, %denom : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_ceildivsi(
+// CHECK-LABEL: @no_speculate_ceildivsi(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.ceildivsi
+ %val = arith.ceildivsi %num, %denom : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_divui_const(%num: i32, %lb: index, %ub: index, %step: index) {
+// CHECK-LABEL: @no_speculate_divui_const(
+ %c0 = arith.constant 0 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.divui
+ %val = arith.divui %num, %c0 : i32
+ }
+
+ return
+}
+
+func.func @speculate_divui_const(
+// CHECK-LABEL: @speculate_divui_const(
+ %num: i32, %lb: index, %ub: index, %step: index) {
+ %c5 = arith.constant 5 : i32
+// CHECK: arith.divui
+// CHECK: scf.for
+ scf.for %i = %lb to %ub step %step {
+ %val = arith.divui %num, %c5 : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_ceildivui_const(%num: i32, %lb: index, %ub: index, %step: index) {
+// CHECK-LABEL: @no_speculate_ceildivui_const(
+ %c0 = arith.constant 0 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.ceildivui
+ %val = arith.ceildivui %num, %c0 : i32
+ }
+
+ return
+}
+
+func.func @speculate_ceildivui_const(
+// CHECK-LABEL: @speculate_ceildivui_const(
+ %num: i32, %lb: index, %ub: index, %step: index) {
+ %c5 = arith.constant 5 : i32
+// CHECK: arith.ceildivui
+// CHECK: scf.for
+ scf.for %i = %lb to %ub step %step {
+ %val = arith.ceildivui %num, %c5 : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_divsi_const0(
+// CHECK-LABEL: @no_speculate_divsi_const0(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %c0 = arith.constant 0 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.divsi
+ %val = arith.divsi %num, %c0 : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_divsi_const_minus1(
+// CHECK-LABEL: @no_speculate_divsi_const_minus1(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %cm1 = arith.constant -1 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.divsi
+ %val = arith.divsi %num, %cm1 : i32
+ }
+
+ return
+}
+
+func.func @speculate_divsi_const(
+// CHECK-LABEL: @speculate_divsi_const(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %c5 = arith.constant 5 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: arith.divsi
+// CHECK: scf.for
+ %val = arith.divsi %num, %c5 : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_ceildivsi_const0(
+// CHECK-LABEL: @no_speculate_ceildivsi_const0(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %c0 = arith.constant 0 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.ceildivsi
+ %val = arith.ceildivsi %num, %c0 : i32
+ }
+
+ return
+}
+
+func.func @no_speculate_ceildivsi_const_minus1(
+// CHECK-LABEL: @no_speculate_ceildivsi_const_minus1(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %cm1 = arith.constant -1 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: scf.for
+// CHECK: arith.ceildivsi
+ %val = arith.ceildivsi %num, %cm1 : i32
+ }
+
+ return
+}
+
+func.func @speculate_ceildivsi_const(
+// CHECK-LABEL: @speculate_ceildivsi_const(
+ %num: i32, %denom: i32, %lb: index, %ub: index, %step: index) {
+ %c5 = arith.constant 5 : i32
+ scf.for %i = %lb to %ub step %step {
+// CHECK: arith.ceildivsi
+// CHECK: scf.for
+ %val = arith.ceildivsi %num, %c5 : i32
+ }
+
+ return
+}