This new features enabled to dedicate custom storage inline within operations.
This storage can be used as an alternative to attributes to store data that is
specific to an operation. Attribute can also be stored inside the properties
storage if desired, but any kind of data can be present as well. This offers
a way to store and mutate data without uniquing in the Context like Attribute.
See the OpPropertiesTest.cpp for an example where a struct with a
std::vector<> is attached to an operation and mutated in-place:
struct TestProperties {
int a = -1;
float b = -1.;
std::vector<int64_t> array = {-33};
};
More complex scheme (including reference-counting) are also possible.
The only constraint to enable storing a C++ object as "properties" on an
operation is to implement three functions:
- convert from the candidate object to an Attribute
- convert from the Attribute to the candidate object
- hash the object
Optional the parsing and printing can also be customized with 2 extra
functions.
A new options is introduced to ODS to allow dialects to specify:
let usePropertiesForAttributes = 1;
When set to true, the inherent attributes for all the ops in this dialect
will be using properties instead of being stored alongside discardable
attributes.
The TestDialect showcases this feature.
Another change is that we introduce new APIs on the Operation class
to access separately the inherent attributes from the discardable ones.
We envision deprecating and removing the `getAttr()`, `getAttrsDictionary()`,
and other similar method which don't make the distinction explicit, leading
to an entirely separate namespace for discardable attributes.
Recommit d572cd1b067f after fixing python bindings build.
Differential Revision: https://reviews.llvm.org/D141742
1441 lines
57 KiB
MLIR
1441 lines
57 KiB
MLIR
// RUN: mlir-opt -allow-unregistered-dialect %s | FileCheck %s
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1, d2, d3, d4)[s0] -> (d0, d1, d2, d4, d3)>
|
|
#map = affine_map<(d0, d1, d2, d3, d4)[s0] -> (d0, d1, d2, d4, d3)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0) -> (d0)>
|
|
#map1 = affine_map<(d0) -> (d0)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1, d2) -> (d0, d1, d2)>
|
|
#map2 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1, d2) -> (d1, d0, d2)>
|
|
#map3 = affine_map<(d0, d1, d2) -> (d1, d0, d2)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<()[s0] -> (0, s0 - 1)>
|
|
#inline_map_minmax_loop1 = affine_map<()[s0] -> (0, s0 - 1)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<()[s0] -> (100, s0 + 1)>
|
|
#inline_map_minmax_loop2 = affine_map<()[s0] -> (100, s0 + 1)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1)[s0] -> (d0 + d1 + s0)>
|
|
#bound_map1 = affine_map<(i, j)[s] -> (i + j + s)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0, d1) -> (d0 + d1)>
|
|
#inline_map_loop_bounds2 = affine_map<(d0, d1) -> (d0 + d1)>
|
|
|
|
// CHECK-DAG: #map{{[0-9]*}} = affine_map<(d0)[s0] -> (d0 + s0, d0 - s0)>
|
|
#bound_map2 = affine_map<(i)[s] -> (i + s, i - s)>
|
|
|
|
// All maps appear in arbitrary order before all sets, in arbitrary order.
|
|
// CHECK-NOT: Placeholder
|
|
|
|
// CHECK-DAG: #set{{[0-9]*}} = affine_set<(d0)[s0, s1] : (d0 >= 0, -d0 + s0 >= 0, s0 - 5 == 0, -d0 + s1 + 1 >= 0)>
|
|
#set0 = affine_set<(i)[N, M] : (i >= 0, -i + N >= 0, N - 5 == 0, -i + M + 1 >= 0)>
|
|
|
|
// CHECK-DAG: #set{{[0-9]*}} = affine_set<(d0, d1)[s0] : (d0 >= 0, d1 >= 0)>
|
|
#set1 = affine_set<(d0, d1)[s0] : (d0 >= 0, d1 >= 0)>
|
|
|
|
// CHECK-DAG: #set{{[0-9]*}} = affine_set<(d0) : (d0 - 1 == 0)>
|
|
#set2 = affine_set<(d0) : (d0 - 1 == 0)>
|
|
|
|
// CHECK-DAG: [[$SET_TRUE:#set[0-9]+]] = affine_set<() : (0 == 0)>
|
|
|
|
// CHECK-DAG: #set{{[0-9]*}} = affine_set<(d0)[s0] : (d0 - 2 >= 0, -d0 + 4 >= 0)>
|
|
|
|
// CHECK: func private @foo(i32, i64) -> f32
|
|
func.func private @foo(i32, i64) -> f32
|
|
|
|
// CHECK: func private @bar()
|
|
func.func private @bar() -> ()
|
|
|
|
// CHECK: func private @baz() -> (i1, index, f32)
|
|
func.func private @baz() -> (i1, index, f32)
|
|
|
|
// CHECK: func private @missingReturn()
|
|
func.func private @missingReturn()
|
|
|
|
// CHECK: func private @int_types(i0, i1, i2, i4, i7, i87) -> (i1, index, i19)
|
|
func.func private @int_types(i0, i1, i2, i4, i7, i87) -> (i1, index, i19)
|
|
|
|
// CHECK: func private @sint_types(si2, si4) -> (si7, si1023)
|
|
func.func private @sint_types(si2, si4) -> (si7, si1023)
|
|
|
|
// CHECK: func private @uint_types(ui2, ui4) -> (ui7, ui1023)
|
|
func.func private @uint_types(ui2, ui4) -> (ui7, ui1023)
|
|
|
|
// CHECK: func private @float_types(f80, f128)
|
|
func.func private @float_types(f80, f128)
|
|
|
|
// CHECK: func private @vectors(vector<f32>, vector<1xf32>, vector<2x4xf32>)
|
|
func.func private @vectors(vector<f32>, vector<1 x f32>, vector<2x4xf32>)
|
|
|
|
// CHECK: func private @tensors(tensor<*xf32>, tensor<*xvector<2x4xf32>>, tensor<1x?x4x?x?xi32>, tensor<i8>)
|
|
func.func private @tensors(tensor<* x f32>, tensor<* x vector<2x4xf32>>,
|
|
tensor<1x?x4x?x?xi32>, tensor<i8>)
|
|
|
|
// CHECK: func private @tensor_encoding(tensor<16x32xf64, "sparse">)
|
|
func.func private @tensor_encoding(tensor<16x32xf64, "sparse">)
|
|
|
|
// CHECK: func private @large_shape_dimension(tensor<9223372036854775807xf32>)
|
|
func.func private @large_shape_dimension(tensor<9223372036854775807xf32>)
|
|
|
|
// CHECK: func private @functions((memref<1x?x4x?x?xi32, #map>, memref<8xi8>) -> (), () -> ())
|
|
func.func private @functions((memref<1x?x4x?x?xi32, #map, 0>, memref<8xi8, #map1, 0>) -> (), ()->())
|
|
|
|
// CHECK: func private @memrefs2(memref<2x4x8xi8, 1>)
|
|
func.func private @memrefs2(memref<2x4x8xi8, #map2, 1>)
|
|
|
|
// CHECK: func private @memrefs3(memref<2x4x8xi8>)
|
|
func.func private @memrefs3(memref<2x4x8xi8, affine_map<(d0, d1, d2) -> (d0, d1, d2)>>)
|
|
|
|
// CHECK: func private @memrefs_drop_triv_id_inline(memref<2xi8>)
|
|
func.func private @memrefs_drop_triv_id_inline(memref<2xi8, affine_map<(d0) -> (d0)>>)
|
|
|
|
// CHECK: func private @memrefs_drop_triv_id_inline0(memref<2xi8>)
|
|
func.func private @memrefs_drop_triv_id_inline0(memref<2xi8, affine_map<(d0) -> (d0)>, 0>)
|
|
|
|
// CHECK: func private @memrefs_drop_triv_id_inline1(memref<2xi8, 1>)
|
|
func.func private @memrefs_drop_triv_id_inline1(memref<2xi8, affine_map<(d0) -> (d0)>, 1>)
|
|
|
|
// Test memref with custom memory space
|
|
|
|
// CHECK: func private @memrefs_nomap_nospace(memref<5x6x7xf32>)
|
|
func.func private @memrefs_nomap_nospace(memref<5x6x7xf32>)
|
|
|
|
// CHECK: func private @memrefs_map_nospace(memref<5x6x7xf32, #map{{[0-9]*}}>)
|
|
func.func private @memrefs_map_nospace(memref<5x6x7xf32, #map3>)
|
|
|
|
// CHECK: func private @memrefs_nomap_intspace(memref<5x6x7xf32, 3>)
|
|
func.func private @memrefs_nomap_intspace(memref<5x6x7xf32, 3>)
|
|
|
|
// CHECK: func private @memrefs_map_intspace(memref<5x6x7xf32, #map{{[0-9]*}}, 5>)
|
|
func.func private @memrefs_map_intspace(memref<5x6x7xf32, #map3, 5>)
|
|
|
|
// CHECK: func private @memrefs_nomap_strspace(memref<5x6x7xf32, "local">)
|
|
func.func private @memrefs_nomap_strspace(memref<5x6x7xf32, "local">)
|
|
|
|
// CHECK: func private @memrefs_map_strspace(memref<5x6x7xf32, #map{{[0-9]*}}, "private">)
|
|
func.func private @memrefs_map_strspace(memref<5x6x7xf32, #map3, "private">)
|
|
|
|
// CHECK: func private @memrefs_nomap_dictspace(memref<5x6x7xf32, {memSpace = "special", subIndex = 1 : i64}>)
|
|
func.func private @memrefs_nomap_dictspace(memref<5x6x7xf32, {memSpace = "special", subIndex = 1}>)
|
|
|
|
// CHECK: func private @memrefs_map_dictspace(memref<5x6x7xf32, #map{{[0-9]*}}, {memSpace = "special", subIndex = 3 : i64}>)
|
|
func.func private @memrefs_map_dictspace(memref<5x6x7xf32, #map3, {memSpace = "special", subIndex = 3}>)
|
|
|
|
// CHECK: func private @complex_types(complex<i1>) -> complex<f32>
|
|
func.func private @complex_types(complex<i1>) -> complex<f32>
|
|
|
|
// CHECK: func private @memref_with_index_elems(memref<1x?xindex>)
|
|
func.func private @memref_with_index_elems(memref<1x?xindex>)
|
|
|
|
// CHECK: func private @memref_with_complex_elems(memref<1x?xcomplex<f32>>)
|
|
func.func private @memref_with_complex_elems(memref<1x?xcomplex<f32>>)
|
|
|
|
// CHECK: func private @memref_with_vector_elems(memref<1x?xvector<10xf32>>)
|
|
func.func private @memref_with_vector_elems(memref<1x?xvector<10xf32>>)
|
|
|
|
// CHECK: func private @memref_with_custom_elem(memref<1x?x!test.memref_element>)
|
|
func.func private @memref_with_custom_elem(memref<1x?x!test.memref_element>)
|
|
|
|
// CHECK: func private @memref_of_memref(memref<1xmemref<1xf64>>)
|
|
func.func private @memref_of_memref(memref<1xmemref<1xf64>>)
|
|
|
|
// CHECK: func private @memref_of_unranked_memref(memref<1xmemref<*xf32>>)
|
|
func.func private @memref_of_unranked_memref(memref<1xmemref<*xf32>>)
|
|
|
|
// CHECK: func private @unranked_memref_of_memref(memref<*xmemref<1xf32>>)
|
|
func.func private @unranked_memref_of_memref(memref<*xmemref<1xf32>>)
|
|
|
|
// CHECK: func private @unranked_memref_of_unranked_memref(memref<*xmemref<*xi32>>)
|
|
func.func private @unranked_memref_of_unranked_memref(memref<*xmemref<*xi32>>)
|
|
|
|
// CHECK: func private @unranked_memref_with_complex_elems(memref<*xcomplex<f32>>)
|
|
func.func private @unranked_memref_with_complex_elems(memref<*xcomplex<f32>>)
|
|
|
|
// CHECK: func private @unranked_memref_with_index_elems(memref<*xindex>)
|
|
func.func private @unranked_memref_with_index_elems(memref<*xindex>)
|
|
|
|
// CHECK: func private @unranked_memref_with_vector_elems(memref<*xvector<10xf32>>)
|
|
func.func private @unranked_memref_with_vector_elems(memref<*xvector<10xf32>>)
|
|
|
|
// CHECK-LABEL: func @simpleCFG(%{{.*}}: i32, %{{.*}}: f32) -> i1 {
|
|
func.func @simpleCFG(%arg0: i32, %f: f32) -> i1 {
|
|
// CHECK: %{{.*}} = "foo"() : () -> i64
|
|
%1 = "foo"() : ()->i64
|
|
// CHECK: "bar"(%{{.*}}) : (i64) -> (i1, i1, i1)
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
// CHECK: return %{{.*}}#1
|
|
return %2#1 : i1
|
|
// CHECK: }
|
|
}
|
|
|
|
// CHECK-LABEL: func @simpleCFGUsingBBArgs(%{{.*}}: i32, %{{.*}}: i64) {
|
|
func.func @simpleCFGUsingBBArgs(i32, i64) {
|
|
^bb42 (%arg0: i32, %f: i64):
|
|
// CHECK: "bar"(%{{.*}}) : (i64) -> (i1, i1, i1)
|
|
%2:3 = "bar"(%f) : (i64) -> (i1,i1,i1)
|
|
// CHECK: return{{$}}
|
|
return
|
|
// CHECK: }
|
|
}
|
|
|
|
// CHECK-LABEL: func @block_label_empty_list
|
|
func.func @block_label_empty_list() {
|
|
^bb0():
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @multiblock() {
|
|
func.func @multiblock() {
|
|
return // CHECK: return
|
|
^bb1: // CHECK: ^bb1: // no predecessors
|
|
cf.br ^bb4 // CHECK: cf.br ^bb3
|
|
^bb2: // CHECK: ^bb2: // pred: ^bb2
|
|
cf.br ^bb2 // CHECK: cf.br ^bb2
|
|
^bb4: // CHECK: ^bb3: // pred: ^bb1
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @emptyMLF() {
|
|
func.func @emptyMLF() {
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @func_with_one_arg(%{{.*}}: i1) -> i2 {
|
|
func.func @func_with_one_arg(%c : i1) -> i2 {
|
|
// CHECK: %{{.*}} = "foo"(%{{.*}}) : (i1) -> i2
|
|
%b = "foo"(%c) : (i1) -> (i2)
|
|
return %b : i2 // CHECK: return %{{.*}} : i2
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @func_with_two_args(%{{.*}}: f16, %{{.*}}: i8) -> (i1, i32) {
|
|
func.func @func_with_two_args(%a : f16, %b : i8) -> (i1, i32) {
|
|
// CHECK: %{{.*}}:2 = "foo"(%{{.*}}, %{{.*}}) : (f16, i8) -> (i1, i32)
|
|
%c:2 = "foo"(%a, %b) : (f16, i8)->(i1, i32)
|
|
return %c#0, %c#1 : i1, i32 // CHECK: return %{{.*}}#0, %{{.*}}#1 : i1, i32
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @second_order_func() -> (() -> ()) {
|
|
func.func @second_order_func() -> (() -> ()) {
|
|
// CHECK-NEXT: %{{.*}} = constant @emptyMLF : () -> ()
|
|
%c = constant @emptyMLF : () -> ()
|
|
// CHECK-NEXT: return %{{.*}} : () -> ()
|
|
return %c : () -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: func @third_order_func() -> (() -> (() -> ())) {
|
|
func.func @third_order_func() -> (() -> (() -> ())) {
|
|
// CHECK-NEXT: %{{.*}} = constant @second_order_func : () -> (() -> ())
|
|
%c = constant @second_order_func : () -> (() -> ())
|
|
// CHECK-NEXT: return %{{.*}} : () -> (() -> ())
|
|
return %c : () -> (() -> ())
|
|
}
|
|
|
|
// CHECK-LABEL: func @identity_functor(%{{.*}}: () -> ()) -> (() -> ()) {
|
|
func.func @identity_functor(%a : () -> ()) -> (() -> ()) {
|
|
// CHECK-NEXT: return %{{.*}} : () -> ()
|
|
return %a : () -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: func @func_ops_in_loop() {
|
|
func.func @func_ops_in_loop() {
|
|
// CHECK: %{{.*}} = "foo"() : () -> i64
|
|
%a = "foo"() : ()->i64
|
|
// CHECK: affine.for %{{.*}} = 1 to 10 {
|
|
affine.for %i = 1 to 10 {
|
|
// CHECK: %{{.*}} = "doo"() : () -> f32
|
|
%b = "doo"() : ()->f32
|
|
// CHECK: "bar"(%{{.*}}, %{{.*}}) : (i64, f32) -> ()
|
|
"bar"(%a, %b) : (i64, f32) -> ()
|
|
// CHECK: }
|
|
}
|
|
// CHECK: return
|
|
return
|
|
// CHECK: }
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: func @loops() {
|
|
func.func @loops() {
|
|
// CHECK: affine.for %{{.*}} = 1 to 100 step 2 {
|
|
affine.for %i = 1 to 100 step 2 {
|
|
// CHECK: affine.for %{{.*}} = 1 to 200 {
|
|
affine.for %j = 1 to 200 {
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @complex_loops() {
|
|
func.func @complex_loops() {
|
|
affine.for %i1 = 1 to 100 { // CHECK: affine.for %{{.*}} = 1 to 100 {
|
|
affine.for %j1 = 1 to 100 { // CHECK: affine.for %{{.*}} = 1 to 100 {
|
|
// CHECK: "foo"(%{{.*}}, %{{.*}}) : (index, index) -> ()
|
|
"foo"(%i1, %j1) : (index,index) -> ()
|
|
} // CHECK: }
|
|
"boo"() : () -> () // CHECK: "boo"() : () -> ()
|
|
affine.for %j2 = 1 to 10 { // CHECK: affine.for %{{.*}} = 1 to 10 {
|
|
affine.for %k2 = 1 to 10 { // CHECK: affine.for %{{.*}} = 1 to 10 {
|
|
"goo"() : () -> () // CHECK: "goo"() : () -> ()
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK: func @triang_loop(%{{.*}}: index, %{{.*}}: memref<?x?xi32>) {
|
|
func.func @triang_loop(%arg0: index, %arg1: memref<?x?xi32>) {
|
|
%c = arith.constant 0 : i32 // CHECK: %{{.*}} = arith.constant 0 : i32
|
|
affine.for %i0 = 1 to %arg0 { // CHECK: affine.for %{{.*}} = 1 to %{{.*}} {
|
|
affine.for %i1 = affine_map<(d0)[]->(d0)>(%i0)[] to %arg0 { // CHECK: affine.for %{{.*}} = #map{{[0-9]*}}(%{{.*}}) to %{{.*}} {
|
|
memref.store %c, %arg1[%i0, %i1] : memref<?x?xi32> // CHECK: memref.store %{{.*}}, %{{.*}}[%{{.*}}, %{{.*}}]
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK: func @minmax_loop(%{{.*}}: index, %{{.*}}: index, %{{.*}}: memref<100xf32>) {
|
|
func.func @minmax_loop(%arg0: index, %arg1: index, %arg2: memref<100xf32>) {
|
|
// CHECK: affine.for %{{.*}} = max #map{{.*}}()[%{{.*}}] to min #map{{.*}}()[%{{.*}}] {
|
|
affine.for %i0 = max affine_map<()[s]->(0,s-1)>()[%arg0] to min affine_map<()[s]->(100,s+1)>()[%arg1] {
|
|
// CHECK: "foo"(%{{.*}}, %{{.*}}) : (memref<100xf32>, index) -> ()
|
|
"foo"(%arg2, %i0) : (memref<100xf32>, index) -> ()
|
|
} // CHECK: }
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @loop_bounds(%{{.*}}: index) {
|
|
func.func @loop_bounds(%N : index) {
|
|
// CHECK: %{{.*}} = "foo"(%{{.*}}) : (index) -> index
|
|
%s = "foo"(%N) : (index) -> index
|
|
// CHECK: affine.for %{{.*}} = %{{.*}} to %{{.*}}
|
|
affine.for %i = %s to %N {
|
|
// CHECK: affine.for %{{.*}} = #map{{[0-9]*}}(%{{.*}}) to 0
|
|
affine.for %j = affine_map<(d0)[]->(d0)>(%i)[] to 0 step 1 {
|
|
// CHECK: %{{.*}} = affine.apply #map{{.*}}(%{{.*}}, %{{.*}})[%{{.*}}]
|
|
%w1 = affine.apply affine_map<(d0, d1)[s0] -> (d0+d1)> (%i, %j) [%s]
|
|
// CHECK: %{{.*}} = affine.apply #map{{.*}}(%{{.*}}, %{{.*}})[%{{.*}}]
|
|
%w2 = affine.apply affine_map<(d0, d1)[s0] -> (s0+1)> (%i, %j) [%s]
|
|
// CHECK: affine.for %{{.*}} = #map{{.*}}(%{{.*}}, %{{.*}})[%{{.*}}] to #map{{.*}}(%{{.*}}, %{{.*}})[%{{.*}}] {
|
|
affine.for %k = #bound_map1 (%w1, %i)[%N] to affine_map<(i, j)[s] -> (i + j + s)> (%w2, %j)[%s] {
|
|
// CHECK: "foo"(%{{.*}}, %{{.*}}, %{{.*}}) : (index, index, index) -> ()
|
|
"foo"(%i, %j, %k) : (index, index, index)->()
|
|
// CHECK: %{{.*}} = arith.constant 30 : index
|
|
%c = arith.constant 30 : index
|
|
// CHECK: %{{.*}} = affine.apply #map{{.*}}(%{{.*}}, %{{.*}})
|
|
%u = affine.apply affine_map<(d0, d1)->(d0+d1)> (%N, %c)
|
|
// CHECK: affine.for %{{.*}} = max #map{{.*}}(%{{.*}})[%{{.*}}] to min #map{{.*}}(%{{.*}})[%{{.*}}] {
|
|
affine.for %l = max #bound_map2(%i)[%u] to min #bound_map2(%k)[%c] {
|
|
// CHECK: "bar"(%{{.*}}) : (index) -> ()
|
|
"bar"(%l) : (index) -> ()
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
} // CHECK: }
|
|
return // CHECK: return
|
|
} // CHECK: }
|
|
|
|
// CHECK-LABEL: func @ifinst(%{{.*}}: index) {
|
|
func.func @ifinst(%N: index) {
|
|
%c = arith.constant 200 : index // CHECK %{{.*}} = arith.constant 200
|
|
affine.for %i = 1 to 10 { // CHECK affine.for %{{.*}} = 1 to 10 {
|
|
affine.if #set0(%i)[%N, %c] { // CHECK affine.if #set0(%{{.*}})[%{{.*}}, %{{.*}}] {
|
|
%x = arith.constant 1 : i32
|
|
// CHECK: %{{.*}} = arith.constant 1 : i32
|
|
%y = "add"(%x, %i) : (i32, index) -> i32 // CHECK: %{{.*}} = "add"(%{{.*}}, %{{.*}}) : (i32, index) -> i32
|
|
%z = "mul"(%y, %y) : (i32, i32) -> i32 // CHECK: %{{.*}} = "mul"(%{{.*}}, %{{.*}}) : (i32, i32) -> i32
|
|
} else { // CHECK } else {
|
|
affine.if affine_set<(i)[N] : (i - 2 >= 0, 4 - i >= 0)>(%i)[%N] { // CHECK affine.if (#set1(%{{.*}})[%{{.*}}]) {
|
|
// CHECK: %{{.*}} = arith.constant 1 : index
|
|
%u = arith.constant 1 : index
|
|
// CHECK: %{{.*}} = affine.apply #map{{.*}}(%{{.*}}, %{{.*}})[%{{.*}}]
|
|
%w = affine.apply affine_map<(d0,d1)[s0] -> (d0+d1+s0)> (%i, %i) [%u]
|
|
} else { // CHECK } else {
|
|
%v = arith.constant 3 : i32 // %c3_i32 = arith.constant 3 : i32
|
|
}
|
|
} // CHECK }
|
|
} // CHECK }
|
|
return // CHECK return
|
|
} // CHECK }
|
|
|
|
// CHECK-LABEL: func @simple_ifinst(%{{.*}}: index) {
|
|
func.func @simple_ifinst(%N: index) {
|
|
%c = arith.constant 200 : index // CHECK %{{.*}} = arith.constant 200
|
|
affine.for %i = 1 to 10 { // CHECK affine.for %{{.*}} = 1 to 10 {
|
|
affine.if #set0(%i)[%N, %c] { // CHECK affine.if #set0(%{{.*}})[%{{.*}}, %{{.*}}] {
|
|
%x = arith.constant 1 : i32
|
|
// CHECK: %{{.*}} = arith.constant 1 : i32
|
|
%y = "add"(%x, %i) : (i32, index) -> i32 // CHECK: %{{.*}} = "add"(%{{.*}}, %{{.*}}) : (i32, index) -> i32
|
|
%z = "mul"(%y, %y) : (i32, i32) -> i32 // CHECK: %{{.*}} = "mul"(%{{.*}}, %{{.*}}) : (i32, i32) -> i32
|
|
} // CHECK }
|
|
} // CHECK }
|
|
return // CHECK return
|
|
} // CHECK }
|
|
|
|
// CHECK-LABEL: func @attributes() {
|
|
func.func @attributes() {
|
|
// CHECK: "foo"()
|
|
"foo"(){} : ()->()
|
|
|
|
// CHECK: "foo"() {a = 1 : i64, b = -423 : i64, c = [true, false], d = 1.600000e+01 : f64} : () -> ()
|
|
"foo"() {a = 1, b = -423, c = [true, false], d = 16.0 } : () -> ()
|
|
|
|
// CHECK: "foo"() {map1 = #map{{[0-9]*}}}
|
|
"foo"() {map1 = #map1} : () -> ()
|
|
|
|
// CHECK: "foo"() {map2 = #map{{[0-9]*}}}
|
|
"foo"() {map2 = affine_map<(d0, d1, d2) -> (d0, d1, d2)>} : () -> ()
|
|
|
|
// CHECK: "foo"() {map12 = [#map{{[0-9]*}}, #map{{[0-9]*}}]}
|
|
"foo"() {map12 = [#map1, #map2]} : () -> ()
|
|
|
|
// CHECK: "foo"() {set1 = #set{{[0-9]*}}}
|
|
"foo"() {set1 = #set1} : () -> ()
|
|
|
|
// CHECK: "foo"() {set2 = #set{{[0-9]*}}}
|
|
"foo"() {set2 = affine_set<(d0, d1, d2) : (d0 >= 0, d1 >= 0, d2 - d1 == 0)>} : () -> ()
|
|
|
|
// CHECK: "foo"() {set12 = [#set{{[0-9]*}}, #set{{[0-9]*}}]}
|
|
"foo"() {set12 = [#set1, #set2]} : () -> ()
|
|
|
|
// CHECK: "foo"() {dictionary = {bool = true, fn = @ifinst}}
|
|
"foo"() {dictionary = {bool = true, fn = @ifinst}} : () -> ()
|
|
|
|
// Check that the dictionary attribute elements are sorted.
|
|
// CHECK: "foo"() {dictionary = {bar = false, bool = true, fn = @ifinst}}
|
|
"foo"() {dictionary = {fn = @ifinst, bar = false, bool = true}} : () -> ()
|
|
|
|
// CHECK: "foo"() {d = 1.000000e-09 : f64, func = [], i123 = 7 : i64, if = "foo"} : () -> ()
|
|
"foo"() {if = "foo", func = [], i123 = 7, d = 1.e-9} : () -> ()
|
|
|
|
// CHECK: "foo"() {fn = @attributes, if = @ifinst} : () -> ()
|
|
"foo"() {fn = @attributes, if = @ifinst} : () -> ()
|
|
|
|
// CHECK: "foo"() {int = 0 : i42} : () -> ()
|
|
"foo"() {int = 0 : i42} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @ssa_values() -> (i16, i8) {
|
|
func.func @ssa_values() -> (i16, i8) {
|
|
// CHECK: %{{.*}}:2 = "foo"() : () -> (i1, i17)
|
|
%0:2 = "foo"() : () -> (i1, i17)
|
|
cf.br ^bb2
|
|
|
|
^bb1: // CHECK: ^bb1: // pred: ^bb2
|
|
// CHECK: %{{.*}}:2 = "baz"(%{{.*}}#1, %{{.*}}#0, %{{.*}}#1) : (f32, i11, i17) -> (i16, i8)
|
|
%1:2 = "baz"(%2#1, %2#0, %0#1) : (f32, i11, i17) -> (i16, i8)
|
|
|
|
// CHECK: return %{{.*}}#0, %{{.*}}#1 : i16, i8
|
|
return %1#0, %1#1 : i16, i8
|
|
|
|
^bb2: // CHECK: ^bb2: // pred: ^bb0
|
|
// CHECK: %{{.*}}:2 = "bar"(%{{.*}}#0, %{{.*}}#1) : (i1, i17) -> (i11, f32)
|
|
%2:2 = "bar"(%0#0, %0#1) : (i1, i17) -> (i11, f32)
|
|
cf.br ^bb1
|
|
}
|
|
|
|
// CHECK-LABEL: func @bbargs() -> (i16, i8) {
|
|
func.func @bbargs() -> (i16, i8) {
|
|
// CHECK: %{{.*}}:2 = "foo"() : () -> (i1, i17)
|
|
%0:2 = "foo"() : () -> (i1, i17)
|
|
cf.br ^bb1(%0#1, %0#0 : i17, i1)
|
|
|
|
^bb1(%x: i17, %y: i1): // CHECK: ^bb1(%{{.*}}: i17, %{{.*}}: i1):
|
|
// CHECK: %{{.*}}:2 = "baz"(%{{.*}}, %{{.*}}, %{{.*}}#1) : (i17, i1, i17) -> (i16, i8)
|
|
%1:2 = "baz"(%x, %y, %0#1) : (i17, i1, i17) -> (i16, i8)
|
|
return %1#0, %1#1 : i16, i8
|
|
}
|
|
|
|
// CHECK-LABEL: func @verbose_terminators() -> (i1, i17)
|
|
func.func @verbose_terminators() -> (i1, i17) {
|
|
%0:2 = "foo"() : () -> (i1, i17)
|
|
// CHECK: cf.br ^bb1(%{{.*}}#0, %{{.*}}#1 : i1, i17)
|
|
"cf.br"(%0#0, %0#1)[^bb1] : (i1, i17) -> ()
|
|
|
|
^bb1(%x : i1, %y : i17):
|
|
// CHECK: cf.cond_br %{{.*}}, ^bb2(%{{.*}} : i17), ^bb3(%{{.*}}, %{{.*}} : i1, i17)
|
|
"cf.cond_br"(%x, %y, %x, %y) [^bb2, ^bb3] {operand_segment_sizes = array<i32: 1, 1, 2>} : (i1, i17, i1, i17) -> ()
|
|
|
|
^bb2(%a : i17):
|
|
%true = arith.constant true
|
|
// CHECK: return %{{.*}}, %{{.*}} : i1, i17
|
|
"func.return"(%true, %a) : (i1, i17) -> ()
|
|
|
|
^bb3(%b : i1, %c : i17):
|
|
// CHECK: return %{{.*}}, %{{.*}} : i1, i17
|
|
"func.return"(%b, %c) : (i1, i17) -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: func @condbr_simple
|
|
func.func @condbr_simple() -> (i32) {
|
|
%cond = "foo"() : () -> i1
|
|
%a = "bar"() : () -> i32
|
|
%b = "bar"() : () -> i64
|
|
// CHECK: cf.cond_br %{{.*}}, ^bb1(%{{.*}} : i32), ^bb2(%{{.*}} : i64)
|
|
cf.cond_br %cond, ^bb1(%a : i32), ^bb2(%b : i64)
|
|
|
|
// CHECK: ^bb1({{.*}}: i32): // pred: ^bb0
|
|
^bb1(%x : i32):
|
|
cf.br ^bb2(%b: i64)
|
|
|
|
// CHECK: ^bb2({{.*}}: i64): // 2 preds: ^bb0, ^bb1
|
|
^bb2(%y : i64):
|
|
%z = "foo"() : () -> i32
|
|
return %z : i32
|
|
}
|
|
|
|
// CHECK-LABEL: func @condbr_moarargs
|
|
func.func @condbr_moarargs() -> (i32) {
|
|
%cond = "foo"() : () -> i1
|
|
%a = "bar"() : () -> i32
|
|
%b = "bar"() : () -> i64
|
|
// CHECK: cf.cond_br %{{.*}}, ^bb1(%{{.*}}, %{{.*}} : i32, i64), ^bb2(%{{.*}}, %{{.*}}, %{{.*}} : i64, i32, i32)
|
|
cf.cond_br %cond, ^bb1(%a, %b : i32, i64), ^bb2(%b, %a, %a : i64, i32, i32)
|
|
|
|
^bb1(%x : i32, %y : i64):
|
|
return %x : i32
|
|
|
|
^bb2(%x2 : i64, %y2 : i32, %z2 : i32):
|
|
%z = "foo"() : () -> i32
|
|
return %z : i32
|
|
}
|
|
|
|
|
|
// Test pretty printing of constant names.
|
|
// CHECK-LABEL: func @constants
|
|
func.func @constants() -> (i32, i23, i23, i1, i1) {
|
|
// CHECK: %{{.*}} = arith.constant 42 : i32
|
|
%x = arith.constant 42 : i32
|
|
// CHECK: %{{.*}} = arith.constant 17 : i23
|
|
%y = arith.constant 17 : i23
|
|
|
|
// This is a redundant definition of 17, the asmprinter gives it a unique name
|
|
// CHECK: %{{.*}} = arith.constant 17 : i23
|
|
%z = arith.constant 17 : i23
|
|
|
|
// CHECK: %{{.*}} = arith.constant true
|
|
%t = arith.constant true
|
|
// CHECK: %{{.*}} = arith.constant false
|
|
%f = arith.constant false
|
|
|
|
// The trick to parse type declarations should not interfere with hex
|
|
// literals.
|
|
// CHECK: %{{.*}} = arith.constant 3890 : i32
|
|
%h = arith.constant 0xf32 : i32
|
|
|
|
// CHECK: return %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}
|
|
return %x, %y, %z, %t, %f : i32, i23, i23, i1, i1
|
|
}
|
|
|
|
// CHECK-LABEL: func @typeattr
|
|
func.func @typeattr() -> () {
|
|
^bb0:
|
|
// CHECK: "foo"() {bar = tensor<*xf32>} : () -> ()
|
|
"foo"(){bar = tensor<*xf32>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @stringquote
|
|
func.func @stringquote() -> () {
|
|
^bb0:
|
|
// CHECK: "foo"() {bar = "a\22quoted\22string"} : () -> ()
|
|
"foo"(){bar = "a\"quoted\"string"} : () -> ()
|
|
|
|
// CHECK-NEXT: "typed_string" : !foo.string
|
|
"foo"(){bar = "typed_string" : !foo.string} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @unitAttrs
|
|
func.func @unitAttrs() -> () {
|
|
// CHECK-NEXT: "foo"() {unitAttr}
|
|
"foo"() {unitAttr = unit} : () -> ()
|
|
|
|
// CHECK-NEXT: "foo"() {unitAttr}
|
|
"foo"() {unitAttr} : () -> ()
|
|
|
|
// CHECK-NEXT: "foo"() {nested = {unitAttr}}
|
|
"foo"() {nested = {unitAttr}} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @floatAttrs
|
|
func.func @floatAttrs() -> () {
|
|
^bb0:
|
|
// CHECK: "foo"() {a = 4.000000e+00 : f64, b = 2.000000e+00 : f64, c = 7.100000e+00 : f64, d = -0.000000e+00 : f64} : () -> ()
|
|
"foo"(){a = 4.0, b = 2.0, c = 7.1, d = -0.0} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func private @externalfuncattr
|
|
func.func private @externalfuncattr() -> ()
|
|
// CHECK: attributes {dialect.a = "a\22quoted\22string", dialect.b = 4.000000e+00 : f64, dialect.c = tensor<*xf32>}
|
|
attributes {dialect.a = "a\"quoted\"string", dialect.b = 4.0, dialect.c = tensor<*xf32>}
|
|
|
|
// CHECK-LABEL: func private @funcattrempty
|
|
func.func private @funcattrempty() -> ()
|
|
attributes {}
|
|
|
|
// CHECK-LABEL: func private @funcattr
|
|
func.func private @funcattr() -> ()
|
|
// CHECK: attributes {dialect.a = "a\22quoted\22string", dialect.b = 4.000000e+00 : f64, dialect.c = tensor<*xf32>}
|
|
attributes {dialect.a = "a\"quoted\"string", dialect.b = 4.0, dialect.c = tensor<*xf32>} {
|
|
^bb0:
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @funcattrwithblock
|
|
func.func @funcattrwithblock() -> ()
|
|
attributes {} {
|
|
^bb0:
|
|
return
|
|
}
|
|
|
|
// CHECK-label func @funcsimplemap
|
|
#map_simple0 = affine_map<()[] -> (10)>
|
|
#map_simple1 = affine_map<()[s0] -> (s0)>
|
|
#map_non_simple0 = affine_map<(d0)[] -> (d0)>
|
|
#map_non_simple1 = affine_map<(d0)[s0] -> (d0 + s0)>
|
|
#map_non_simple2 = affine_map<()[s0, s1] -> (s0 + s1)>
|
|
#map_non_simple3 = affine_map<()[s0] -> (s0 + 3)>
|
|
func.func @funcsimplemap(%arg0: index, %arg1: index) -> () {
|
|
affine.for %i0 = 0 to #map_simple0()[] {
|
|
// CHECK: affine.for %{{.*}} = 0 to 10 {
|
|
affine.for %i1 = 0 to #map_simple1()[%arg1] {
|
|
// CHECK: affine.for %{{.*}} = 0 to %{{.*}} {
|
|
affine.for %i2 = 0 to #map_non_simple0(%i0)[] {
|
|
// CHECK: affine.for %{{.*}} = 0 to #map{{[a-z_0-9]*}}(%{{.*}}) {
|
|
affine.for %i3 = 0 to #map_non_simple1(%i0)[%arg1] {
|
|
// CHECK: affine.for %{{.*}} = 0 to #map{{[a-z_0-9]*}}(%{{.*}})[%{{.*}}] {
|
|
affine.for %i4 = 0 to #map_non_simple2()[%arg1, %arg0] {
|
|
// CHECK: affine.for %{{.*}} = 0 to #map{{[a-z_0-9]*}}()[%{{.*}}, %{{.*}}] {
|
|
affine.for %i5 = 0 to #map_non_simple3()[%arg0] {
|
|
// CHECK: affine.for %{{.*}} = 0 to #map{{[a-z_0-9]*}}()[%{{.*}}] {
|
|
%c42_i32 = arith.constant 42 : i32
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @splattensorattr
|
|
func.func @splattensorattr() -> () {
|
|
^bb0:
|
|
// CHECK: "splatBoolTensor"() {bar = dense<false> : tensor<i1>} : () -> ()
|
|
"splatBoolTensor"(){bar = dense<false> : tensor<i1>} : () -> ()
|
|
|
|
// CHECK: "splatUIntTensor"() {bar = dense<222> : tensor<2x1x4xui8>} : () -> ()
|
|
"splatUIntTensor"(){bar = dense<222> : tensor<2x1x4xui8>} : () -> ()
|
|
|
|
// CHECK: "splatIntTensor"() {bar = dense<5> : tensor<2x1x4xi32>} : () -> ()
|
|
"splatIntTensor"(){bar = dense<5> : tensor<2x1x4xi32>} : () -> ()
|
|
|
|
// CHECK: "splatFloatTensor"() {bar = dense<-5.000000e+00> : tensor<2x1x4xf32>} : () -> ()
|
|
"splatFloatTensor"(){bar = dense<-5.0> : tensor<2x1x4xf32>} : () -> ()
|
|
|
|
// CHECK: "splatIntVector"() {bar = dense<5> : vector<2x1x4xi64>} : () -> ()
|
|
"splatIntVector"(){bar = dense<5> : vector<2x1x4xi64>} : () -> ()
|
|
|
|
// CHECK: "splatFloatVector"() {bar = dense<-5.000000e+00> : vector<2x1x4xf16>} : () -> ()
|
|
"splatFloatVector"(){bar = dense<-5.0> : vector<2x1x4xf16>} : () -> ()
|
|
|
|
// CHECK: "splatIntScalar"() {bar = dense<5> : tensor<i9>} : () -> ()
|
|
"splatIntScalar"() {bar = dense<5> : tensor<i9>} : () -> ()
|
|
// CHECK: "splatFloatScalar"() {bar = dense<-5.000000e+00> : tensor<f16>} : () -> ()
|
|
"splatFloatScalar"() {bar = dense<-5.0> : tensor<f16>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @densetensorattr
|
|
func.func @densetensorattr() -> () {
|
|
^bb0:
|
|
|
|
// NOTE: The {{\[\[}} syntax is because "[[" confuses FileCheck.
|
|
// CHECK: "fooi3"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi3>} : () -> ()
|
|
"fooi3"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi3>} : () -> ()
|
|
// CHECK: "fooi6"() {bar = dense<{{\[\[\[}}5, -6, 1, 2]], {{\[\[}}7, 8, 3, 4]]]> : tensor<2x1x4xi6>} : () -> ()
|
|
"fooi6"(){bar = dense<[[[5, -6, 1, 2]], [[7, 8, 3, 4]]]> : tensor<2x1x4xi6>} : () -> ()
|
|
// CHECK: "fooi8"() {bar = dense<5> : tensor<1x1x1xi8>} : () -> ()
|
|
"fooi8"(){bar = dense<[[[5]]]> : tensor<1x1x1xi8>} : () -> ()
|
|
// CHECK: "fooi13"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi13>} : () -> ()
|
|
"fooi13"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi13>} : () -> ()
|
|
// CHECK: "fooi16"() {bar = dense<-5> : tensor<1x1x1xi16>} : () -> ()
|
|
"fooi16"(){bar = dense<[[[-5]]]> : tensor<1x1x1xi16>} : () -> ()
|
|
// CHECK: "fooi23"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi23>} : () -> ()
|
|
"fooi23"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi23>} : () -> ()
|
|
// CHECK: "fooi32"() {bar = dense<5> : tensor<1x1x1xi32>} : () -> ()
|
|
"fooi32"(){bar = dense<[[[5]]]> : tensor<1x1x1xi32>} : () -> ()
|
|
// CHECK: "fooi33"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi33>} : () -> ()
|
|
"fooi33"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi33>} : () -> ()
|
|
// CHECK: "fooi43"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi43>} : () -> ()
|
|
"fooi43"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi43>} : () -> ()
|
|
// CHECK: "fooi53"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 2, -1, 2]]]> : tensor<2x1x4xi53>} : () -> ()
|
|
"fooi53"(){bar = dense<[[[1, -2, 1, 2]], [[0, 2, -1, 2]]]> : tensor<2x1x4xi53>} : () -> ()
|
|
// CHECK: "fooi64"() {bar = dense<{{\[\[\[}}1, -2, 1, 2]], {{\[\[}}0, 3, -1, 2]]]> : tensor<2x1x4xi64>} : () -> ()
|
|
"fooi64"(){bar = dense<[[[1, -2, 1, 2]], [[0, 3, -1, 2]]]> : tensor<2x1x4xi64>} : () -> ()
|
|
// CHECK: "fooi64"() {bar = dense<-5> : tensor<1x1x1xi64>} : () -> ()
|
|
"fooi64"(){bar = dense<[[[-5]]]> : tensor<1x1x1xi64>} : () -> ()
|
|
// CHECK: "fooi67"() {bar = dense<{{\[\[\[}}-5, 4, 6, 2]]]> : vector<1x1x4xi67>} : () -> ()
|
|
"fooi67"(){bar = dense<[[[-5, 4, 6, 2]]]> : vector<1x1x4xi67>} : () -> ()
|
|
|
|
// CHECK: "foo2"() {bar = dense<> : tensor<0xi32>} : () -> ()
|
|
"foo2"(){bar = dense<> : tensor<0xi32>} : () -> ()
|
|
// CHECK: "foo2"() {bar = dense<> : tensor<1x0xi32>} : () -> ()
|
|
"foo2"(){bar = dense<> : tensor<1x0xi32>} : () -> ()
|
|
// CHECK: dense<> : tensor<0x512x512xi32>
|
|
"foo2"(){bar = dense<> : tensor<0x512x512xi32>} : () -> ()
|
|
// CHECK: "foo3"() {bar = dense<{{\[\[\[}}5, -6, 1, 2]], {{\[\[}}7, 8, 3, 4]]]> : tensor<2x1x4xi32>} : () -> ()
|
|
"foo3"(){bar = dense<[[[5, -6, 1, 2]], [[7, 8, 3, 4]]]> : tensor<2x1x4xi32>} : () -> ()
|
|
|
|
// CHECK: "float1"() {bar = dense<5.000000e+00> : tensor<1x1x1xf32>} : () -> ()
|
|
"float1"(){bar = dense<[[[5.0]]]> : tensor<1x1x1xf32>} : () -> ()
|
|
// CHECK: "float2"() {bar = dense<> : tensor<0xf32>} : () -> ()
|
|
"float2"(){bar = dense<> : tensor<0xf32>} : () -> ()
|
|
// CHECK: "float2"() {bar = dense<> : tensor<1x0xf32>} : () -> ()
|
|
"float2"(){bar = dense<> : tensor<1x0xf32>} : () -> ()
|
|
|
|
// CHECK: "bfloat16"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : tensor<2x1x4xbf16>} : () -> ()
|
|
"bfloat16"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : tensor<2x1x4xbf16>} : () -> ()
|
|
// CHECK: "float16"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : tensor<2x1x4xf16>} : () -> ()
|
|
"float16"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : tensor<2x1x4xf16>} : () -> ()
|
|
// CHECK: "float32"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : tensor<2x1x4xf32>} : () -> ()
|
|
"float32"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : tensor<2x1x4xf32>} : () -> ()
|
|
// CHECK: "float64"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : tensor<2x1x4xf64>} : () -> ()
|
|
"float64"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : tensor<2x1x4xf64>} : () -> ()
|
|
|
|
// CHECK: "intscalar"() {bar = dense<1> : tensor<i32>} : () -> ()
|
|
"intscalar"(){bar = dense<1> : tensor<i32>} : () -> ()
|
|
// CHECK: "floatscalar"() {bar = dense<5.000000e+00> : tensor<f32>} : () -> ()
|
|
"floatscalar"(){bar = dense<5.0> : tensor<f32>} : () -> ()
|
|
|
|
// CHECK: "index"() {bar = dense<1> : tensor<index>} : () -> ()
|
|
"index"(){bar = dense<1> : tensor<index>} : () -> ()
|
|
// CHECK: "index"() {bar = dense<[1, 2]> : tensor<2xindex>} : () -> ()
|
|
"index"(){bar = dense<[1, 2]> : tensor<2xindex>} : () -> ()
|
|
|
|
// CHECK: dense<(1,1)> : tensor<complex<i64>>
|
|
"complex_attr"(){bar = dense<(1,1)> : tensor<complex<i64>>} : () -> ()
|
|
// CHECK: dense<[(1,1), (2,2)]> : tensor<2xcomplex<i64>>
|
|
"complex_attr"(){bar = dense<[(1,1), (2,2)]> : tensor<2xcomplex<i64>>} : () -> ()
|
|
// CHECK: dense<(1.000000e+00,0.000000e+00)> : tensor<complex<f32>>
|
|
"complex_attr"(){bar = dense<(1.000000e+00,0.000000e+00)> : tensor<complex<f32>>} : () -> ()
|
|
// CHECK: dense<[(1.000000e+00,0.000000e+00), (2.000000e+00,2.000000e+00)]> : tensor<2xcomplex<f32>>
|
|
"complex_attr"(){bar = dense<[(1.000000e+00,0.000000e+00), (2.000000e+00,2.000000e+00)]> : tensor<2xcomplex<f32>>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @densevectorattr
|
|
func.func @densevectorattr() -> () {
|
|
^bb0:
|
|
// NOTE: The {{\[\[}} syntax is because "[[" confuses FileCheck.
|
|
// CHECK: "fooi8"() {bar = dense<5> : vector<1x1x1xi8>} : () -> ()
|
|
"fooi8"(){bar = dense<[[[5]]]> : vector<1x1x1xi8>} : () -> ()
|
|
// CHECK: "fooi16"() {bar = dense<-5> : vector<1x1x1xi16>} : () -> ()
|
|
"fooi16"(){bar = dense<[[[-5]]]> : vector<1x1x1xi16>} : () -> ()
|
|
// CHECK: "foo32"() {bar = dense<5> : vector<1x1x1xi32>} : () -> ()
|
|
"foo32"(){bar = dense<[[[5]]]> : vector<1x1x1xi32>} : () -> ()
|
|
// CHECK: "fooi64"() {bar = dense<-5> : vector<1x1x1xi64>} : () -> ()
|
|
"fooi64"(){bar = dense<[[[-5]]]> : vector<1x1x1xi64>} : () -> ()
|
|
|
|
// CHECK: "foo3"() {bar = dense<{{\[\[\[}}5, -6, 1, 2]], {{\[\[}}7, 8, 3, 4]]]> : vector<2x1x4xi32>} : () -> ()
|
|
"foo3"(){bar = dense<[[[5, -6, 1, 2]], [[7, 8, 3, 4]]]> : vector<2x1x4xi32>} : () -> ()
|
|
|
|
// CHECK: "float1"() {bar = dense<5.000000e+00> : vector<1x1x1xf32>} : () -> ()
|
|
"float1"(){bar = dense<[[[5.0]]]> : vector<1x1x1xf32>} : () -> ()
|
|
|
|
// CHECK: "bfloat16"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : vector<2x1x4xbf16>} : () -> ()
|
|
"bfloat16"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : vector<2x1x4xbf16>} : () -> ()
|
|
// CHECK: "float16"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : vector<2x1x4xf16>} : () -> ()
|
|
"float16"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : vector<2x1x4xf16>} : () -> ()
|
|
// CHECK: "float32"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : vector<2x1x4xf32>} : () -> ()
|
|
"float32"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : vector<2x1x4xf32>} : () -> ()
|
|
// CHECK: "float64"() {bar = dense<{{\[\[\[}}-5.000000e+00, 6.000000e+00, 1.000000e+00, 2.000000e+00]], {{\[\[}}7.000000e+00, -8.000000e+00, 3.000000e+00, 4.000000e+00]]]> : vector<2x1x4xf64>} : () -> ()
|
|
"float64"(){bar = dense<[[[-5.0, 6.0, 1.0, 2.0]], [[7.0, -8.0, 3.0, 4.0]]]> : vector<2x1x4xf64>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @sparsetensorattr
|
|
func.func @sparsetensorattr() -> () {
|
|
^bb0:
|
|
// NOTE: The {{\[\[}} syntax is because "[[" confuses FileCheck.
|
|
// CHECK: "fooi8"() {bar = sparse<0, -2> : tensor<1x1x1xi8>} : () -> ()
|
|
"fooi8"(){bar = sparse<0, -2> : tensor<1x1x1xi8>} : () -> ()
|
|
// CHECK: "fooi16"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}2, -1, 5]> : tensor<2x2x2xi16>} : () -> ()
|
|
"fooi16"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], [2, -1, 5]> : tensor<2x2x2xi16>} : () -> ()
|
|
// CHECK: "fooi32"() {bar = sparse<> : tensor<1x1xi32>} : () -> ()
|
|
"fooi32"(){bar = sparse<> : tensor<1x1xi32>} : () -> ()
|
|
// CHECK: "fooi64"() {bar = sparse<0, -1> : tensor<1xi64>} : () -> ()
|
|
"fooi64"(){bar = sparse<[0], [-1]> : tensor<1xi64>} : () -> ()
|
|
// CHECK: "foo2"() {bar = sparse<> : tensor<0xi32>} : () -> ()
|
|
"foo2"(){bar = sparse<> : tensor<0xi32>} : () -> ()
|
|
// CHECK: "foo3"() {bar = sparse<> : tensor<i32>} : () -> ()
|
|
"foo3"(){bar = sparse<> : tensor<i32>} : () -> ()
|
|
|
|
// CHECK: "foof16"() {bar = sparse<0, -2.000000e+00> : tensor<1x1x1xf16>} : () -> ()
|
|
"foof16"(){bar = sparse<0, -2.0> : tensor<1x1x1xf16>} : () -> ()
|
|
// CHECK: "foobf16"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}2.000000e+00, -1.000000e+00, 5.000000e+00]> : tensor<2x2x2xbf16>} : () -> ()
|
|
"foobf16"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], [2.0, -1.0, 5.0]> : tensor<2x2x2xbf16>} : () -> ()
|
|
// CHECK: "foof32"() {bar = sparse<> : tensor<1x0x1xf32>} : () -> ()
|
|
"foof32"(){bar = sparse<> : tensor<1x0x1xf32>} : () -> ()
|
|
// CHECK: "foof64"() {bar = sparse<0, -1.000000e+00> : tensor<1xf64>} : () -> ()
|
|
"foof64"(){bar = sparse<[[0]], [-1.0]> : tensor<1xf64>} : () -> ()
|
|
// CHECK: "foof320"() {bar = sparse<> : tensor<0xf32>} : () -> ()
|
|
"foof320"(){bar = sparse<> : tensor<0xf32>} : () -> ()
|
|
// CHECK: "foof321"() {bar = sparse<> : tensor<f32>} : () -> ()
|
|
"foof321"(){bar = sparse<> : tensor<f32>} : () -> ()
|
|
|
|
// CHECK: "foostr"() {bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<>>} : () -> ()
|
|
"foostr"(){bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<>>} : () -> ()
|
|
// CHECK: "foostr"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}"a", "b", "c"]> : tensor<2x2x2x!unknown<>>} : () -> ()
|
|
"foostr"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], ["a", "b", "c"]> : tensor<2x2x2x!unknown<>>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @sparsevectorattr
|
|
func.func @sparsevectorattr() -> () {
|
|
^bb0:
|
|
// NOTE: The {{\[\[}} syntax is because "[[" confuses FileCheck.
|
|
// CHECK: "fooi8"() {bar = sparse<0, -2> : vector<1x1x1xi8>} : () -> ()
|
|
"fooi8"(){bar = sparse<0, -2> : vector<1x1x1xi8>} : () -> ()
|
|
// CHECK: "fooi16"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}2, -1, 5]> : vector<2x2x2xi16>} : () -> ()
|
|
"fooi16"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], [2, -1, 5]> : vector<2x2x2xi16>} : () -> ()
|
|
// CHECK: "fooi32"() {bar = sparse<> : vector<1x1xi32>} : () -> ()
|
|
"fooi32"(){bar = sparse<> : vector<1x1xi32>} : () -> ()
|
|
// CHECK: "fooi64"() {bar = sparse<0, -1> : vector<1xi64>} : () -> ()
|
|
"fooi64"(){bar = sparse<[[0]], [-1]> : vector<1xi64>} : () -> ()
|
|
|
|
// CHECK: "foof16"() {bar = sparse<0, -2.000000e+00> : vector<1x1x1xf16>} : () -> ()
|
|
"foof16"(){bar = sparse<0, -2.0> : vector<1x1x1xf16>} : () -> ()
|
|
// CHECK: "foobf16"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}2.000000e+00, -1.000000e+00, 5.000000e+00]> : vector<2x2x2xbf16>} : () -> ()
|
|
"foobf16"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], [2.0, -1.0, 5.0]> : vector<2x2x2xbf16>} : () -> ()
|
|
// CHECK: "foof64"() {bar = sparse<0, -1.000000e+00> : vector<1xf64>} : () -> ()
|
|
"foof64"(){bar = sparse<0, [-1.0]> : vector<1xf64>} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @unknown_dialect_type() -> !bar<> {
|
|
func.func @unknown_dialect_type() -> !bar<> {
|
|
// Unregistered dialect 'bar'.
|
|
// CHECK: "foo"() : () -> !bar<>
|
|
%0 = "foo"() : () -> !bar<>
|
|
|
|
// CHECK: "foo"() : () -> !bar.baz
|
|
%1 = "foo"() : () -> !bar<baz>
|
|
|
|
return %0 : !bar<>
|
|
}
|
|
|
|
// CHECK-LABEL: func @type_alias() -> i32 {
|
|
!i32_type_alias = i32
|
|
func.func @type_alias() -> !i32_type_alias {
|
|
|
|
// Return a non-aliased i32 type.
|
|
%0 = "foo"() : () -> i32
|
|
return %0 : i32
|
|
}
|
|
|
|
// CHECK-LABEL: func @no_integer_set_constraints(
|
|
func.func @no_integer_set_constraints() {
|
|
// CHECK: affine.if [[$SET_TRUE]]() {
|
|
affine.if affine_set<() : ()> () {
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @verbose_if(
|
|
func.func @verbose_if(%N: index) {
|
|
%c = arith.constant 200 : index
|
|
|
|
// CHECK: affine.if #set{{.*}}(%{{.*}})[%{{.*}}, %{{.*}}] {
|
|
"affine.if"(%c, %N, %c) ({
|
|
// CHECK-NEXT: "add"
|
|
%y = "add"(%c, %N) : (index, index) -> index
|
|
"affine.yield"() : () -> ()
|
|
// CHECK-NEXT: } else {
|
|
}, { // The else region.
|
|
// CHECK-NEXT: "add"
|
|
%z = "add"(%c, %c) : (index, index) -> index
|
|
"affine.yield"() : () -> ()
|
|
})
|
|
{ condition = #set0 } : (index, index, index) -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @terminator_with_regions
|
|
func.func @terminator_with_regions() {
|
|
// Combine successors and regions in the same operation.
|
|
// CHECK: "region"()[^bb1] ({
|
|
// CHECK: }) : () -> ()
|
|
"region"()[^bb2] ({}) : () -> ()
|
|
^bb2:
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @unregistered_term
|
|
func.func @unregistered_term(%arg0 : i1) -> i1 {
|
|
// CHECK-NEXT: "unregistered_br"(%{{.*}})[^bb1] : (i1) -> ()
|
|
"unregistered_br"(%arg0)[^bb1] : (i1) -> ()
|
|
|
|
^bb1(%arg1 : i1):
|
|
return %arg1 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: func @dialect_attrs
|
|
func.func @dialect_attrs()
|
|
// CHECK: attributes {dialect.attr = 10
|
|
attributes {dialect.attr = 10} {
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func private @_valid.function$name
|
|
func.func private @_valid.function$name()
|
|
|
|
// CHECK-LABEL: func private @external_func_arg_attrs(i32, i1 {dialect.attr = 10 : i64}, i32)
|
|
func.func private @external_func_arg_attrs(i32, i1 {dialect.attr = 10 : i64}, i32)
|
|
|
|
// CHECK-LABEL: func @func_arg_attrs(%{{.*}}: i1 {dialect.attr = 10 : i64})
|
|
func.func @func_arg_attrs(%arg0: i1 {dialect.attr = 10 : i64}) {
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @func_result_attrs({{.*}}) -> (f32 {dialect.attr = 1 : i64})
|
|
func.func @func_result_attrs(%arg0: f32) -> (f32 {dialect.attr = 1}) {
|
|
return %arg0 : f32
|
|
}
|
|
|
|
// CHECK-LABEL: func private @empty_tuple(tuple<>)
|
|
func.func private @empty_tuple(tuple<>)
|
|
|
|
// CHECK-LABEL: func private @tuple_single_element(tuple<i32>)
|
|
func.func private @tuple_single_element(tuple<i32>)
|
|
|
|
// CHECK-LABEL: func private @tuple_multi_element(tuple<i32, i16, f32>)
|
|
func.func private @tuple_multi_element(tuple<i32, i16, f32>)
|
|
|
|
// CHECK-LABEL: func private @tuple_nested(tuple<tuple<tuple<i32>>>)
|
|
func.func private @tuple_nested(tuple<tuple<tuple<i32>>>)
|
|
|
|
// CHECK-LABEL: func @pretty_form_multi_result
|
|
func.func @pretty_form_multi_result() -> (i16, i16) {
|
|
// CHECK: %{{.*}}:2 = "foo_div"() : () -> (i16, i16)
|
|
%quot, %rem = "foo_div"() : () -> (i16, i16)
|
|
return %quot, %rem : i16, i16
|
|
}
|
|
|
|
// CHECK-LABEL: func @pretty_form_multi_result_groups
|
|
func.func @pretty_form_multi_result_groups() -> (i16, i16, i16, i16, i16) {
|
|
// CHECK: %[[RES:.*]]:5 =
|
|
// CHECK: return %[[RES]]#0, %[[RES]]#1, %[[RES]]#2, %[[RES]]#3, %[[RES]]#4
|
|
%group_1:2, %group_2, %group_3:2 = "foo_test"() : () -> (i16, i16, i16, i16, i16)
|
|
return %group_1#0, %group_1#1, %group_2, %group_3#0, %group_3#1 : i16, i16, i16, i16, i16
|
|
}
|
|
|
|
// CHECK-LABEL: func @pretty_dialect_attribute()
|
|
func.func @pretty_dialect_attribute() {
|
|
// CHECK: "foo.unknown_op"() {foo = #foo.simple_attr} : () -> ()
|
|
"foo.unknown_op"() {foo = #foo.simple_attr} : () -> ()
|
|
|
|
// CHECK: "foo.unknown_op"() {foo = #foo.complexattr<abcd>} : () -> ()
|
|
"foo.unknown_op"() {foo = #foo.complexattr<abcd>} : () -> ()
|
|
|
|
// CHECK: "foo.unknown_op"() {foo = #foo.complexattr<abcd<f32>>} : () -> ()
|
|
"foo.unknown_op"() {foo = #foo.complexattr<abcd<f32>>} : () -> ()
|
|
|
|
// CHECK: "foo.unknown_op"() {foo = #foo.complexattr<abcd<[f]$$[32]>>} : () -> ()
|
|
"foo.unknown_op"() {foo = #foo.complexattr<abcd<[f]$$[32]>>} : () -> ()
|
|
|
|
// CHECK: "foo.unknown_op"() {foo = #foo.dialect<!x@#!@#>} : () -> ()
|
|
"foo.unknown_op"() {foo = #foo.dialect<!x@#!@#>} : () -> ()
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @pretty_dialect_type()
|
|
func.func @pretty_dialect_type() {
|
|
|
|
// CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.simpletype
|
|
%0 = "foo.unknown_op"() : () -> !foo.simpletype
|
|
|
|
// CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.complextype<abcd>
|
|
%1 = "foo.unknown_op"() : () -> !foo.complextype<abcd>
|
|
|
|
// CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.complextype<abcd<f32>>
|
|
%2 = "foo.unknown_op"() : () -> !foo.complextype<abcd<f32>>
|
|
|
|
// CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.complextype<abcd<[f]$$[32]>>
|
|
%3 = "foo.unknown_op"() : () -> !foo.complextype<abcd<[f]$$[32]>>
|
|
|
|
// CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.dialect<!x@#!@#>
|
|
%4 = "foo.unknown_op"() : () -> !foo.dialect<!x@#!@#>
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @none_type
|
|
func.func @none_type() {
|
|
// CHECK: "foo.unknown_op"() : () -> none
|
|
%none_val = "foo.unknown_op"() : () -> none
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @scoped_names
|
|
func.func @scoped_names() {
|
|
// CHECK-NEXT: "foo.region_op"
|
|
"foo.region_op"() ({
|
|
// CHECK-NEXT: "foo.unknown_op"
|
|
%scoped_name = "foo.unknown_op"() : () -> none
|
|
"foo.terminator"() : () -> ()
|
|
}, {
|
|
// CHECK: "foo.unknown_op"
|
|
%scoped_name = "foo.unknown_op"() : () -> none
|
|
"foo.terminator"() : () -> ()
|
|
}) : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @dialect_attribute_with_type
|
|
func.func @dialect_attribute_with_type() {
|
|
// CHECK-NEXT: foo = #foo.attr : i32
|
|
"foo.unknown_op"() {foo = #foo.attr : i32} : () -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: @f16_special_values
|
|
func.func @f16_special_values() {
|
|
// F16 NaNs.
|
|
// CHECK: arith.constant 0x7C01 : f16
|
|
%0 = arith.constant 0x7C01 : f16
|
|
// CHECK: arith.constant 0x7FFF : f16
|
|
%1 = arith.constant 0x7FFF : f16
|
|
// CHECK: arith.constant 0xFFFF : f16
|
|
%2 = arith.constant 0xFFFF : f16
|
|
|
|
// F16 positive infinity.
|
|
// CHECK: arith.constant 0x7C00 : f16
|
|
%3 = arith.constant 0x7C00 : f16
|
|
// F16 negative infinity.
|
|
// CHECK: arith.constant 0xFC00 : f16
|
|
%4 = arith.constant 0xFC00 : f16
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @f32_special_values
|
|
func.func @f32_special_values() {
|
|
// F32 signaling NaNs.
|
|
// CHECK: arith.constant 0x7F800001 : f32
|
|
%0 = arith.constant 0x7F800001 : f32
|
|
// CHECK: arith.constant 0x7FBFFFFF : f32
|
|
%1 = arith.constant 0x7FBFFFFF : f32
|
|
|
|
// F32 quiet NaNs.
|
|
// CHECK: arith.constant 0x7FC00000 : f32
|
|
%2 = arith.constant 0x7FC00000 : f32
|
|
// CHECK: arith.constant 0xFFFFFFFF : f32
|
|
%3 = arith.constant 0xFFFFFFFF : f32
|
|
|
|
// F32 positive infinity.
|
|
// CHECK: arith.constant 0x7F800000 : f32
|
|
%4 = arith.constant 0x7F800000 : f32
|
|
// F32 negative infinity.
|
|
// CHECK: arith.constant 0xFF800000 : f32
|
|
%5 = arith.constant 0xFF800000 : f32
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @f64_special_values
|
|
func.func @f64_special_values() {
|
|
// F64 signaling NaNs.
|
|
// CHECK: arith.constant 0x7FF0000000000001 : f64
|
|
%0 = arith.constant 0x7FF0000000000001 : f64
|
|
// CHECK: arith.constant 0x7FF8000000000000 : f64
|
|
%1 = arith.constant 0x7FF8000000000000 : f64
|
|
|
|
// F64 quiet NaNs.
|
|
// CHECK: arith.constant 0x7FF0000001000000 : f64
|
|
%2 = arith.constant 0x7FF0000001000000 : f64
|
|
// CHECK: arith.constant 0xFFF0000001000000 : f64
|
|
%3 = arith.constant 0xFFF0000001000000 : f64
|
|
|
|
// F64 positive infinity.
|
|
// CHECK: arith.constant 0x7FF0000000000000 : f64
|
|
%4 = arith.constant 0x7FF0000000000000 : f64
|
|
// F64 negative infinity.
|
|
// CHECK: arith.constant 0xFFF0000000000000 : f64
|
|
%5 = arith.constant 0xFFF0000000000000 : f64
|
|
|
|
// Check that values that can't be represented with the default format, use
|
|
// hex instead.
|
|
// CHECK: arith.constant 0xC1CDC00000000000 : f64
|
|
%6 = arith.constant 0xC1CDC00000000000 : f64
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @bfloat16_special_values
|
|
func.func @bfloat16_special_values() {
|
|
// bfloat16 signaling NaNs.
|
|
// CHECK: arith.constant 0x7F81 : bf16
|
|
%0 = arith.constant 0x7F81 : bf16
|
|
// CHECK: arith.constant 0xFF81 : bf16
|
|
%1 = arith.constant 0xFF81 : bf16
|
|
|
|
// bfloat16 quiet NaNs.
|
|
// CHECK: arith.constant 0x7FC0 : bf16
|
|
%2 = arith.constant 0x7FC0 : bf16
|
|
// CHECK: arith.constant 0xFFC0 : bf16
|
|
%3 = arith.constant 0xFFC0 : bf16
|
|
|
|
// bfloat16 positive infinity.
|
|
// CHECK: arith.constant 0x7F80 : bf16
|
|
%4 = arith.constant 0x7F80 : bf16
|
|
// bfloat16 negative infinity.
|
|
// CHECK: arith.constant 0xFF80 : bf16
|
|
%5 = arith.constant 0xFF80 : bf16
|
|
|
|
return
|
|
}
|
|
|
|
// We want to print floats in exponential notation with 6 significant digits,
|
|
// but it may lead to precision loss when parsing back, in which case we print
|
|
// the decimal form instead.
|
|
// CHECK-LABEL: @f32_potential_precision_loss()
|
|
func.func @f32_potential_precision_loss() {
|
|
// CHECK: arith.constant -1.23697901 : f32
|
|
%0 = arith.constant -1.23697901 : f32
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: @special_float_values_in_tensors
|
|
func.func @special_float_values_in_tensors() {
|
|
// CHECK: dense<0xFFFFFFFF> : tensor<4x4xf32>
|
|
"foo"(){bar = dense<0xFFFFFFFF> : tensor<4x4xf32>} : () -> ()
|
|
// CHECK: dense<[{{\[}}0xFFFFFFFF, 0x7F800000], [0x7FBFFFFF, 0x7F800001]]> : tensor<2x2xf32>
|
|
"foo"(){bar = dense<[[0xFFFFFFFF, 0x7F800000], [0x7FBFFFFF, 0x7F800001]]> : tensor<2x2xf32>} : () -> ()
|
|
// CHECK: dense<[0xFFFFFFFF, 0.000000e+00]> : tensor<2xf32>
|
|
"foo"(){bar = dense<[0xFFFFFFFF, 0.0]> : tensor<2xf32>} : () -> ()
|
|
|
|
// CHECK: sparse<[{{\[}}1, 1, 0], [0, 1, 1]], [0xFFFFFFFF, 0x7F800001]>
|
|
"foo"(){bar = sparse<[[1,1,0],[0,1,1]], [0xFFFFFFFF, 0x7F800001]> : tensor<2x2x2xf32>} : () -> ()
|
|
}
|
|
|
|
// Test parsing of an op with multiple region arguments, and without a
|
|
// delimiter.
|
|
|
|
// CHECK-LABEL: func @op_with_region_args
|
|
func.func @op_with_region_args() {
|
|
// CHECK: "test.polyfor"() ({
|
|
// CHECK-NEXT: ^bb{{.*}}(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index):
|
|
test.polyfor %i, %j, %k {
|
|
"foo"() : () -> ()
|
|
}
|
|
return
|
|
}
|
|
|
|
// Test allowing different name scopes for regions isolated from above.
|
|
|
|
// CHECK-LABEL: func @op_with_passthrough_region_args
|
|
func.func @op_with_passthrough_region_args() {
|
|
// CHECK: [[VAL:%.*]] = arith.constant
|
|
%0 = arith.constant 10 : index
|
|
|
|
// CHECK: test.isolated_region [[VAL]] {
|
|
// CHECK-NEXT: "foo.consumer"([[VAL]]) : (index)
|
|
// CHECK-NEXT: }
|
|
test.isolated_region %0 {
|
|
"foo.consumer"(%0) : (index) -> ()
|
|
}
|
|
|
|
// CHECK: [[VAL:%.*]]:2 = "foo.op"
|
|
%result:2 = "foo.op"() : () -> (index, index)
|
|
|
|
// CHECK: test.isolated_region [[VAL]]#1 {
|
|
// CHECK-NEXT: "foo.consumer"([[VAL]]#1) : (index)
|
|
// CHECK-NEXT: }
|
|
test.isolated_region %result#1 {
|
|
"foo.consumer"(%result#1) : (index) -> ()
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func private @ptr_to_function() -> !unreg.ptr<() -> ()>
|
|
func.func private @ptr_to_function() -> !unreg.ptr<() -> ()>
|
|
|
|
// CHECK-LABEL: func private @escaped_string_char(i1 {foo.value = "\0A"})
|
|
func.func private @escaped_string_char(i1 {foo.value = "\n"})
|
|
|
|
// CHECK-LABEL: func @parse_integer_literal_test
|
|
func.func @parse_integer_literal_test() {
|
|
// CHECK: test.parse_integer_literal : 5
|
|
test.parse_integer_literal : 5
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @parse_wrapped_keyword_test
|
|
func.func @parse_wrapped_keyword_test() {
|
|
// CHECK: test.parse_wrapped_keyword foo.keyword
|
|
test.parse_wrapped_keyword foo.keyword
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @parse_base64_test
|
|
func.func @parse_base64_test() {
|
|
// CHECK: test.parse_b64 "hello world"
|
|
test.parse_b64 "aGVsbG8gd29ybGQ="
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @"\22_string_symbol_reference\22"
|
|
func.func @"\"_string_symbol_reference\""() {
|
|
// CHECK: ref = @"\22_string_symbol_reference\22"
|
|
"foo.symbol_reference"() {ref = @"\"_string_symbol_reference\""} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func private @parse_opaque_attr_escape
|
|
func.func private @parse_opaque_attr_escape() {
|
|
// CHECK: value = #foo<"\"escaped\\\n\"">
|
|
"foo.constant"() {value = #foo<"\"escaped\\\n\"">} : () -> ()
|
|
}
|
|
|
|
// CHECK-LABEL: func private @string_attr_name
|
|
// CHECK-SAME: {"0 . 0", nested = {"0 . 0"}}
|
|
func.func private @string_attr_name() attributes {"0 . 0", nested = {"0 . 0"}}
|
|
|
|
// CHECK-LABEL: func private @nested_reference
|
|
// CHECK: ref = @some_symbol::@some_nested_symbol
|
|
func.func private @nested_reference() attributes {test.ref = @some_symbol::@some_nested_symbol }
|
|
|
|
// CHECK-LABEL: func @custom_asm_names
|
|
func.func @custom_asm_names() -> (i32, i32, i32, i32, i32, i32) {
|
|
// CHECK: %[[FIRST:first.*]], %[[MIDDLE:middle_results.*]]:2, %[[LAST:[0-9]+]]
|
|
%0, %1:2, %2 = "test.asm_interface_op"() : () -> (i32, i32, i32, i32)
|
|
|
|
// CHECK: %[[FIRST_2:first.*]], %[[LAST_2:[0-9]+]]
|
|
%3, %4 = "test.asm_interface_op"() : () -> (i32, i32)
|
|
|
|
// CHECK: return %[[FIRST]], %[[MIDDLE]]#0, %[[MIDDLE]]#1, %[[LAST]], %[[FIRST_2]], %[[LAST_2]]
|
|
return %0, %1#0, %1#1, %2, %3, %4 : i32, i32, i32, i32, i32, i32
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: func @pretty_names
|
|
|
|
// This tests the behavior
|
|
func.func @pretty_names() {
|
|
// Simple case, should parse and print as %x being an implied 'name'
|
|
// attribute.
|
|
%x = test.string_attr_pretty_name
|
|
// CHECK: %x = test.string_attr_pretty_name
|
|
// CHECK-NOT: attributes
|
|
|
|
// This specifies an explicit name, which should override the result.
|
|
%YY = test.string_attr_pretty_name attributes { names = ["y"] }
|
|
// CHECK: %y = test.string_attr_pretty_name
|
|
// CHECK-NOT: attributes
|
|
|
|
// Conflicts with the 'y' name, so need an explicit attribute.
|
|
%0 = "test.string_attr_pretty_name"() { names = ["y"]} : () -> i32
|
|
// CHECK: %y_0 = test.string_attr_pretty_name attributes {names = ["y"]}
|
|
|
|
// Name contains a space.
|
|
%1 = "test.string_attr_pretty_name"() { names = ["space name"]} : () -> i32
|
|
// CHECK: %space_name = test.string_attr_pretty_name attributes {names = ["space name"]}
|
|
|
|
"unknown.use"(%x, %YY, %0, %1) : (i32, i32, i32, i32) -> ()
|
|
|
|
// Multi-result support.
|
|
|
|
%a, %b, %c = test.string_attr_pretty_name
|
|
// CHECK: %a, %b, %c = test.string_attr_pretty_name
|
|
// CHECK-NOT: attributes
|
|
|
|
%q:3, %r = test.string_attr_pretty_name
|
|
// CHECK: %q, %q_1, %q_2, %r = test.string_attr_pretty_name attributes {names = ["q", "q", "q", "r"]}
|
|
|
|
// CHECK: return
|
|
return
|
|
}
|
|
|
|
|
|
// This tests the behavior of "default dialect":
|
|
// operations like `test.default_dialect` can define a default dialect
|
|
// used in nested region.
|
|
// CHECK-LABEL: func @default_dialect
|
|
func.func @default_dialect(%bool : i1) {
|
|
test.default_dialect {
|
|
// The test dialect is the default in this region, the following two
|
|
// operations are parsed identically.
|
|
// CHECK-NOT: test.parse_integer_literal
|
|
parse_integer_literal : 5
|
|
// CHECK: parse_integer_literal : 6
|
|
test.parse_integer_literal : 6
|
|
// Verify that only an op prefix is stripped, not an attribute value for
|
|
// example.
|
|
// CHECK: "test.op_with_attr"() {test.attr = "test.value"} : () -> ()
|
|
"test.op_with_attr"() {test.attr = "test.value"} : () -> ()
|
|
// Verify that the prefix is not stripped when it can lead to ambiguity.
|
|
// CHECK: test.op.with_dot_in_name
|
|
test.op.with_dot_in_name
|
|
// This is an unregistered operation, the printing/parsing is handled by the
|
|
// dialect, and the dialect prefix should not be stripped while printing
|
|
// because of potential ambiguity.
|
|
// CHECK: test.dialect_custom_printer.with.dot
|
|
test.dialect_custom_printer.with.dot
|
|
"test.terminator"() : ()->()
|
|
}
|
|
// The same operation outside of the region does not have an func. prefix.
|
|
// CHECK: return
|
|
func.return
|
|
}
|
|
|
|
// CHECK-LABEL: func @unreachable_dominance_violation_ok
|
|
func.func @unreachable_dominance_violation_ok() -> i1 {
|
|
// CHECK: [[VAL:%.*]] = arith.constant false
|
|
// CHECK: return [[VAL]] : i1
|
|
// CHECK: ^bb1: // no predecessors
|
|
// CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3:%.*]]) : (i64) -> (i1, i1, i1)
|
|
// CHECK: cf.br ^bb3
|
|
// CHECK: ^bb2: // pred: ^bb2
|
|
// CHECK: cf.br ^bb2
|
|
// CHECK: ^bb3: // pred: ^bb1
|
|
// CHECK: [[VAL3]] = "foo"() : () -> i64
|
|
// CHECK: return [[VAL2]]#1 : i1
|
|
// CHECK: }
|
|
%c = arith.constant false
|
|
return %c : i1
|
|
^bb1:
|
|
// %1 is not dominated by it's definition, but block is not reachable.
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
cf.br ^bb3
|
|
^bb2:
|
|
cf.br ^bb2
|
|
^bb3:
|
|
%1 = "foo"() : ()->i64
|
|
return %2#1 : i1
|
|
}
|
|
|
|
// CHECK-LABEL: func @graph_region_in_hierarchy_ok
|
|
func.func @graph_region_in_hierarchy_ok() -> i64 {
|
|
// CHECK: cf.br ^bb2
|
|
// CHECK: ^bb1:
|
|
// CHECK: test.graph_region {
|
|
// CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3:%.*]]) : (i64) -> (i1, i1, i1)
|
|
// CHECK: }
|
|
// CHECK: cf.br ^bb3
|
|
// CHECK: ^bb2: // pred: ^bb0
|
|
// CHECK: [[VAL3]] = "foo"() : () -> i64
|
|
// CHECK: cf.br ^bb1
|
|
// CHECK: ^bb3: // pred: ^bb1
|
|
// CHECK: return [[VAL3]] : i64
|
|
// CHECK: }
|
|
cf.br ^bb2
|
|
^bb1:
|
|
test.graph_region {
|
|
// %1 is well-defined here, since bb2 dominates bb1.
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
}
|
|
cf.br ^bb4
|
|
^bb2:
|
|
%1 = "foo"() : ()->i64
|
|
cf.br ^bb1
|
|
^bb4:
|
|
return %1 : i64
|
|
}
|
|
|
|
// CHECK-LABEL: func @graph_region_kind
|
|
func.func @graph_region_kind() -> () {
|
|
// CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3:%.*]]) : (i64) -> (i1, i1, i1)
|
|
// CHECK: [[VAL3]] = "baz"([[VAL2]]#0) : (i1) -> i64
|
|
test.graph_region {
|
|
// %1 OK here in in graph region.
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
%1 = "baz"(%2#0) : (i1) -> (i64)
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @graph_region_inside_ssacfg_region
|
|
func.func @graph_region_inside_ssacfg_region() -> () {
|
|
// CHECK: "test.ssacfg_region"
|
|
// CHECK: [[VAL3:%.*]] = "baz"() : () -> i64
|
|
// CHECK: test.graph_region {
|
|
// CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3]]) : (i64) -> (i1, i1, i1)
|
|
// CHECK: }
|
|
// CHECK: [[VAL4:.*]] = "baz"() : () -> i64
|
|
"test.ssacfg_region"() ({
|
|
%1 = "baz"() : () -> (i64)
|
|
test.graph_region {
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
}
|
|
%3 = "baz"() : () -> (i64)
|
|
}) : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK-LABEL: func @graph_region_in_graph_region_ok
|
|
func.func @graph_region_in_graph_region_ok() -> () {
|
|
// CHECK: test.graph_region {
|
|
// CHECK: test.graph_region {
|
|
// CHECK: [[VAL2:%.*]]:3 = "bar"([[VAL3:%.*]]) : (i64) -> (i1, i1, i1)
|
|
// CHECK: }
|
|
// CHECK: [[VAL3]] = "foo"() : () -> i64
|
|
// CHECK: }
|
|
test.graph_region {
|
|
test.graph_region {
|
|
// %1 is well-defined here since defined in graph region
|
|
%2:3 = "bar"(%1) : (i64) -> (i1,i1,i1)
|
|
}
|
|
%1 = "foo"() : ()->i64
|
|
"test.terminator"() : ()->()
|
|
}
|
|
return
|
|
}
|
|
|
|
// CHECK: test.graph_region {
|
|
test.graph_region {
|
|
// CHECK: [[VAL1:%.*]] = "op1"([[VAL3:%.*]]) : (i32) -> i32
|
|
// CHECK: [[VAL2:%.*]] = "test.ssacfg_region"([[VAL1]], [[VAL2]], [[VAL3]], [[VAL4:%.*]]) ({
|
|
// CHECK: [[VAL5:%.*]] = "op2"([[VAL1]], [[VAL2]], [[VAL3]], [[VAL4]]) : (i32, i32, i32, i32) -> i32
|
|
// CHECK: }) : (i32, i32, i32, i32) -> i32
|
|
// CHECK: [[VAL3]] = "op2"([[VAL1]], [[VAL4]]) : (i32, i32) -> i32
|
|
// CHECK: [[VAL4]] = "op3"([[VAL1]]) : (i32) -> i32
|
|
%1 = "op1"(%3) : (i32) -> (i32)
|
|
%2 = "test.ssacfg_region"(%1, %2, %3, %4) ({
|
|
%5 = "op2"(%1, %2, %3, %4) :
|
|
(i32, i32, i32, i32) -> (i32)
|
|
}) : (i32, i32, i32, i32) -> (i32)
|
|
%3 = "op2"(%1, %4) : (i32, i32) -> (i32)
|
|
%4 = "op3"(%1) : (i32) -> (i32)
|
|
}
|
|
|
|
// CHECK: "unregistered_func_might_have_graph_region"() ({
|
|
// CHECK: [[VAL1:%.*]] = "foo"([[VAL1]], [[VAL2:%.*]]) : (i64, i64) -> i64
|
|
// CHECK: [[VAL2]] = "bar"([[VAL1]])
|
|
"unregistered_func_might_have_graph_region"() ({
|
|
%1 = "foo"(%1, %2) : (i64, i64) -> i64
|
|
%2 = "bar"(%1) : (i64) -> i64
|
|
"unregistered_terminator"() : () -> ()
|
|
}) {sym_name = "unregistered_op_dominance_violation_ok", function_type = () -> i1} : () -> ()
|
|
|
|
// This is an unregister operation, the printing/parsing is handled by the dialect.
|
|
// CHECK: test.dialect_custom_printer custom_format
|
|
test.dialect_custom_printer custom_format
|
|
|
|
// This is a registered operation with no custom parser and printer, and should
|
|
// be handled by the dialect.
|
|
// CHECK: test.dialect_custom_format_fallback custom_format_fallback
|
|
test.dialect_custom_format_fallback custom_format_fallback
|
|
|
|
// Check that an op with an optional result parses f80 as type.
|
|
// CHECK: test.format_optional_result_d_op : f80
|
|
test.format_optional_result_d_op : f80
|
|
|