Verify that attribute type and constant op return type matches.
authorJacques Pienaar <jpienaar@google.com>
Wed, 8 May 2019 19:11:10 +0000 (12:11 -0700)
committerMehdi Amini <joker.eph@gmail.com>
Sat, 11 May 2019 02:24:14 +0000 (19:24 -0700)
--

PiperOrigin-RevId: 247263129

mlir/lib/StandardOps/Ops.cpp
mlir/test/IR/invalid-ops.mlir
mlir/test/IR/memory-ops.mlir
mlir/test/Transforms/Vectorize/vector_utils.mlir

index 9de36a7..c89d66d 100644 (file)
@@ -1164,22 +1164,21 @@ static LogicalResult verify(ConstantOp &op) {
     return op.emitOpError("requires a 'value' attribute");
 
   auto type = op.getType();
-  if (type.isa<IntegerType>() || type.isIndex()) {
-    auto intAttr = value.dyn_cast<IntegerAttr>();
-    if (!intAttr)
-      return op.emitOpError(
-          "requires 'value' to be an integer for an integer result type");
+  if (type != value.getType())
+    return op.emitOpError() << "requires attribute's type (" << value.getType()
+                            << ") to match op's return type (" << type << ")";
 
+  if (type.isa<IndexType>())
+    return success();
+
+  if (auto intAttr = value.dyn_cast<IntegerAttr>()) {
     // If the type has a known bitwidth we verify that the value can be
     // represented with the given bitwidth.
-    if (!type.isIndex()) {
-      auto bitwidth = type.cast<IntegerType>().getWidth();
-      auto intVal = intAttr.getValue();
-      if (!intVal.isSignedIntN(bitwidth) && !intVal.isIntN(bitwidth))
-        return op.emitOpError(
-            "requires 'value' to be an integer within the range "
-            "of the integer result type");
-    }
+    auto bitwidth = type.cast<IntegerType>().getWidth();
+    auto intVal = intAttr.getValue();
+    if (!intVal.isSignedIntN(bitwidth) && !intVal.isIntN(bitwidth))
+      return op.emitOpError("requires 'value' to be an integer within the "
+                            "range of the integer result type");
     return success();
   }
 
@@ -1201,10 +1200,6 @@ static LogicalResult verify(ConstantOp &op) {
     return success();
   }
 
-  if (value.getType() != type)
-    return op.emitOpError("requires the type of the 'value' attribute to match "
-                          "that of the operation result");
-
   return op.emitOpError(
       "requires a result type that aligns with the 'value' attribute");
 }
index b2bd89b..419c6ad 100644 (file)
@@ -26,7 +26,7 @@ func @dim3(tensor<1xf32>) {
 
 func @constant() {
 ^bb:
-  %x = "std.constant"(){value: "xyz"} : () -> i32 // expected-error {{'std.constant' op requires 'value' to be an integer for an integer result type}}
+  %x = "std.constant"(){value: "xyz"} : () -> i32 // expected-error {{requires attribute's type (none) to match op's return type (i32)}}
   return
 }
 
@@ -34,15 +34,22 @@ func @constant() {
 
 func @constant_out_of_range() {
 ^bb:
-  %x = "std.constant"(){value: 100} : () -> i1 // expected-error {{'std.constant' op requires 'value' to be an integer within the range of the integer result type}}
+  %x = "std.constant"(){value: 100} : () -> i1 // expected-error {{requires attribute's type (i64) to match op's return type (i1)}}
   return
 }
 
 // -----
 
+func @constant_wrong_type() {
+^bb:
+  %x = "std.constant"(){value: 10.} : () -> f32 // expected-error {{requires attribute's type (f64) to match op's return type (f32)}}
+  return
+}
+
+// -----
 func @affine_apply_no_map() {
 ^bb0:
-  %i = "std.constant"() {value: 0} : () -> index
+  %i = constant 0 : index
   %x = "affine.apply" (%i) { } : (index) -> (index) //  expected-error {{'affine.apply' op requires an affine map}}
   return
 }
@@ -51,7 +58,7 @@ func @affine_apply_no_map() {
 
 func @affine_apply_wrong_operand_count() {
 ^bb0:
-  %i = "std.constant"() {value: 0} : () -> index
+  %i = constant 0 : index
   %x = "affine.apply" (%i) {map: (d0, d1) -> ((d0 + 1), (d1 + 2))} : (index) -> (index) //  expected-error {{'affine.apply' op operand count and affine map dimension and symbol count must match}}
   return
 }
@@ -60,8 +67,8 @@ func @affine_apply_wrong_operand_count() {
 
 func @affine_apply_wrong_result_count() {
 ^bb0:
-  %i = "std.constant"() {value: 0} : () -> index
-  %j = "std.constant"() {value: 1} : () -> index
+  %i = constant 0 : index
+  %j = constant 1 : index
   %x = "affine.apply" (%i, %j) {map: (d0, d1) -> ((d0 + 1), (d1 + 2))} : (index,index) -> (index) //  expected-error {{'affine.apply' op mapping must produce one value}}
   return
 }
@@ -86,7 +93,7 @@ func @unknown_std_op() {
 
 func @bad_alloc_wrong_dynamic_dim_count() {
 ^bb0:
-  %0 = "std.constant"() {value: 7} : () -> index
+  %0 = constant 7 : index
   // Test alloc with wrong number of dynamic dimensions.
   %1 = alloc(%0)[%1] : memref<2x4xf32, (d0, d1)[s0] -> ((d0 + s0), d1), 1> // expected-error {{custom op 'alloc' dimension operand count does not equal memref dynamic dimension count}}
   return
@@ -96,7 +103,7 @@ func @bad_alloc_wrong_dynamic_dim_count() {
 
 func @bad_alloc_wrong_symbol_count() {
 ^bb0:
-  %0 = "std.constant"() {value: 7} : () -> index
+  %0 = constant 7 : index
   // Test alloc with wrong number of symbols
   %1 = alloc(%0) : memref<2x?xf32, (d0, d1)[s0] -> ((d0 + s0), d1), 1> // expected-error {{operand count does not equal dimension plus symbol operand count}}
   return
@@ -107,8 +114,8 @@ func @bad_alloc_wrong_symbol_count() {
 func @test_store_zero_results() {
 ^bb0:
   %0 = alloc() : memref<1024x64xf32, (d0, d1) -> (d0, d1), 1>
-  %1 = "std.constant"() {value: 0} : () -> index
-  %2 = "std.constant"() {value: 1} : () -> index
+  %1 = constant 0 : index
+  %2 = constant 1 : index
   %3 = load %0[%1, %2] : memref<1024x64xf32, (d0, d1) -> (d0, d1), 1>
   // Test that store returns zero results.
   %4 = store %3, %0[%1, %2] : memref<1024x64xf32, (d0, d1) -> (d0, d1), 1> // expected-error {{cannot name an operation with no results}}
@@ -141,20 +148,6 @@ func @intlimit2() {
 
 // -----
 
-func @func_constant() {
-  %x = "std.constant"(){value: "xyz"} : () -> i32 // expected-error {{'std.constant' op requires 'value' to be an integer for an integer result type}}
-  return
-}
-
-// -----
-
-func @func_constant_out_of_range() {
-  %x = "std.constant"(){value: 100} : () -> i1 // expected-error {{'std.constant' op requires 'value' to be an integer within the range of the integer result type}}
-  return
-}
-
-// -----
-
 func @calls(%arg0: i32) {
   %x = call @calls() : () -> i32  // expected-error {{reference to function with mismatched type}}
   return
index b078c35..6c5ec07 100644 (file)
@@ -9,8 +9,8 @@ func @alloc() {
   // CHECK: %0 = alloc() : memref<1024x64xf32, 1>
   %0 = alloc() : memref<1024x64xf32, (d0, d1) -> (d0, d1), 1>
 
-  %c0 = "std.constant"() {value: 0} : () -> index
-  %c1 = "std.constant"() {value: 1} : () -> index
+  %c0 = "std.constant"() {value: 0: index} : () -> index
+  %c1 = "std.constant"() {value: 1: index} : () -> index
 
   // Test alloc with dynamic dimensions.
   // CHECK: %1 = alloc(%c0, %c1) : memref<?x?xf32, 1>
index ceb295b..cec3650 100644 (file)
@@ -17,7 +17,7 @@ func @vector_add_2d(%arg0: index, %arg1: index) -> f32 {
   // CHECK:matched: {{.*}} constant splat{{.*}} with shape ratio: 1, 3, 7, 2, 1
   %cst_a = constant splat<vector<1x3x7x8x8xf32>, 1.000000e+00> : vector<1x3x7x8x8xf32>
   // CHECK-NOT:matched: {{.*}} constant splat{{.*}} with shape ratio: 1, 3, 7, 1{{.*}}
-  %cst_b = constant splat<vector<1x3x7x4x4xf32>, 1.000000e+00> : vector<1x3x7x8x8xf32>
+  %cst_b = constant splat<vector<1x3x7x4x4xf32>, 1.000000e+00> : vector<1x3x7x4x4xf32>
   // TEST-3x4x5x8:matched: {{.*}} constant splat{{.*}} with shape ratio: 3, 2, 1, 4
   %cst_c = constant splat<vector<3x4x5x8xf32>, 1.000000e+00> : vector<3x4x5x8xf32>
   // TEST-3x4x4x8-NOT:matched: {{.*}} constant splat{{.*}} with shape ratio{{.*}}
@@ -34,4 +34,4 @@ func @vector_add_2d(%arg0: index, %arg1: index) -> f32 {
   %c42 = constant 42 : index
   %9 = load %2[%c7, %c42] : memref<?x?xf32>
   return %9 : f32
-}
\ No newline at end of file
+}