diff --git a/mlir/include/mlir/Dialect/Arithmetic/IR/Arithmetic.h b/mlir/include/mlir/Dialect/Arithmetic/IR/Arithmetic.h --- a/mlir/include/mlir/Dialect/Arithmetic/IR/Arithmetic.h +++ b/mlir/include/mlir/Dialect/Arithmetic/IR/Arithmetic.h @@ -38,6 +38,7 @@ //===----------------------------------------------------------------------===// namespace mlir { +namespace arith { /// Compute `lhs` `pred` `rhs`, where `pred` is one of the known integer /// comparison predicates. @@ -49,6 +50,7 @@ bool applyCmpPredicate(arith::CmpFPredicate predicate, const APFloat &lhs, const APFloat &rhs); +} // end namespace arith } // end namespace mlir #endif // MLIR_DIALECT_ARITHMETIC_IR_ARITHMETIC_H_ diff --git a/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticBase.td b/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticBase.td --- a/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticBase.td +++ b/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticBase.td @@ -16,59 +16,9 @@ let cppNamespace = "::mlir::arith"; let description = [{ The arithmetic dialect is intended to hold basic integer and floating point - mathematical operations. This includes unary, binary, and ternery arithmetic + mathematical operations. This includes unary, binary, and ternary arithmetic ops, bitwise and shift ops, cast ops, and compare ops. Operations in this dialect also accept vectors and tensors of integers or floats. - - Operation index: - - ``` - ArithmeticOp - | - |-> IntBinaryOp - | addi - | subi - | muli - | divui - | divsi - | ceildivsi - | floordivsi - | remui - | remsi - | andi - | ori - | xori - | shli - | shrui - | shrsi - | - |-> FloatUnaryOp - | negf - | - \-> FloatBinaryOp - addf - subf - mulf - divf - remf - - ArithmeticCastOp - extui - extsi - extf - trunci - truncf - uitofp - sitofp - fptoui - fptosi - index_cast - bitcast - - ArithmeticCompareOp - cmpi - cmpf - ``` }]; } diff --git a/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticOps.td b/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticOps.td --- a/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticOps.td +++ b/mlir/include/mlir/Dialect/Arithmetic/IR/ArithmeticOps.td @@ -21,72 +21,50 @@ DeclareOpInterfaceMethods] # ElementwiseMappable.traits>; -// Base class for integer and floating point arithmetic ops. Has one result. -// Requires operands and result to be of the same type. +// 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 +// tensors or vectors of integers or floats. class Arith_ArithmeticOp traits = []> : Arith_Op; -// Base class for unary arithmetic operations, which have one operand. +// Base class for unary arithmetic operations. class Arith_UnaryOp traits = []> : Arith_ArithmeticOp { let assemblyFormat = "$operand attr-dict `:` type($result)"; } -// Base class for binary arithmetic operations, which have two operands. +// Base class for binary arithmetic operations. class Arith_BinaryOp traits = []> : Arith_ArithmeticOp { let assemblyFormat = "$lhs `,` $rhs attr-dict `:` type($result)"; } -// Base class for ternary arithmetic operations, which have three operands. +// Base class for ternary arithmetic operations. class Arith_TernaryOp traits = []> : Arith_ArithmeticOp { let assemblyFormat = "$a `,` $b `,` $c attr-dict `:` type($result)"; } -// Base class for integer arithmetic operations. These operations accept two -// operands and return one result of the same type. This type may be an integer -// scalar type, a vector whose element type is an integer type, or an integer -// tensor. The custom assembly format of these operations is: -// -// i %0, %1 : i32 -// +// Base class for integer binary operations. class Arith_IntBinaryOp traits = []> : Arith_BinaryOp, Arguments<(ins SignlessIntegerLike:$lhs, SignlessIntegerLike:$rhs)>, Results<(outs SignlessIntegerLike:$result)>; -// Base class for float point unary operations. These operations accept one -// operand and return one result of the same type. This type may be a floating -// point scalar type, a vector whose element type is a floating point type, or a -// floating point tensor. The custom assembly form of these operations is: -// -// f %0 : f32 -// +// Base class for floating point unary operations. class Arith_FloatUnaryOp traits = []> : Arith_UnaryOp, Arguments<(ins FloatLike:$operand)>, Results<(outs FloatLike:$result)>; -// Base class for floating point binary operations. These operations accept two -// operands and return one result of the same type. This type may be a floating -// point scalar type, a vector whose element type is a floating point type, or a -// floating point tensor. The custom asesmbly form of these operations is: -// -// f %0, %1 : f32 -// +// Base class for floating point binary operations. class Arith_FloatBinaryOp traits = []> : Arith_BinaryOp, Arguments<(ins FloatLike:$lhs, FloatLike:$rhs)>, Results<(outs FloatLike:$result)>; -// Base class for arithmetic cast operations. Requires a single operand and a -// single result, but does not constrain them to any specific types. If either -// operand or result is a vector or tensor of types, the other must be one of -// the same shape. The custom assembly format of these operations is: -// -// %0 : to -// +// Base class for arithmetic cast operations. Requires a single operand and +// result. If either is a shaped type, then the other must be of the same shape. class Arith_CastOp traits = []> : Arith_Op { - let summary = "integer addition operation"; +def Arith_ConstantOp : Op]> { + let summary = "integer or floating point constant"; let description = [{ Syntax: ``` - operation ::= ssa-id `=` `arith.addi` ssa-use `,` ssa-use `:` type + operation ::= ssa-id `=` `arith.const` attribute-value `:` type ``` + The `const` operation produces an SSA value equal to some integer or + floating point constant specified by an attribute. This is the way MLIR uses + to form simple integer and floating point constants. + + Example: + + ``` + // Integer constant + %1 = constant 42 : i32 + + // Equivalent generic form + %1 = "std.constant"() {value = 42 : i32} : () -> i32 + ``` + }]; + + let arguments = (ins AnyAttr:$value); + let results = (outs SignlessIntegerOrFloatLike:$result); + + let builders = [ + OpBuilder<(ins "Attribute":$value), + [{ build($_builder, $_state, value.getType(), value); }]>, + OpBuilder<(ins "Attribute":$value, "Type":$type), + [{ build($_builder, $_state, type, value); }]>, + ]; + + let hasFolder = 1; + let verifier = [{ return ::verify(*this); }]; + let assemblyFormat = "attr-dict $value"; +} + +//===----------------------------------------------------------------------===// +// AddIOp +//===----------------------------------------------------------------------===// + +def Arith_AddIOp : Arith_IntBinaryOp<"addi", [Commutative]> { + let summary = "integer addition operation"; + let description = [{ The `addi` operation takes two operands and returns one result, each of these is required to be the same type. This type may be an integer scalar type, a vector whose element type is integer, or a tensor of integers. It @@ -197,11 +215,6 @@ def Arith_DivUIOp : Arith_IntBinaryOp<"divui"> { let summary = "unsigned integer division operation"; let description = [{ - Syntax: - ``` - operation ::= ssa-id `=` `arith.divui` ssa-use `,` ssa-use `:` type - ``` - Unsigned integer division. Rounds towards zero. Treats the leading bit as the most significant, i.e. for `i16` given two's complement representation, `6 / -2 = 6 / (2^16 - 2) = 0`. @@ -232,12 +245,6 @@ def Arith_DivSIOp : Arith_IntBinaryOp<"divsi"> { let summary = "signed integer division operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.divsi` ssa-use `,` ssa-use `:` type - ``` - Signed integer division. Rounds towards zero. Treats the leading bit as sign, i.e. `6 / -2 = -3`. @@ -267,12 +274,6 @@ def Arith_CeilDivSIOp : Arith_IntBinaryOp<"ceildivsi"> { let summary = "signed ceil integer division operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.ceildivsi` ssa-use `,` ssa-use `:` type - ``` - Signed integer division. Rounds towards positive infinity, i.e. `7 / -2 = -3`. Note: the semantics of division by zero or signed division overflow (minimum @@ -295,12 +296,6 @@ def Arith_FloorDivSIOp : Arith_IntBinaryOp<"floordivsi"> { let summary = "signed floor integer division operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.floordivsi` ssa-use `,` ssa-use `:` type - ``` - Signed integer division. Rounds towards negative infinity, i.e. `5 / -2 = -3`. Note: the semantics of division by zero or signed division overflow (minimum @@ -324,12 +319,6 @@ def Arith_RemUIOp : Arith_IntBinaryOp<"remui"> { let summary = "unsigned integer division remainder operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.remui` ssa-use `,` ssa-use `:` type - ``` - Unsigned integer division remainder. Treats the leading bit as the most significant, i.e. for `i16`, `6 % -2 = 6 % (2^16 - 2) = 6`. @@ -359,12 +348,6 @@ def Arith_RemSIOp : Arith_IntBinaryOp<"remsi"> { let summary = "signed integer division remainder operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.remsi` ssa-use `,` ssa-use `:` type - ``` - Signed integer division remainder. Treats the leading bit as sign, i.e. `6 % -2 = 0`. @@ -394,12 +377,6 @@ def Arith_AndIOp : Arith_IntBinaryOp<"andi", [Commutative]> { let summary = "integer binary and"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.andi` ssa-use `,` ssa-use `:` type - ``` - The `andi` operation takes two operands and returns one result, each of these is required to be the same type. This type may be an integer scalar type, a vector whose element type is integer, or a tensor of integers. It @@ -428,12 +405,6 @@ def Arith_OrIOp : Arith_IntBinaryOp<"ori", [Commutative]> { let summary = "integer binary or"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.ori` ssa-use `,` ssa-use `:` type - ``` - The `ori` operation takes two operands and returns one result, each of these is required to be the same type. This type may be an integer scalar type, a vector whose element type is integer, or a tensor of integers. It has no @@ -556,12 +527,6 @@ def Arith_NegFOp : Arith_FloatUnaryOp<"negf"> { let summary = "floating point negation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.negf` ssa-use `:` type - ``` - The `negf` operation computes the negation of a given value. It takes one operand and returns one result of the same type. This type may be a float scalar type, a vector whose element type is float, or a tensor of floats. @@ -589,12 +554,6 @@ def Arith_AddFOp : Arith_FloatBinaryOp<"addf"> { let summary = "floating point addition operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.addf` ssa-use `,` ssa-use `:` type - ``` - The `addf` operation takes two operands and returns one result, each of these is required to be the same type. This type may be a floating point scalar type, a vector whose element type is a floating point type, or a @@ -635,12 +594,6 @@ def Arith_MulFOp : Arith_FloatBinaryOp<"mulf"> { let summary = "floating point multiplication operation"; let description = [{ - Syntax: - - ``` - operation ::= ssa-id `=` `arith.mulf` ssa-use `,` ssa-use `:` type - ``` - The `mulf` operation takes two operands and returns one result, each of these is required to be the same type. This type may be a floating point scalar type, a vector whose element type is a floating point type, or a diff --git a/mlir/include/mlir/Dialect/Arithmetic/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/Arithmetic/IR/CMakeLists.txt --- a/mlir/include/mlir/Dialect/Arithmetic/IR/CMakeLists.txt +++ b/mlir/include/mlir/Dialect/Arithmetic/IR/CMakeLists.txt @@ -1,2 +1,5 @@ +set(LLVM_TARGET_DEFINITIONS ArithmeticOps.td) +mlir_tablegen(ArithmeticOpsEnums.h.inc -gen-enum-decls) +mlir_tablegen(ArithmeticOpsEnums.cpp.inc -gen-enum-defs) add_mlir_dialect(ArithmeticOps arith) add_mlir_doc(ArithmeticOps ArithmeticOps Dialects/ -gen-dialect-doc) diff --git a/mlir/lib/Dialect/Arithmetic/IR/ArithmeticOps.cpp b/mlir/lib/Dialect/Arithmetic/IR/ArithmeticOps.cpp --- a/mlir/lib/Dialect/Arithmetic/IR/ArithmeticOps.cpp +++ b/mlir/lib/Dialect/Arithmetic/IR/ArithmeticOps.cpp @@ -18,28 +18,26 @@ using namespace mlir; using namespace mlir::arith; -namespace { - //===----------------------------------------------------------------------===// // Pattern helpers //===----------------------------------------------------------------------===// -IntegerAttr addIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, - Attribute rhs) { +static IntegerAttr addIntegerAttrs(PatternRewriter &builder, Value res, + Attribute lhs, Attribute rhs) { return builder.getIntegerAttr(res.getType(), lhs.cast().getInt() + rhs.cast().getInt()); } -IntegerAttr subIntegerAttrs(PatternRewriter &builder, Value res, Attribute lhs, - Attribute rhs) { +static IntegerAttr subIntegerAttrs(PatternRewriter &builder, Value res, + Attribute lhs, Attribute rhs) { return builder.getIntegerAttr(res.getType(), lhs.cast().getInt() - rhs.cast().getInt()); } /// Invert an integer comparison predicate. -arith::CmpIPredicate invertPredicate(arith::CmpIPredicate pred) { +static arith::CmpIPredicate invertPredicate(arith::CmpIPredicate pred) { switch (pred) { case arith::CmpIPredicate::eq: return arith::CmpIPredicate::ne; @@ -62,9 +60,10 @@ case arith::CmpIPredicate::uge: return arith::CmpIPredicate::ult; } + llvm_unreachable("unknown cmpi predicate kind"); } -arith::CmpIPredicateAttr invertPredicate(arith::CmpIPredicateAttr pred) { +static arith::CmpIPredicateAttr invertPredicate(arith::CmpIPredicateAttr pred) { return arith::CmpIPredicateAttr::get(pred.getContext(), invertPredicate(pred.getValue())); } @@ -73,8 +72,8 @@ // TableGen'd canonicalization patterns //===----------------------------------------------------------------------===// +namespace { #include "ArithmeticCanonicalization.inc" - } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -219,22 +218,23 @@ if (a.sgt(zero) && b.sgt(zero)) { // Both positive, return ceil(a, b). return signedCeilNonnegInputs(a, b, overflowOrDiv0); - } else if (a.slt(zero) && b.slt(zero)) { + } + if (a.slt(zero) && b.slt(zero)) { // Both negative, return ceil(-a, -b). APInt posA = zero.ssub_ov(a, overflowOrDiv0); APInt posB = zero.ssub_ov(b, overflowOrDiv0); return signedCeilNonnegInputs(posA, posB, overflowOrDiv0); - } else if (a.slt(zero) && b.sgt(zero)) { + } + if (a.slt(zero) && b.sgt(zero)) { // A is negative, b is positive, return - ( -a / b). APInt posA = zero.ssub_ov(a, overflowOrDiv0); APInt div = posA.sdiv_ov(b, overflowOrDiv0); return zero.ssub_ov(div, overflowOrDiv0); - } else { - // A is positive (or zero), b is negative, return - (a / -b). - APInt posB = zero.ssub_ov(b, overflowOrDiv0); - APInt div = a.sdiv_ov(posB, overflowOrDiv0); - return zero.ssub_ov(div, overflowOrDiv0); } + // A is positive (or zero), b is negative, return - (a / -b). + APInt posB = zero.ssub_ov(b, overflowOrDiv0); + APInt div = a.sdiv_ov(posB, overflowOrDiv0); + return zero.ssub_ov(div, overflowOrDiv0); }); // Fold out floor division by one. Assumes all tensors of all ones are @@ -267,22 +267,23 @@ if (a.sge(zero) && b.sgt(zero)) { // Both positive (or a is zero), return a / b. return a.sdiv_ov(b, overflowOrDiv0); - } else if (a.sle(zero) && b.slt(zero)) { + } + if (a.sle(zero) && b.slt(zero)) { // Both negative (or a is zero), return -a / -b. APInt posA = zero.ssub_ov(a, overflowOrDiv0); APInt posB = zero.ssub_ov(b, overflowOrDiv0); return posA.sdiv_ov(posB, overflowOrDiv0); - } else if (a.slt(zero) && b.sgt(zero)) { + } + if (a.slt(zero) && b.sgt(zero)) { // A is negative, b is positive, return - ceil(-a, b). APInt posA = zero.ssub_ov(a, overflowOrDiv0); APInt ceil = signedCeilNonnegInputs(posA, b, overflowOrDiv0); return zero.ssub_ov(ceil, overflowOrDiv0); - } else { - // A is positive, b is negative, return - ceil(a, -b). - APInt posB = zero.ssub_ov(b, overflowOrDiv0); - APInt ceil = signedCeilNonnegInputs(a, posB, overflowOrDiv0); - return zero.ssub_ov(ceil, overflowOrDiv0); } + // A is positive, b is negative, return - ceil(a, -b). + APInt posB = zero.ssub_ov(b, overflowOrDiv0); + APInt ceil = signedCeilNonnegInputs(a, posB, overflowOrDiv0); + return zero.ssub_ov(ceil, overflowOrDiv0); }); // Fold out floor division by one. Assumes all tensors of all ones are @@ -594,8 +595,8 @@ /// Compute `lhs` `pred` `rhs`, where `pred` is one of the known integer /// comparison predicates. -bool mlir::applyCmpPredicate(arith::CmpIPredicate predicate, const APInt &lhs, - const APInt &rhs) { +bool mlir::arith::applyCmpPredicate(arith::CmpIPredicate predicate, + const APInt &lhs, const APInt &rhs) { switch (predicate) { case arith::CmpIPredicate::eq: return lhs.eq(rhs); @@ -618,6 +619,7 @@ case arith::CmpIPredicate::uge: return lhs.uge(rhs); } + llvm_unreachable("unknown cmpi predicate kind"); } /// Returns true if the predicate is true for two equal operands. @@ -636,6 +638,7 @@ case arith::CmpIPredicate::ugt: return false; } + llvm_unreachable("unknown cmpi predicate kind"); } OpFoldResult arith::CmpIOp::fold(ArrayRef operands) { @@ -662,8 +665,8 @@ /// Compute `lhs` `pred` `rhs`, where `pred` is one of the known floating point /// comparison predicates. -bool mlir::applyCmpPredicate(arith::CmpFPredicate predicate, const APFloat &lhs, - const APFloat &rhs) { +bool mlir::arith::applyCmpPredicate(arith::CmpFPredicate predicate, + const APFloat &lhs, const APFloat &rhs) { auto cmpResult = lhs.compare(rhs); switch (predicate) { case arith::CmpFPredicate::AlwaysFalse: @@ -705,6 +708,7 @@ case arith::CmpFPredicate::AlwaysTrue: return true; } + llvm_unreachable("unknown cmpf predicate kind"); } OpFoldResult arith::CmpFOp::fold(ArrayRef operands) {