diff --git a/mlir/docs/Tutorials/Toy/Ch-2.md b/mlir/docs/Tutorials/Toy/Ch-2.md --- a/mlir/docs/Tutorials/Toy/Ch-2.md +++ b/mlir/docs/Tutorials/Toy/Ch-2.md @@ -517,12 +517,7 @@ } ``` -Above we introduce several of the concepts for defining operations in the ODS -framework, but there are many more that we haven't had a chance to: regions, -variadic operands, etc. Check out the -[full specification](../../OpDefinitions.md) for more details. - -## Complete Toy Example +#### Specifying a Custom Assembly Format At this point we can generate our "Toy IR". A simplified version of the previous example: @@ -565,6 +560,185 @@ } loc("test/codegen.toy":0:0) ``` +One thing to notice here is that all of our Toy operations are printed using the +generic assembly format. This format is the one shown when breaking down +`toy.transpose` at the beginning of this chapter. MLIR allows for operations to +define their own custom assembly format, either +[declaratively](../../OpDefinitions.md#declarative-assembly-format) or +imperatively via C++. Defining a custom assembly format allows for tailoring the +generated IR into something a bit more readable by removing a lot of the fluff +that is required by the generic format. Let's walk through an example of an +operation format that we would like to simplify. + +##### `toy.print` + +The current form of `toy.print` is a little verbose. There are a lot of +additional characters that we would like to strip away. Let's begin by thinking +of what a good format of `toy.print` would be, and see how we can implement it. +Looking at the basics of `toy.print` we get: + +```mlir +toy.print %5 : tensor<*xf64> loc(...) +``` + +Here we have stripped much of the format down to the bare essentials, and it has +become much more readable. To provide a custom assembly format, an operation can +either override the `parser` and `printer` fields for a C++ format, or the +`assemblyFormat` field for the declarative format. Let's look at the C++ variant +first, as this is what the declarative format maps to internally. + +```tablegen +/// Consider a stripped definition of `toy.print` here. +def PrintOp : Toy_Op<"print"> { + let arguments = (ins F64Tensor:$input); + + // Divert the printer and parser to static functions in our .cpp + // file that correspond to 'print' and 'printPrintOp'. 'printer' and 'parser' + // here correspond to an instance of a 'OpAsmParser' and 'OpAsmPrinter'. More + // details on these classes is shown below. + let printer = [{ return ::print(printer, *this); }]; + let parser = [{ return ::parse$cppClass(parser, result); }]; +} +``` + +A C++ implementation for the printer and parser is shown below: + +```c++ +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, PrintOp op) { + printer << "toy.print " << op.input(); + printer.printOptionalAttrDict(op.getAttrs()); + printer << " : " << op.input().getType(); +} + +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parsePrintOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + // Parse the input operand, the attribute dictionary, and the type of the + // input. + mlir::OpAsmParser::OperandType inputOperand; + mlir::Type inputType; + if (parser.parseOperand(inputOperand) || + parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || + parser.parseType(inputType)) + return mlir::failure(); + + // Resolve the input operand to the type we parsed in. + if (parser.resolveOperand(inputOperand, inputType, result.operands)) + return mlir::failure(); + + return mlir::success(); +} +``` + +With the C++ implementation defined, let's see how this can be mapped to the +[declarative format](../../OpDefinitions.md#declarative-assembly-format). The +declarative format is largely composed of three different components: + +* Directives + - A type of builtin function, with an optional set of arguments. +* Literals + - A keyword or punctuation surrounded by \`\`. +* Variables + - An entity that has been registered on the operation itself, i.e. an + argument(attribute or operand), result, successor, etc. In the `PrintOp` + example above, a variable would be `$input`. + +A direct mapping of our C++ format looks something like: + +```tablegen +/// Consider a stripped definition of `toy.print` here. +def PrintOp : Toy_Op<"print"> { + let arguments = (ins F64Tensor:$input); + + // In the following format we have two directives, `attr-dict` and `type`. + // These correspond to the attribute dictionary and the type of a given + // variable represectively. + let assemblyFormat = "$input attr-dict `:` type($input)"; +} +``` + +The [declarative format](../../OpDefinitions.md#declarative-assembly-format) has +many more interesting features, so be sure to check it out before implementing a +custom format in C++. After beautifying the format of a few of our operations we +now get a much more readable: + +```mlir +module { + func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> { + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> loc("test/codegen.toy":5:10) + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> loc("test/codegen.toy":5:25) + %2 = toy.mul %0, %1 : tensor<*xf64> loc("test/codegen.toy":5:25) + toy.return %2 : tensor<*xf64> loc("test/codegen.toy":5:3) + } loc("test/codegen.toy":4:1) + func @main() { + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> loc("test/codegen.toy":9:17) + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> loc("test/codegen.toy":9:3) + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> loc("test/codegen.toy":10:17) + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> loc("test/codegen.toy":10:3) + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/codegen.toy":11:11) + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/codegen.toy":12:11) + toy.print %5 : tensor<*xf64> loc("test/codegen.toy":13:3) + toy.return loc("test/codegen.toy":8:1) + } loc("test/codegen.toy":8:1) +} loc("test/codegen.toy":0:0) +``` + +Above we introduce several of the concepts for defining operations in the ODS +framework, but there are many more that we haven't had a chance to: regions, +variadic operands, etc. Check out the +[full specification](../../OpDefinitions.md) for more details. + +## Complete Toy Example + +At this point we can generate our "Toy IR". A simplified version of the previous +example: + +```toy +# User defined generic function that operates on unknown shaped arguments. +def multiply_transpose(a, b) { + return transpose(a) * transpose(b); +} + +def main() { + var a<2, 3> = [[1, 2, 3], [4, 5, 6]]; + var b<2, 3> = [1, 2, 3, 4, 5, 6]; + var c = multiply_transpose(a, b); + var d = multiply_transpose(b, a); + print(d); +} +``` + +Results in the following IR: + +```mlir +module { + func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> { + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> loc("test/codegen.toy":5:10) + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> loc("test/codegen.toy":5:25) + %2 = toy.mul %0, %1 : tensor<*xf64> loc("test/codegen.toy":5:25) + toy.return %2 : tensor<*xf64> loc("test/codegen.toy":5:3) + } loc("test/codegen.toy":4:1) + func @main() { + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> loc("test/codegen.toy":9:17) + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> loc("test/codegen.toy":9:3) + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> loc("test/codegen.toy":10:17) + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> loc("test/codegen.toy":10:3) + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/codegen.toy":11:11) + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> loc("test/codegen.toy":12:11) + toy.print %5 : tensor<*xf64> loc("test/codegen.toy":13:3) + toy.return loc("test/codegen.toy":8:1) + } loc("test/codegen.toy":8:1) +} loc("test/codegen.toy":0:0) +``` + You can build `toyc-ch2` and try yourself: `toyc-ch2 test/Examples/Toy/Ch2/codegen.toy -emit=mlir -mlir-print-debuginfo`. We can also check our RoundTrip: `toyc-ch2 test/Examples/Toy/Ch2/codegen.toy -emit=mlir diff --git a/mlir/docs/Tutorials/Toy/Ch-3.md b/mlir/docs/Tutorials/Toy/Ch-3.md --- a/mlir/docs/Tutorials/Toy/Ch-3.md +++ b/mlir/docs/Tutorials/Toy/Ch-3.md @@ -38,9 +38,9 @@ ```mlir func @transpose_transpose(%arg0: tensor<*xf64>) -> tensor<*xf64> { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%0) : (tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%1) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%0 : tensor<*xf64>) to tensor<*xf64> + toy.return %1 : tensor<*xf64> } ``` @@ -133,8 +133,8 @@ ```mlir func @transpose_transpose(%arg0: tensor<*xf64>) -> tensor<*xf64> { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%arg0) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + toy.return %arg0 : tensor<*xf64> } ``` @@ -154,7 +154,7 @@ ```mlir func @transpose_transpose(%arg0: tensor<*xf64>) -> tensor<*xf64> { - "toy.return"(%arg0) : (tensor<*xf64>) -> () + toy.return %arg0 : tensor<*xf64> } ``` @@ -229,13 +229,12 @@ ```mlir module { func @main() { - %0 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00]> : tensor<2xf64>} - : () -> tensor<2xf64> - %1 = "toy.reshape"(%0) : (tensor<2xf64>) -> tensor<2x1xf64> - %2 = "toy.reshape"(%1) : (tensor<2x1xf64>) -> tensor<2x1xf64> - %3 = "toy.reshape"(%2) : (tensor<2x1xf64>) -> tensor<2x1xf64> - "toy.print"(%3) : (tensor<2x1xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[1.000000e+00, 2.000000e+00]> : tensor<2xf64> + %1 = toy.reshape(%0 : tensor<2xf64>) to tensor<2x1xf64> + %2 = toy.reshape(%1 : tensor<2x1xf64>) to tensor<2x1xf64> + %3 = toy.reshape(%2 : tensor<2x1xf64>) to tensor<2x1xf64> + toy.print %3 : tensor<2x1xf64> + toy.return } } ``` @@ -246,10 +245,9 @@ ```mlir module { func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00], [2.000000e+00]]> \ - : tensor<2x1xf64>} : () -> tensor<2x1xf64> - "toy.print"(%0) : (tensor<2x1xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00], [2.000000e+00]]> : tensor<2x1xf64> + toy.print %0 : tensor<2x1xf64> + toy.return } } ``` diff --git a/mlir/docs/Tutorials/Toy/Ch-4.md b/mlir/docs/Tutorials/Toy/Ch-4.md --- a/mlir/docs/Tutorials/Toy/Ch-4.md +++ b/mlir/docs/Tutorials/Toy/Ch-4.md @@ -150,20 +150,20 @@ ```mlir func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%arg1) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.mul"(%0, %1) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%2) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.mul %0, %1 : tensor<*xf64> + toy.return %2 : tensor<*xf64> } func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.reshape"(%0) : (tensor<2x3xf64>) -> tensor<2x3xf64> - %2 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> - %3 = "toy.reshape"(%2) : (tensor<6xf64>) -> tensor<2x3xf64> - %4 = "toy.generic_call"(%1, %3) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - %5 = "toy.generic_call"(%3, %1) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } ``` @@ -226,8 +226,8 @@ %4 = "toy.transpose"(%2) : (tensor<*xf64>) -> tensor<*xf64> %5 = "toy.transpose"(%3) : (tensor<*xf64>) -> tensor<*xf64> %6 = "toy.mul"(%4, %5) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.print"(%6) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + toy.print %6 : tensor<*xf64> + toy.return } ``` @@ -374,8 +374,8 @@ %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> %1 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> %2 = "toy.mul"(%1, %1) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%2) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + toy.print %2 : tensor<3x2xf64> + toy.return } ``` diff --git a/mlir/docs/Tutorials/Toy/Ch-5.md b/mlir/docs/Tutorials/Toy/Ch-5.md --- a/mlir/docs/Tutorials/Toy/Ch-5.md +++ b/mlir/docs/Tutorials/Toy/Ch-5.md @@ -239,11 +239,11 @@ ```mlir func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } ``` @@ -291,7 +291,7 @@ } // Print the value held by the buffer. - "toy.print"(%0) : (memref<3x2xf64>) -> () + toy.print %0 : memref<3x2xf64> dealloc %2 : memref<2x3xf64> dealloc %1 : memref<3x2xf64> dealloc %0 : memref<3x2xf64> @@ -340,7 +340,7 @@ } // Print the value held by the buffer. - "toy.print"(%0) : (memref<3x2xf64>) -> () + toy.print %0 : memref<3x2xf64> dealloc %1 : memref<2x3xf64> dealloc %0 : memref<3x2xf64> return diff --git a/mlir/docs/Tutorials/Toy/Ch-6.md b/mlir/docs/Tutorials/Toy/Ch-6.md --- a/mlir/docs/Tutorials/Toy/Ch-6.md +++ b/mlir/docs/Tutorials/Toy/Ch-6.md @@ -115,11 +115,11 @@ ```mlir func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } ``` diff --git a/mlir/docs/Tutorials/Toy/Ch-7.md b/mlir/docs/Tutorials/Toy/Ch-7.md --- a/mlir/docs/Tutorials/Toy/Ch-7.md +++ b/mlir/docs/Tutorials/Toy/Ch-7.md @@ -342,7 +342,7 @@ ```mlir module { func @multiply_transpose(%arg0: !toy.struct, tensor<*xf64>>) { - "toy.return"() : () -> () + toy.return } } ``` @@ -391,9 +391,9 @@ that contains a set of constant values for each of the `struct` elements. ```mlir - %0 = "toy.struct_constant"() { - value = [dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64>] - } : () -> !toy.struct> + %0 = toy.struct_constant [ + dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> + ] : !toy.struct> ``` ##### `toy.struct_access` @@ -401,10 +401,10 @@ This new operation materializes the Nth element of a `struct` value. ```mlir - %0 = "toy.struct_constant"() { - value = [dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64>] - } : () -> !toy.struct> - %1 = "toy.struct_access"(%0) {index = 0 : i64} : (!toy.struct>) -> tensor<*xf64> + %0 = toy.struct_constant [ + dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> + ] : !toy.struct> + %1 = toy.struct_access %0[0] : !toy.struct> -> tensor<*xf64> ``` With these operations, we can revisit our original example: @@ -436,18 +436,21 @@ ```mlir module { func @multiply_transpose(%arg0: !toy.struct, tensor<*xf64>>) -> tensor<*xf64> { - %0 = "toy.struct_access"(%arg0) {index = 0 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> - %1 = "toy.transpose"(%0) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.struct_access"(%arg0) {index = 1 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> - %3 = "toy.transpose"(%2) : (tensor<*xf64>) -> tensor<*xf64> - %4 = "toy.mul"(%1, %3) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%4) : (tensor<*xf64>) -> () + %0 = toy.struct_access %arg0[0] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> + %1 = toy.transpose(%0 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.struct_access %arg0[1] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> + %3 = toy.transpose(%2 : tensor<*xf64>) to tensor<*xf64> + %4 = toy.mul %1, %3 : tensor<*xf64> + toy.return %4 : tensor<*xf64> } func @main() { - %0 = "toy.struct_constant"() {value = [dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>]} : () -> !toy.struct, tensor<*xf64>> - %1 = "toy.generic_call"(%0) {callee = @multiply_transpose} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> - "toy.print"(%1) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.struct_constant [ + dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, + dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + ] : !toy.struct, tensor<*xf64>> + %1 = toy.generic_call @multiply_transpose(%0) : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> + toy.print %1 : tensor<*xf64> + toy.return } } ``` @@ -462,14 +465,17 @@ ```mlir module { func @main() { - %0 = "toy.struct_constant"() {value = [dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>]} : () -> !toy.struct, tensor<*xf64>> - %1 = "toy.struct_access"(%0) {index = 0 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> - %2 = "toy.transpose"(%1) : (tensor<*xf64>) -> tensor<*xf64> - %3 = "toy.struct_access"(%0) {index = 1 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> - %4 = "toy.transpose"(%3) : (tensor<*xf64>) -> tensor<*xf64> - %5 = "toy.mul"(%2, %4) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.struct_constant [ + dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, + dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + ] : !toy.struct, tensor<*xf64>> + %1 = toy.struct_access %0[0] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> + %2 = toy.transpose(%1 : tensor<*xf64>) to tensor<*xf64> + %3 = toy.struct_access %0[1] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> + %4 = toy.transpose(%3 : tensor<*xf64>) to tensor<*xf64> + %5 = toy.mul %2, %4 : tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } } ``` @@ -524,11 +530,11 @@ ```mlir module { func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %2 = "toy.mul"(%1, %1) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%2) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %2 = toy.mul %1, %1 : tensor<3x2xf64> + toy.print %2 : tensor<3x2xf64> + toy.return } } ``` diff --git a/mlir/examples/toy/Ch2/include/toy/Ops.td b/mlir/examples/toy/Ch2/include/toy/Ops.td --- a/mlir/examples/toy/Ch2/include/toy/Ops.td +++ b/mlir/examples/toy/Ch2/include/toy/Ops.td @@ -47,9 +47,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -59,6 +58,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -87,6 +90,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -102,7 +109,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -117,6 +124,11 @@ // The generic call operation returns a single value of TensorType. let results = (outs F64Tensor); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -134,6 +146,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -149,6 +165,8 @@ // The print operation takes an input tensor to print. let arguments = (ins F64Tensor:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape"> { @@ -158,7 +176,7 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; @@ -166,6 +184,10 @@ // We expect that the reshape operation returns a statically shaped tensor. let results = (outs StaticShapeTensorOf<[F64]>); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; } def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> { @@ -188,6 +210,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -208,6 +233,10 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + // Allow building a TransposeOp with from the input operand. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value input"> diff --git a/mlir/examples/toy/Ch2/mlir/Dialect.cpp b/mlir/examples/toy/Ch2/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch2/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch2/mlir/Dialect.cpp @@ -14,6 +14,7 @@ #include "toy/Dialect.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" using namespace mlir; @@ -36,6 +37,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -49,6 +98,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verifier for the constant operation. This corresponds to the `::verify(...)` /// in the op definition. static mlir::LogicalResult verify(ConstantOp op) { diff --git a/mlir/examples/toy/Ch3/include/toy/Ops.td b/mlir/examples/toy/Ch3/include/toy/Ops.td --- a/mlir/examples/toy/Ch3/include/toy/Ops.td +++ b/mlir/examples/toy/Ch3/include/toy/Ops.td @@ -47,9 +47,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -59,6 +58,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -87,6 +90,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -102,7 +109,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -117,6 +124,11 @@ // The generic call operation returns a single value of TensorType. let results = (outs F64Tensor); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -134,6 +146,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -149,6 +165,8 @@ // The print operation takes an input tensor to print. let arguments = (ins F64Tensor:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { @@ -158,17 +176,21 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; let arguments = (ins F64Tensor:$input); - // Enabled registering canonicalization patterns with this operation. - let hasCanonicalizer = 1; - // We expect that the reshape operation returns a statically shaped tensor. let results = (outs StaticShapeTensorOf<[F64]>); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. + let hasCanonicalizer = 1; } def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> { @@ -191,6 +213,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -211,7 +236,11 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); - // Enabled registering canonicalization patterns with this operation. + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // Allow building a TransposeOp with from the input operand. diff --git a/mlir/examples/toy/Ch3/mlir/Dialect.cpp b/mlir/examples/toy/Ch3/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch3/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch3/mlir/Dialect.cpp @@ -14,6 +14,7 @@ #include "toy/Dialect.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" using namespace mlir; @@ -36,6 +37,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -49,6 +98,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verifier for the constant operation. This corresponds to the `::verify(...)` /// in the op definition. static mlir::LogicalResult verify(ConstantOp op) { diff --git a/mlir/examples/toy/Ch4/include/toy/Ops.td b/mlir/examples/toy/Ch4/include/toy/Ops.td --- a/mlir/examples/toy/Ch4/include/toy/Ops.td +++ b/mlir/examples/toy/Ch4/include/toy/Ops.td @@ -48,9 +48,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -60,6 +59,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -89,6 +92,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -110,6 +117,8 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor:$output); + let assemblyFormat = "$input attr-dict `:` type($input) `to` type($output)"; + // Set the folder bit so that we can fold redundant cast operations. let hasFolder = 1; } @@ -124,7 +133,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -139,6 +148,11 @@ // The generic call operation returns a single value of TensorType. let results = (outs F64Tensor); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -157,6 +171,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -172,6 +190,8 @@ // The print operation takes an input tensor to print. let arguments = (ins F64Tensor:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { @@ -181,15 +201,21 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; let arguments = (ins F64Tensor:$input); - let hasCanonicalizer = 1; // We expect that the reshape operation returns a statically shaped tensor. let results = (outs StaticShapeTensorOf<[F64]>); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. + let hasCanonicalizer = 1; } def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> { @@ -212,6 +238,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -232,6 +261,12 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // Allow building a TransposeOp with from the input operand. diff --git a/mlir/examples/toy/Ch4/mlir/Dialect.cpp b/mlir/examples/toy/Ch4/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch4/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch4/mlir/Dialect.cpp @@ -14,6 +14,7 @@ #include "toy/Dialect.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" #include "mlir/Transforms/InliningUtils.h" @@ -86,6 +87,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -99,6 +148,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verifier for the constant operation. This corresponds to the `::verify(...)` /// in the op definition. static mlir::LogicalResult verify(ConstantOp op) { diff --git a/mlir/examples/toy/Ch5/include/toy/Ops.td b/mlir/examples/toy/Ch5/include/toy/Ops.td --- a/mlir/examples/toy/Ch5/include/toy/Ops.td +++ b/mlir/examples/toy/Ch5/include/toy/Ops.td @@ -48,9 +48,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -60,6 +59,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -89,6 +92,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -110,6 +117,8 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor:$output); + let assemblyFormat = "$input attr-dict `:` type($input) `to` type($output)"; + // Set the folder bit so that we can fold redundant cast operations. let hasFolder = 1; } @@ -124,7 +133,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -139,6 +148,11 @@ // The generic call operation returns a single value of TensorType. let results = (outs F64Tensor); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -157,6 +171,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -173,6 +191,8 @@ // The print operation takes an input tensor to print. // We also allow a F64MemRef to enable interop during partial lowering. let arguments = (ins AnyTypeOf<[F64Tensor, F64MemRef]>:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { @@ -182,15 +202,21 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; let arguments = (ins F64Tensor:$input); - let hasCanonicalizer = 1; // We expect that the reshape operation returns a statically shaped tensor. let results = (outs StaticShapeTensorOf<[F64]>); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. + let hasCanonicalizer = 1; } def ReturnOp : Toy_Op<"return", [Terminator, HasParent<"FuncOp">]> { @@ -213,6 +239,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -233,6 +262,12 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // Allow building a TransposeOp with from the input operand. diff --git a/mlir/examples/toy/Ch5/mlir/Dialect.cpp b/mlir/examples/toy/Ch5/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch5/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch5/mlir/Dialect.cpp @@ -14,6 +14,7 @@ #include "toy/Dialect.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" #include "mlir/Transforms/InliningUtils.h" @@ -86,6 +87,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -99,6 +148,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verifier for the constant operation. This corresponds to the `::verify(...)` /// in the op definition. static mlir::LogicalResult verify(ConstantOp op) { diff --git a/mlir/examples/toy/Ch6/include/toy/Ops.td b/mlir/examples/toy/Ch6/include/toy/Ops.td --- a/mlir/examples/toy/Ch6/include/toy/Ops.td +++ b/mlir/examples/toy/Ch6/include/toy/Ops.td @@ -48,9 +48,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -60,6 +59,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -89,6 +92,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -110,6 +117,8 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor:$output); + let assemblyFormat = "$input attr-dict `:` type($input) `to` type($output)"; + // Set the folder bit so that we can fold redundant cast operations. let hasFolder = 1; } @@ -124,7 +133,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -139,6 +148,11 @@ // The generic call operation returns a single value of TensorType. let results = (outs F64Tensor); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -157,6 +171,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -173,6 +191,8 @@ // The print operation takes an input tensor to print. // We also allow a F64MemRef to enable interop during partial lowering. let arguments = (ins AnyTypeOf<[F64Tensor, F64MemRef]>:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { @@ -182,11 +202,17 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; let arguments = (ins F64Tensor:$input); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // We expect that the reshape operation returns a statically shaped tensor. @@ -213,6 +239,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -233,6 +262,12 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // Allow building a TransposeOp with from the input operand. diff --git a/mlir/examples/toy/Ch6/mlir/Dialect.cpp b/mlir/examples/toy/Ch6/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch6/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch6/mlir/Dialect.cpp @@ -14,6 +14,7 @@ #include "toy/Dialect.h" #include "mlir/IR/Builders.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" #include "mlir/Transforms/InliningUtils.h" @@ -86,6 +87,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -99,6 +148,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verifier for the constant operation. This corresponds to the `::verify(...)` /// in the op definition. static mlir::LogicalResult verify(ConstantOp op) { diff --git a/mlir/examples/toy/Ch7/include/toy/Ops.td b/mlir/examples/toy/Ch7/include/toy/Ops.td --- a/mlir/examples/toy/Ch7/include/toy/Ops.td +++ b/mlir/examples/toy/Ch7/include/toy/Ops.td @@ -57,9 +57,8 @@ to the operation as an attribute. For example: ```mlir - %0 = "toy.constant"() - { value = dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> } - : () -> tensor<2x3xf64> + %0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> + : tensor<2x3xf64> ``` }]; @@ -69,6 +68,10 @@ // The constant operation returns a single value of TensorType. let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseConstantOp(parser, result); }]; + let printer = [{ return ::print(p, *this); }]; + // Add custom build methods for the constant operation. These method populates // the `state` that MLIR uses to create operations, i.e. these are used when // using `builder.create(...)`. @@ -101,6 +104,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building an AddOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -122,6 +129,8 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor:$output); + let assemblyFormat = "$input attr-dict `:` type($input) `to` type($output)"; + // Set the folder bit so that we can fold redundant cast operations. let hasFolder = 1; } @@ -136,7 +145,7 @@ arguments expected by the callee. For example: ```mlir - %4 = "toy.generic_call"(%1, %3) {callee = @my_func} + %4 = toy.generic_call @my_func(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> ``` @@ -152,6 +161,11 @@ // StructType. let results = (outs Toy_Type); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = [{ + $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results) + }]; + // Add custom build methods for the generic call operation. let builders = [ OpBuilder<"Builder *builder, OperationState &state, " @@ -170,6 +184,10 @@ let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs); let results = (outs F64Tensor); + // Specify a parser and printer method. + let parser = [{ return ::parseBinaryOp(parser, result); }]; + let printer = [{ return ::printBinaryOp(p, *this); }]; + // Allow building a MulOp with from the two input operands. let builders = [ OpBuilder<"Builder *b, OperationState &state, Value lhs, Value rhs"> @@ -186,6 +204,8 @@ // The print operation takes an input tensor to print. // We also allow a F64MemRef to enable interop during partial lowering. let arguments = (ins AnyTypeOf<[F64Tensor, F64MemRef]>:$input); + + let assemblyFormat = "$input attr-dict `:` type($input)"; } def ReshapeOp : Toy_Op<"reshape", [NoSideEffect]> { @@ -195,11 +215,17 @@ the same number of elements but different shapes. For example: ```mlir - %0 = "toy.reshape"(%arg1) : (tensor<10xf64>) -> tensor<5x2xf64> + %0 = toy.reshape (%arg1 : tensor<10xf64>) to tensor<5x2xf64> ``` }]; let arguments = (ins F64Tensor:$input); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // We expect that the reshape operation returns a statically shaped tensor. @@ -226,6 +252,9 @@ // value must match the return type of the enclosing function. let arguments = (ins Variadic:$input); + // The return operation only emits the input in the format if it is present. + let assemblyFormat = "($input^ `:` type($input))? attr-dict "; + // Allow building a ReturnOp with no return operand. let builders = [OpBuilder< "Builder *b, OperationState &state", [{ build(b, state, llvm::None); }] @@ -247,7 +276,11 @@ }]; let arguments = (ins Toy_StructType:$input, I64Attr:$index); - let results = (outs Toy_Type); + let results = (outs Toy_Type:$output); + + let assemblyFormat = [{ + $input `[` $index `]` attr-dict `:` type($input) `->` type($output) + }]; // Allow building a StructAccessOp with just a struct value and an index. let builders = [ @@ -268,16 +301,19 @@ as an array of other constant values. For example: ```mlir - %0 = "toy.struct_constant"() { - value = [dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64>] - } : () -> !toy.struct> + %0 = toy.struct_constant [ + dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf64> + ] : !toy.struct> ``` }]; - let hasFolder = 1; let arguments = (ins ArrayAttr:$value); - let results = (outs Toy_StructType); + let results = (outs Toy_StructType:$output); + + let assemblyFormat = "$value attr-dict `:` type($output)"; + let verifier = [{ return ::verify(*this); }]; + let hasFolder = 1; } def TransposeOp : Toy_Op<"transpose", @@ -286,6 +322,12 @@ let arguments = (ins F64Tensor:$input); let results = (outs F64Tensor); + + let assemblyFormat = [{ + `(` $input `:` type($input) `)` attr-dict `to` type(results) + }]; + + // Enable registering canonicalization patterns with this operation. let hasCanonicalizer = 1; // Allow building a TransposeOp with from the input operand. diff --git a/mlir/examples/toy/Ch7/mlir/Dialect.cpp b/mlir/examples/toy/Ch7/mlir/Dialect.cpp --- a/mlir/examples/toy/Ch7/mlir/Dialect.cpp +++ b/mlir/examples/toy/Ch7/mlir/Dialect.cpp @@ -15,6 +15,7 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/DialectImplementation.h" +#include "mlir/IR/OpImplementation.h" #include "mlir/IR/StandardTypes.h" #include "mlir/Transforms/InliningUtils.h" @@ -99,6 +100,54 @@ // Toy Operations //===----------------------------------------------------------------------===// +/// A generalized parser for binary operations. This parses the different forms +/// of 'printBinaryOp' below. +static mlir::ParseResult parseBinaryOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + SmallVector operands; + llvm::SMLoc operandsLoc = parser.getCurrentLocation(); + Type type; + if (parser.parseOperandList(operands, /*requiredOperandCount=*/2) || + parser.parseOptionalAttrDict(result.attributes) || + parser.parseColonType(type)) + return mlir::failure(); + + // If the type is a function type, it contains the input and result types of + // this operation. + if (FunctionType funcType = type.dyn_cast()) { + if (parser.resolveOperands(operands, funcType.getInputs(), operandsLoc, + result.operands)) + return mlir::failure(); + result.addTypes(funcType.getResults()); + return mlir::success(); + } + + // Otherwise, the parsed type is the type of both operands and results. + if (parser.resolveOperands(operands, type, result.operands)) + return mlir::failure(); + result.addTypes(type); + return mlir::success(); +} + +/// A generalized printer for binary operations. It prints in two different +/// forms depending on if all of the types match. +static void printBinaryOp(mlir::OpAsmPrinter &printer, mlir::Operation *op) { + printer << op->getName() << " " << op->getOperands(); + printer.printOptionalAttrDict(op->getAttrs()); + printer << " : "; + + // If all of the types are the same, print the type directly. + Type resultType = *op->result_type_begin(); + if (llvm::all_of(op->getOperandTypes(), + [=](Type type) { return type == resultType; })) { + printer << resultType; + return; + } + + // Otherwise, print a functional type. + printer.printFunctionalType(op->getOperandTypes(), op->getResultTypes()); +} + //===----------------------------------------------------------------------===// // ConstantOp @@ -112,6 +161,32 @@ ConstantOp::build(builder, state, dataType, dataAttribute); } +/// The 'OpAsmPrinter' class provides a collection of methods for parsing +/// various punctuation, as well as attributes, operands, types, etc. Each of +/// these methods returns a `ParseResult`. This class is a wrapper around +/// `LogicalResult` that can be converted to a boolean `true` value on failure, +/// or `false` on success. This allows for easily chaining together a set of +/// parser rules. These rules are used to populate an `mlir::OperationState` +/// similarly to the `build` methods described above. +static mlir::ParseResult parseConstantOp(mlir::OpAsmParser &parser, + mlir::OperationState &result) { + mlir::DenseElementsAttr value; + if (parser.parseOptionalAttrDict(result.attributes) || + parser.parseAttribute(value, "value", result.attributes)) + return failure(); + + result.addTypes(value.getType()); + return success(); +} + +/// The 'OpAsmPrinter' class is a stream that will allows for formatting +/// strings, attributes, operands, types, etc. +static void print(mlir::OpAsmPrinter &printer, ConstantOp op) { + printer << "toy.constant "; + printer.printOptionalAttrDict(op.getAttrs(), /*elidedAttrs=*/{"value"}); + printer << op.value(); +} + /// Verify that the given attribute value is valid for the given type. static mlir::LogicalResult verifyConstantForType(mlir::Type type, mlir::Attribute opaqueValue, diff --git a/mlir/test/Examples/Toy/Ch2/codegen.toy b/mlir/test/Examples/Toy/Ch2/codegen.toy --- a/mlir/test/Examples/Toy/Ch2/codegen.toy +++ b/mlir/test/Examples/Toy/Ch2/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch2/scalar.toy b/mlir/test/Examples/Toy/Ch2/scalar.toy --- a/mlir/test/Examples/Toy/Ch2/scalar.toy +++ b/mlir/test/Examples/Toy/Ch2/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch3/codegen.toy b/mlir/test/Examples/Toy/Ch3/codegen.toy --- a/mlir/test/Examples/Toy/Ch3/codegen.toy +++ b/mlir/test/Examples/Toy/Ch3/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch3/scalar.toy b/mlir/test/Examples/Toy/Ch3/scalar.toy --- a/mlir/test/Examples/Toy/Ch3/scalar.toy +++ b/mlir/test/Examples/Toy/Ch3/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch4/codegen.toy b/mlir/test/Examples/Toy/Ch4/codegen.toy --- a/mlir/test/Examples/Toy/Ch4/codegen.toy +++ b/mlir/test/Examples/Toy/Ch4/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch4/scalar.toy b/mlir/test/Examples/Toy/Ch4/scalar.toy --- a/mlir/test/Examples/Toy/Ch4/scalar.toy +++ b/mlir/test/Examples/Toy/Ch4/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch4/shape_inference.mlir b/mlir/test/Examples/Toy/Ch4/shape_inference.mlir --- a/mlir/test/Examples/Toy/Ch4/shape_inference.mlir +++ b/mlir/test/Examples/Toy/Ch4/shape_inference.mlir @@ -4,28 +4,28 @@ func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> attributes { sym_visibility = "private" } { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%arg1) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.mul"(%0, %1) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%2) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.mul %0, %1 : tensor<*xf64> + toy.return %2 : tensor<*xf64> } func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.reshape"(%0) : (tensor<2x3xf64>) -> tensor<2x3xf64> - %2 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> - %3 = "toy.reshape"(%2) : (tensor<6xf64>) -> tensor<2x3xf64> - %4 = "toy.generic_call"(%1, %3) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - %5 = "toy.generic_call"(%3, %1) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } // CHECK-NOT: func @multiply_transpose // CHECK-NOT: tensor<*xf64> // CHECK-LABEL: func @main() -// CHECK: [[VAL_0:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -// CHECK: [[VAL_1:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<2x3xf64>) -> tensor<3x2xf64> -// CHECK: [[VAL_2:%.*]] = "toy.mul"([[VAL_1]], [[VAL_1]]) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> -// CHECK: "toy.print"([[VAL_2]]) : (tensor<3x2xf64>) -> () -// CHECK: "toy.return"() : () -> () +// CHECK: [[VAL_0:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +// CHECK: [[VAL_1:%.*]] = toy.transpose([[VAL_0]] : tensor<2x3xf64>) to tensor<3x2xf64> +// CHECK: [[VAL_2:%.*]] = toy.mul [[VAL_1]], [[VAL_1]] : tensor<3x2xf64> +// CHECK: toy.print [[VAL_2]] : tensor<3x2xf64> +// CHECK: toy.return diff --git a/mlir/test/Examples/Toy/Ch5/affine-lowering.mlir b/mlir/test/Examples/Toy/Ch5/affine-lowering.mlir --- a/mlir/test/Examples/Toy/Ch5/affine-lowering.mlir +++ b/mlir/test/Examples/Toy/Ch5/affine-lowering.mlir @@ -2,11 +2,11 @@ // RUN: toyc-ch5 %s -emit=mlir-affine -opt 2>&1 | FileCheck %s --check-prefix=OPT func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } // CHECK-LABEL: func @main() @@ -35,7 +35,7 @@ // CHECK: [[VAL_15:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> // CHECK: [[VAL_16:%.*]] = mulf [[VAL_14]], [[VAL_15]] : f64 // CHECK: affine.store [[VAL_16]], [[VAL_6]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> -// CHECK: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// CHECK: toy.print [[VAL_6]] : memref<3x2xf64> // CHECK: dealloc [[VAL_8]] : memref<2x3xf64> // CHECK: dealloc [[VAL_7]] : memref<3x2xf64> // CHECK: dealloc [[VAL_6]] : memref<3x2xf64> @@ -60,6 +60,6 @@ // OPT: [[VAL_10:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_9]], [[VAL_8]]] : memref<2x3xf64> // OPT: [[VAL_11:%.*]] = mulf [[VAL_10]], [[VAL_10]] : f64 // OPT: affine.store [[VAL_11]], [[VAL_6]]{{\[}}[[VAL_8]], [[VAL_9]]] : memref<3x2xf64> -// OPT: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// OPT: toy.print [[VAL_6]] : memref<3x2xf64> // OPT: dealloc [[VAL_7]] : memref<2x3xf64> // OPT: dealloc [[VAL_6]] : memref<3x2xf64> diff --git a/mlir/test/Examples/Toy/Ch5/codegen.toy b/mlir/test/Examples/Toy/Ch5/codegen.toy --- a/mlir/test/Examples/Toy/Ch5/codegen.toy +++ b/mlir/test/Examples/Toy/Ch5/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch5/scalar.toy b/mlir/test/Examples/Toy/Ch5/scalar.toy --- a/mlir/test/Examples/Toy/Ch5/scalar.toy +++ b/mlir/test/Examples/Toy/Ch5/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch5/shape_inference.mlir b/mlir/test/Examples/Toy/Ch5/shape_inference.mlir --- a/mlir/test/Examples/Toy/Ch5/shape_inference.mlir +++ b/mlir/test/Examples/Toy/Ch5/shape_inference.mlir @@ -4,28 +4,28 @@ func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> attributes { sym_visibility = "private" } { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%arg1) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.mul"(%0, %1) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%2) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.mul %0, %1 : tensor<*xf64> + toy.return %2 : tensor<*xf64> } func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.reshape"(%0) : (tensor<2x3xf64>) -> tensor<2x3xf64> - %2 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> - %3 = "toy.reshape"(%2) : (tensor<6xf64>) -> tensor<2x3xf64> - %4 = "toy.generic_call"(%1, %3) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - %5 = "toy.generic_call"(%3, %1) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } // CHECK-NOT: func @multiply_transpose // CHECK-NOT: tensor<*xf64> // CHECK-LABEL: func @main() -// CHECK: [[VAL_0:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -// CHECK: [[VAL_1:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<2x3xf64>) -> tensor<3x2xf64> -// CHECK: [[VAL_2:%.*]] = "toy.mul"([[VAL_1]], [[VAL_1]]) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> -// CHECK: "toy.print"([[VAL_2]]) : (tensor<3x2xf64>) -> () -// CHECK: "toy.return"() : () -> () +// CHECK: [[VAL_0:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +// CHECK: [[VAL_1:%.*]] = toy.transpose([[VAL_0]] : tensor<2x3xf64>) to tensor<3x2xf64> +// CHECK: [[VAL_2:%.*]] = toy.mul [[VAL_1]], [[VAL_1]] : tensor<3x2xf64> +// CHECK: toy.print [[VAL_2]] : tensor<3x2xf64> +// CHECK: toy.return diff --git a/mlir/test/Examples/Toy/Ch6/affine-lowering.mlir b/mlir/test/Examples/Toy/Ch6/affine-lowering.mlir --- a/mlir/test/Examples/Toy/Ch6/affine-lowering.mlir +++ b/mlir/test/Examples/Toy/Ch6/affine-lowering.mlir @@ -2,11 +2,11 @@ // RUN: toyc-ch6 %s -emit=mlir-affine -opt 2>&1 | FileCheck %s --check-prefix=OPT func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } // CHECK-LABEL: func @main() @@ -35,7 +35,7 @@ // CHECK: [[VAL_15:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> // CHECK: [[VAL_16:%.*]] = mulf [[VAL_14]], [[VAL_15]] : f64 // CHECK: affine.store [[VAL_16]], [[VAL_6]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> -// CHECK: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// CHECK: toy.print [[VAL_6]] : memref<3x2xf64> // CHECK: dealloc [[VAL_8]] : memref<2x3xf64> // CHECK: dealloc [[VAL_7]] : memref<3x2xf64> // CHECK: dealloc [[VAL_6]] : memref<3x2xf64> @@ -60,6 +60,6 @@ // OPT: [[VAL_10:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_9]], [[VAL_8]]] : memref<2x3xf64> // OPT: [[VAL_11:%.*]] = mulf [[VAL_10]], [[VAL_10]] : f64 // OPT: affine.store [[VAL_11]], [[VAL_6]]{{\[}}[[VAL_8]], [[VAL_9]]] : memref<3x2xf64> -// OPT: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// OPT: toy.print [[VAL_6]] : memref<3x2xf64> // OPT: dealloc [[VAL_7]] : memref<2x3xf64> // OPT: dealloc [[VAL_6]] : memref<3x2xf64> diff --git a/mlir/test/Examples/Toy/Ch6/codegen.toy b/mlir/test/Examples/Toy/Ch6/codegen.toy --- a/mlir/test/Examples/Toy/Ch6/codegen.toy +++ b/mlir/test/Examples/Toy/Ch6/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch6/llvm-lowering.mlir b/mlir/test/Examples/Toy/Ch6/llvm-lowering.mlir --- a/mlir/test/Examples/Toy/Ch6/llvm-lowering.mlir +++ b/mlir/test/Examples/Toy/Ch6/llvm-lowering.mlir @@ -1,11 +1,11 @@ // RUN: toyc-ch6 %s -emit=llvm -opt func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } // CHECK-LABEL: define void @main() diff --git a/mlir/test/Examples/Toy/Ch6/scalar.toy b/mlir/test/Examples/Toy/Ch6/scalar.toy --- a/mlir/test/Examples/Toy/Ch6/scalar.toy +++ b/mlir/test/Examples/Toy/Ch6/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch6/shape_inference.mlir b/mlir/test/Examples/Toy/Ch6/shape_inference.mlir --- a/mlir/test/Examples/Toy/Ch6/shape_inference.mlir +++ b/mlir/test/Examples/Toy/Ch6/shape_inference.mlir @@ -4,28 +4,28 @@ func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> attributes { sym_visibility = "private" } { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%arg1) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.mul"(%0, %1) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%2) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.mul %0, %1 : tensor<*xf64> + toy.return %2 : tensor<*xf64> } func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.reshape"(%0) : (tensor<2x3xf64>) -> tensor<2x3xf64> - %2 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> - %3 = "toy.reshape"(%2) : (tensor<6xf64>) -> tensor<2x3xf64> - %4 = "toy.generic_call"(%1, %3) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - %5 = "toy.generic_call"(%3, %1) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } // CHECK-NOT: func @multiply_transpose // CHECK-NOT: tensor<*xf64> // CHECK-LABEL: func @main() -// CHECK: [[VAL_0:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -// CHECK: [[VAL_1:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<2x3xf64>) -> tensor<3x2xf64> -// CHECK: [[VAL_2:%.*]] = "toy.mul"([[VAL_1]], [[VAL_1]]) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> -// CHECK: "toy.print"([[VAL_2]]) : (tensor<3x2xf64>) -> () -// CHECK: "toy.return"() : () -> () +// CHECK: [[VAL_0:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +// CHECK: [[VAL_1:%.*]] = toy.transpose([[VAL_0]] : tensor<2x3xf64>) to tensor<3x2xf64> +// CHECK: [[VAL_2:%.*]] = toy.mul [[VAL_1]], [[VAL_1]] : tensor<3x2xf64> +// CHECK: toy.print [[VAL_2]] : tensor<3x2xf64> +// CHECK: toy.return diff --git a/mlir/test/Examples/Toy/Ch7/affine-lowering.mlir b/mlir/test/Examples/Toy/Ch7/affine-lowering.mlir --- a/mlir/test/Examples/Toy/Ch7/affine-lowering.mlir +++ b/mlir/test/Examples/Toy/Ch7/affine-lowering.mlir @@ -2,11 +2,11 @@ // RUN: toyc-ch7 %s -emit=mlir-affine -opt 2>&1 | FileCheck %s --check-prefix=OPT func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } // CHECK-LABEL: func @main() @@ -35,7 +35,7 @@ // CHECK: [[VAL_15:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> // CHECK: [[VAL_16:%.*]] = mulf [[VAL_14]], [[VAL_15]] : f64 // CHECK: affine.store [[VAL_16]], [[VAL_6]]{{\[}}[[VAL_12]], [[VAL_13]]] : memref<3x2xf64> -// CHECK: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// CHECK: toy.print [[VAL_6]] : memref<3x2xf64> // CHECK: dealloc [[VAL_8]] : memref<2x3xf64> // CHECK: dealloc [[VAL_7]] : memref<3x2xf64> // CHECK: dealloc [[VAL_6]] : memref<3x2xf64> @@ -60,6 +60,6 @@ // OPT: [[VAL_10:%.*]] = affine.load [[VAL_7]]{{\[}}[[VAL_9]], [[VAL_8]]] : memref<2x3xf64> // OPT: [[VAL_11:%.*]] = mulf [[VAL_10]], [[VAL_10]] : f64 // OPT: affine.store [[VAL_11]], [[VAL_6]]{{\[}}[[VAL_8]], [[VAL_9]]] : memref<3x2xf64> -// OPT: "toy.print"([[VAL_6]]) : (memref<3x2xf64>) -> () +// OPT: toy.print [[VAL_6]] : memref<3x2xf64> // OPT: dealloc [[VAL_7]] : memref<2x3xf64> // OPT: dealloc [[VAL_6]] : memref<3x2xf64> diff --git a/mlir/test/Examples/Toy/Ch7/codegen.toy b/mlir/test/Examples/Toy/Ch7/codegen.toy --- a/mlir/test/Examples/Toy/Ch7/codegen.toy +++ b/mlir/test/Examples/Toy/Ch7/codegen.toy @@ -15,17 +15,17 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64> -# CHECK: [[VAL_2:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.mul"([[VAL_2]], [[VAL_3]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_4]]) : (tensor<*xf64>) -> () +# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.mul [[VAL_2]], [[VAL_3]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_4]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.reshape"([[VAL_5]]) : (tensor<2x3xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> -# CHECK-NEXT: [[VAL_8:%.*]] = "toy.reshape"([[VAL_7]]) : (tensor<6xf64>) -> tensor<2x3xf64> -# CHECK-NEXT: [[VAL_9:%.*]] = "toy.generic_call"([[VAL_6]], [[VAL_8]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_10:%.*]] = "toy.generic_call"([[VAL_8]], [[VAL_6]]) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_10]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_5:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# CHECK-NEXT: [[VAL_6:%.*]] = toy.reshape([[VAL_5]] : tensor<2x3xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> +# CHECK-NEXT: [[VAL_8:%.*]] = toy.reshape([[VAL_7]] : tensor<6xf64>) to tensor<2x3xf64> +# CHECK-NEXT: [[VAL_9:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]], [[VAL_8]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: [[VAL_10:%.*]] = toy.generic_call @multiply_transpose([[VAL_8]], [[VAL_6]]) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_10]] : tensor<*xf64> +# CHECK-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch7/llvm-lowering.mlir b/mlir/test/Examples/Toy/Ch7/llvm-lowering.mlir --- a/mlir/test/Examples/Toy/Ch7/llvm-lowering.mlir +++ b/mlir/test/Examples/Toy/Ch7/llvm-lowering.mlir @@ -1,11 +1,11 @@ // RUN: toyc-ch7 %s -emit=llvm -opt func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %2 = "toy.transpose"(%0) : (tensor<2x3xf64>) -> tensor<3x2xf64> - %3 = "toy.mul"(%2, %2) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> - "toy.print"(%3) : (tensor<3x2xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %2 = toy.transpose(%0 : tensor<2x3xf64>) to tensor<3x2xf64> + %3 = toy.mul %2, %2 : tensor<3x2xf64> + toy.print %3 : tensor<3x2xf64> + toy.return } // CHECK-LABEL: define void @main() diff --git a/mlir/test/Examples/Toy/Ch7/scalar.toy b/mlir/test/Examples/Toy/Ch7/scalar.toy --- a/mlir/test/Examples/Toy/Ch7/scalar.toy +++ b/mlir/test/Examples/Toy/Ch7/scalar.toy @@ -6,9 +6,9 @@ } # CHECK-LABEL: func @main() { -# CHECK-NEXT: %0 = "toy.constant"() {value = dense<5.500000e+00> : tensor} : () -> tensor -# CHECK-NEXT: %1 = "toy.reshape"(%0) : (tensor) -> tensor<2x2xf64> -# CHECK-NEXT: "toy.print"(%1) : (tensor<2x2xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: %0 = toy.constant dense<5.500000e+00> : tensor +# CHECK-NEXT: %1 = toy.reshape(%0 : tensor) to tensor<2x2xf64> +# CHECK-NEXT: toy.print %1 : tensor<2x2xf64> +# CHECK-NEXT: toy.return # CHECK-NEXT: } diff --git a/mlir/test/Examples/Toy/Ch7/shape_inference.mlir b/mlir/test/Examples/Toy/Ch7/shape_inference.mlir --- a/mlir/test/Examples/Toy/Ch7/shape_inference.mlir +++ b/mlir/test/Examples/Toy/Ch7/shape_inference.mlir @@ -4,28 +4,28 @@ func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> attributes { sym_visibility = "private" } { - %0 = "toy.transpose"(%arg0) : (tensor<*xf64>) -> tensor<*xf64> - %1 = "toy.transpose"(%arg1) : (tensor<*xf64>) -> tensor<*xf64> - %2 = "toy.mul"(%0, %1) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> - "toy.return"(%2) : (tensor<*xf64>) -> () + %0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64> + %1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64> + %2 = toy.mul %0, %1 : tensor<*xf64> + toy.return %2 : tensor<*xf64> } func @main() { - %0 = "toy.constant"() {value = dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> - %1 = "toy.reshape"(%0) : (tensor<2x3xf64>) -> tensor<2x3xf64> - %2 = "toy.constant"() {value = dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64>} : () -> tensor<6xf64> - %3 = "toy.reshape"(%2) : (tensor<6xf64>) -> tensor<2x3xf64> - %4 = "toy.generic_call"(%1, %3) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - %5 = "toy.generic_call"(%3, %1) {callee = @multiply_transpose} : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> - "toy.print"(%5) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.constant dense<[[1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> + %1 = toy.reshape(%0 : tensor<2x3xf64>) to tensor<2x3xf64> + %2 = toy.constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf64> + %3 = toy.reshape(%2 : tensor<6xf64>) to tensor<2x3xf64> + %4 = toy.generic_call @multiply_transpose(%1, %3) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + %5 = toy.generic_call @multiply_transpose(%3, %1) : (tensor<2x3xf64>, tensor<2x3xf64>) -> tensor<*xf64> + toy.print %5 : tensor<*xf64> + toy.return } // CHECK-NOT: func @multiply_transpose // CHECK-NOT: tensor<*xf64> // CHECK-LABEL: func @main() -// CHECK: [[VAL_0:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -// CHECK: [[VAL_1:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<2x3xf64>) -> tensor<3x2xf64> -// CHECK: [[VAL_2:%.*]] = "toy.mul"([[VAL_1]], [[VAL_1]]) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> -// CHECK: "toy.print"([[VAL_2]]) : (tensor<3x2xf64>) -> () -// CHECK: "toy.return"() : () -> () +// CHECK: [[VAL_0:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +// CHECK: [[VAL_1:%.*]] = toy.transpose([[VAL_0]] : tensor<2x3xf64>) to tensor<3x2xf64> +// CHECK: [[VAL_2:%.*]] = toy.mul [[VAL_1]], [[VAL_1]] : tensor<3x2xf64> +// CHECK: toy.print [[VAL_2]] : tensor<3x2xf64> +// CHECK: toy.return diff --git a/mlir/test/Examples/Toy/Ch7/struct-codegen.toy b/mlir/test/Examples/Toy/Ch7/struct-codegen.toy --- a/mlir/test/Examples/Toy/Ch7/struct-codegen.toy +++ b/mlir/test/Examples/Toy/Ch7/struct-codegen.toy @@ -24,22 +24,22 @@ # CHECK-LABEL: func @multiply_transpose( # CHECK-SAME: [[VAL_0:%.*]]: !toy.struct, tensor<*xf64>>) -> tensor<*xf64> # CHECK-SAME: attributes {sym_visibility = "private"} -# CHECK-NEXT: [[VAL_1:%.*]] = "toy.struct_access"([[VAL_0]]) {index = 0 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_2:%.*]] = "toy.transpose"([[VAL_1]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_3:%.*]] = "toy.struct_access"([[VAL_0]]) {index = 1 : i64} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_4:%.*]] = "toy.transpose"([[VAL_3]]) : (tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: [[VAL_5:%.*]] = "toy.mul"([[VAL_2]], [[VAL_4]]) : (tensor<*xf64>, tensor<*xf64>) -> tensor<*xf64> -# CHECK-NEXT: "toy.return"([[VAL_5]]) : (tensor<*xf64>) -> () +# CHECK-NEXT: [[VAL_1:%.*]] = toy.struct_access [[VAL_0]][0] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> +# CHECK-NEXT: [[VAL_2:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_3:%.*]] = toy.struct_access [[VAL_0]][1] : !toy.struct, tensor<*xf64>> -> tensor<*xf64> +# CHECK-NEXT: [[VAL_4:%.*]] = toy.transpose([[VAL_3]] : tensor<*xf64>) to tensor<*xf64> +# CHECK-NEXT: [[VAL_5:%.*]] = toy.mul [[VAL_2]], [[VAL_4]] : tensor<*xf64> +# CHECK-NEXT: toy.return [[VAL_5]] : tensor<*xf64> # CHECK-LABEL: func @main() -# CHECK-NEXT: [[VAL_6:%.*]] = "toy.struct_constant"() {value = [dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>]} : () -> !toy.struct, tensor<*xf64>> -# CHECK-NEXT: [[VAL_7:%.*]] = "toy.generic_call"([[VAL_6]]) {callee = @multiply_transpose} : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> -# CHECK-NEXT: "toy.print"([[VAL_7]]) : (tensor<*xf64>) -> () -# CHECK-NEXT: "toy.return"() : () -> () +# CHECK-NEXT: [[VAL_6:%.*]] = toy.struct_constant [dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>, dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>] : !toy.struct, tensor<*xf64>> +# CHECK-NEXT: [[VAL_7:%.*]] = toy.generic_call @multiply_transpose([[VAL_6]]) : (!toy.struct, tensor<*xf64>>) -> tensor<*xf64> +# CHECK-NEXT: toy.print [[VAL_7]] : tensor<*xf64> +# CHECK-NEXT: toy.return # OPT-LABEL: func @main() -# OPT-NEXT: [[VAL_0:%.*]] = "toy.constant"() {value = dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>} : () -> tensor<2x3xf64> -# OPT-NEXT: [[VAL_1:%.*]] = "toy.transpose"([[VAL_0]]) : (tensor<2x3xf64>) -> tensor<3x2xf64> -# OPT-NEXT: [[VAL_2:%.*]] = "toy.mul"([[VAL_1]], [[VAL_1]]) : (tensor<3x2xf64>, tensor<3x2xf64>) -> tensor<3x2xf64> -# OPT-NEXT: "toy.print"([[VAL_2]]) : (tensor<3x2xf64>) -> () -# OPT-NEXT: "toy.return"() : () -> () +# OPT-NEXT: [[VAL_0:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64> +# OPT-NEXT: [[VAL_1:%.*]] = toy.transpose([[VAL_0]] : tensor<2x3xf64>) to tensor<3x2xf64> +# OPT-NEXT: [[VAL_2:%.*]] = toy.mul [[VAL_1]], [[VAL_1]] : tensor<3x2xf64> +# OPT-NEXT: toy.print [[VAL_2]] : tensor<3x2xf64> +# OPT-NEXT: toy.return diff --git a/mlir/test/Examples/Toy/Ch7/struct-opt.mlir b/mlir/test/Examples/Toy/Ch7/struct-opt.mlir --- a/mlir/test/Examples/Toy/Ch7/struct-opt.mlir +++ b/mlir/test/Examples/Toy/Ch7/struct-opt.mlir @@ -1,16 +1,15 @@ // RUN: toyc-ch7 %s -emit=mlir -opt 2>&1 | FileCheck %s func @main() { - %0 = "toy.struct_constant"() { - value = [[dense<4.000000e+00> : tensor<2x2xf64>], dense<4.000000e+00> : tensor<2x2xf64>] - } : () -> !toy.struct>, tensor<*xf64>> - %1 = "toy.struct_access"(%0) {index = 0 : i64} : (!toy.struct>, tensor<*xf64>>) -> !toy.struct> - %2 = "toy.struct_access"(%1) {index = 0 : i64} : (!toy.struct>) -> tensor<*xf64> - "toy.print"(%2) : (tensor<*xf64>) -> () - "toy.return"() : () -> () + %0 = toy.struct_constant [ + [dense<4.000000e+00> : tensor<2x2xf64>], dense<4.000000e+00> : tensor<2x2xf64> + ] : !toy.struct>, tensor<*xf64>> + %1 = toy.struct_access %0[0] : !toy.struct>, tensor<*xf64>> -> !toy.struct> + %2 = toy.struct_access %1[0] : !toy.struct> -> tensor<*xf64> + toy.print %2 : tensor<*xf64> + toy.return } // CHECK-LABEL: func @main -// CHECK-NEXT: %[[CST:.*]] = "toy.constant" -// CHECK-SAME: dense<4.0 -// CHECK-NEXT: "toy.print"(%[[CST]]) +// CHECK-NEXT: %[[CST:.*]] = toy.constant dense<4.0 +// CHECK-NEXT: toy.print %[[CST]]