1// RUN: mlir-opt %s -split-input-file \ 2// RUN: -test-one-to-n-type-conversion="convert-func-ops convert-scf-ops" \ 3// RUN: | FileCheck %s 4 5// Test case: Nested 1:N type conversion is carried through scf.if and 6// scf.yield. 7 8// CHECK-LABEL: func.func @if_result( 9// CHECK-SAME: %[[ARG0:.*]]: i1, 10// CHECK-SAME: %[[ARG1:.*]]: i2, 11// CHECK-SAME: %[[ARG2:.*]]: i1) -> (i1, i2) { 12// CHECK-NEXT: %[[V0:.*]]:2 = scf.if %[[ARG2]] -> (i1, i2) { 13// CHECK-NEXT: scf.yield %[[ARG0]], %[[ARG1]] : i1, i2 14// CHECK-NEXT: } else { 15// CHECK-NEXT: scf.yield %[[ARG0]], %[[ARG1]] : i1, i2 16// CHECK-NEXT: } 17// CHECK-NEXT: return %[[V0]]#0, %[[V0]]#1 : i1, i2 18func.func @if_result(%arg0: tuple<tuple<>, i1, tuple<i2>>, %arg1: i1) -> tuple<tuple<>, i1, tuple<i2>> { 19 %0 = scf.if %arg1 -> (tuple<tuple<>, i1, tuple<i2>>) { 20 scf.yield %arg0 : tuple<tuple<>, i1, tuple<i2>> 21 } else { 22 scf.yield %arg0 : tuple<tuple<>, i1, tuple<i2>> 23 } 24 return %0 : tuple<tuple<>, i1, tuple<i2>> 25} 26 27// ----- 28 29// Test case: Nested 1:N type conversion is carried through scf.if and 30// scf.yield and unconverted ops inside have proper materializations. 31 32// CHECK-LABEL: func.func @if_tuple_ops( 33// CHECK-SAME: %[[ARG0:.*]]: i1, 34// CHECK-SAME: %[[ARG1:.*]]: i1) -> i1 { 35// CHECK-NEXT: %[[V0:.*]] = "test.make_tuple"() : () -> tuple<> 36// CHECK-NEXT: %[[V1:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]]) : (tuple<>, i1) -> tuple<tuple<>, i1> 37// CHECK-NEXT: %[[V2:.*]] = scf.if %[[ARG1]] -> (i1) { 38// CHECK-NEXT: %[[V3:.*]] = "test.op"(%[[V1]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 39// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 40// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 41// CHECK-NEXT: scf.yield %[[V5]] : i1 42// CHECK-NEXT: } else { 43// CHECK-NEXT: %[[V6:.*]] = "test.source"() : () -> tuple<tuple<>, i1> 44// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 45// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 46// CHECK-NEXT: scf.yield %[[V8]] : i1 47// CHECK-NEXT: } 48// CHECK-NEXT: return %[[V2]] : i1 49func.func @if_tuple_ops(%arg0: tuple<tuple<>, i1>, %arg1: i1) -> tuple<tuple<>, i1> { 50 %0 = scf.if %arg1 -> (tuple<tuple<>, i1>) { 51 %1 = "test.op"(%arg0) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 52 scf.yield %1 : tuple<tuple<>, i1> 53 } else { 54 %1 = "test.source"() : () -> tuple<tuple<>, i1> 55 scf.yield %1 : tuple<tuple<>, i1> 56 } 57 return %0 : tuple<tuple<>, i1> 58} 59// ----- 60 61// Test case: Nested 1:N type conversion is carried through scf.while, 62// scf.condition, and scf.yield. 63 64// CHECK-LABEL: func.func @while_operands_results( 65// CHECK-SAME: %[[ARG0:.*]]: i1, 66// CHECK-SAME: %[[ARG1:.*]]: i2, 67// CHECK-SAME: %[[ARG2:.*]]: i1) -> (i1, i2) { 68// %[[V0:.*]]:2 = scf.while (%[[ARG3:.*]] = %[[ARG0]], %[[ARG4:.*]] = %[[ARG1]]) : (i1, i2) -> (i1, i2) { 69// scf.condition(%arg2) %[[ARG3]], %[[ARG4]] : i1, i2 70// } do { 71// ^bb0(%[[ARG5:.*]]: i1, %[[ARG6:.*]]: i2): 72// scf.yield %[[ARG5]], %[[ARG4]] : i1, i2 73// } 74// return %[[V0]]#0, %[[V0]]#1 : i1, i2 75func.func @while_operands_results(%arg0: tuple<tuple<>, i1, tuple<i2>>, %arg1: i1) -> tuple<tuple<>, i1, tuple<i2>> { 76 %0 = scf.while (%arg2 = %arg0) : (tuple<tuple<>, i1, tuple<i2>>) -> tuple<tuple<>, i1, tuple<i2>> { 77 scf.condition(%arg1) %arg2 : tuple<tuple<>, i1, tuple<i2>> 78 } do { 79 ^bb0(%arg2: tuple<tuple<>, i1, tuple<i2>>): 80 scf.yield %arg2 : tuple<tuple<>, i1, tuple<i2>> 81 } 82 return %0 : tuple<tuple<>, i1, tuple<i2>> 83} 84 85// ----- 86 87// Test case: Nested 1:N type conversion is carried through scf.while, 88// scf.condition, and unconverted ops inside have proper materializations. 89 90// CHECK-LABEL: func.func @while_tuple_ops( 91// CHECK-SAME: %[[ARG0:.*]]: i1, 92// CHECK-SAME: %[[ARG1:.*]]: i1) -> i1 { 93// CHECK-NEXT: %[[V0:.*]] = scf.while (%[[ARG2:.*]] = %[[ARG0]]) : (i1) -> i1 { 94// CHECK-NEXT: %[[V1:.*]] = "test.make_tuple"() : () -> tuple<> 95// CHECK-NEXT: %[[V2:.*]] = "test.make_tuple"(%[[V1]], %[[ARG2]]) : (tuple<>, i1) -> tuple<tuple<>, i1> 96// CHECK-NEXT: %[[V3:.*]] = "test.op"(%[[V2]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 97// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 98// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 99// CHECK-NEXT: scf.condition(%[[ARG1]]) %[[V5]] : i1 100// CHECK-NEXT: } do { 101// CHECK-NEXT: ^bb0(%[[ARG3:.*]]: i1): 102// CHECK-NEXT: %[[V6:.*]] = "test.source"() : () -> tuple<tuple<>, i1> 103// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 104// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 105// CHECK-NEXT: scf.yield %[[V8]] : i1 106// CHECK-NEXT: } 107// CHECK-NEXT: return %[[V0]] : i1 108func.func @while_tuple_ops(%arg0: tuple<tuple<>, i1>, %arg1: i1) -> tuple<tuple<>, i1> { 109 %0 = scf.while (%arg2 = %arg0) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> { 110 %1 = "test.op"(%arg2) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 111 scf.condition(%arg1) %1 : tuple<tuple<>, i1> 112 } do { 113 ^bb0(%arg2: tuple<tuple<>, i1>): 114 %1 = "test.source"() : () -> tuple<tuple<>, i1> 115 scf.yield %1 : tuple<tuple<>, i1> 116 } 117 return %0 : tuple<tuple<>, i1> 118} 119 120// ----- 121 122// Test case: Nested 1:N type conversion is carried through scf.for and scf.yield. 123 124// CHECK-LABEL: func.func @for_operands_results( 125// CHECK-SAME: %[[ARG0:.*]]: i1, 126// CHECK-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) { 127// CHECK-NEXT: %[[C0:.+]] = arith.constant 0 : index 128// CHECK-NEXT: %[[C1:.+]] = arith.constant 1 : index 129// CHECK-NEXT: %[[C10:.+]] = arith.constant 10 : index 130// CHECK-NEXT: %[[OUT:.+]]:2 = scf.for %arg2 = %[[C0]] to %[[C10]] step %[[C1]] iter_args(%[[ITER0:.+]] = %[[ARG0]], %[[ITER1:.+]] = %[[ARG1]]) -> (i1, i2) { 131// CHECK-NEXT: scf.yield %[[ITER0]], %[[ITER1]] : i1, i2 132// CHECK-NEXT: } 133// CHECK-NEXT: return %[[OUT]]#0, %[[OUT]]#1 : i1, i2 134 135func.func @for_operands_results(%arg0: tuple<tuple<>, i1, tuple<i2>>) -> tuple<tuple<>, i1, tuple<i2>> { 136 %c0 = arith.constant 0 : index 137 %c1 = arith.constant 1 : index 138 %c10 = arith.constant 10 : index 139 140 %0 = scf.for %i = %c0 to %c10 step %c1 iter_args(%acc = %arg0) -> tuple<tuple<>, i1, tuple<i2>> { 141 scf.yield %acc : tuple<tuple<>, i1, tuple<i2>> 142 } 143 144 return %0 : tuple<tuple<>, i1, tuple<i2>> 145} 146 147// ----- 148 149// Test case: Nested 1:N type conversion is carried through scf.for and scf.yield 150 151// CHECK-LABEL: func.func @for_tuple_ops( 152// CHECK-SAME: %[[ARG0:.+]]: i1) -> i1 { 153// CHECK-NEXT: %[[C0:.+]] = arith.constant 0 : index 154// CHECK-NEXT: %[[C1:.+]] = arith.constant 1 : index 155// CHECK-NEXT: %[[C10:.+]] = arith.constant 10 : index 156// CHECK-NEXT: %[[FOR:.+]] = scf.for %arg1 = %[[C0]] to %[[C10]] step %[[C1]] iter_args(%[[ITER:.+]] = %[[ARG0]]) -> (i1) { 157// CHECK-NEXT: %[[V1:.+]] = "test.make_tuple"() : () -> tuple<> 158// CHECK-NEXT: %[[V2:.+]] = "test.make_tuple"(%[[V1]], %[[ITER]]) : (tuple<>, i1) -> tuple<tuple<>, i1> 159// CHECK-NEXT: %[[V3:.+]] = "test.op"(%[[V2]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 160// CHECK-NEXT: %[[V4:.+]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 161// CHECK-NEXT: %[[V5:.+]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 162// CHECK-NEXT: scf.yield %[[V5]] : i1 163// CHECK-NEXT: } 164// CHECK-NEXT: %[[V6:.+]] = "test.make_tuple"() : () -> tuple<> 165// CHECK-NEXT: %[[V7:.+]] = "test.make_tuple"(%[[V6]], %[[FOR]]) : (tuple<>, i1) -> tuple<tuple<>, i1> 166// CHECK-NEXT: %[[V8:.+]] = "test.op"(%[[V7]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 167// CHECK-NEXT: %[[V9:.+]] = "test.get_tuple_element"(%[[V8]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<> 168// CHECK-NEXT: %[[V10:.+]] = "test.get_tuple_element"(%[[V8]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1 169// CHECK-NEXT: return %[[V10]] : i1 170 171func.func @for_tuple_ops(%arg0: tuple<tuple<>, i1>) -> tuple<tuple<>, i1> { 172 %c0 = arith.constant 0 : index 173 %c1 = arith.constant 1 : index 174 %c10 = arith.constant 10 : index 175 176 %0 = scf.for %i = %c0 to %c10 step %c1 iter_args(%acc = %arg0) -> tuple<tuple<>, i1> { 177 %1 = "test.op"(%acc) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 178 scf.yield %1 : tuple<tuple<>, i1> 179 } 180 181 %1 = "test.op"(%0) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1> 182 return %1 : tuple<tuple<>, i1> 183} 184