1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
// RUN: mlir-opt %s -split-input-file \
// RUN: -test-one-to-n-type-conversion="convert-tuple-ops" \
// RUN: | FileCheck --check-prefix=CHECK-TUP %s
// RUN: mlir-opt %s -split-input-file \
// RUN: -test-one-to-n-type-conversion="convert-func-ops" \
// RUN: | FileCheck --check-prefix=CHECK-FUNC %s
// RUN: mlir-opt %s -split-input-file \
// RUN: -test-one-to-n-type-conversion="convert-func-ops convert-tuple-ops" \
// RUN: | FileCheck --check-prefix=CHECK-BOTH %s
// Test case: Matching nested packs and unpacks just disappear.
// CHECK-TUP-LABEL: func.func @pack_unpack(
// CHECK-TUP-SAME: %[[ARG0:.*]]: i1,
// CHECK-TUP-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) {
// CHECK-TUP-DAG: return %[[ARG0]], %[[ARG1]] : i1, i2
func.func @pack_unpack(%arg0: i1, %arg1: i2) -> (i1, i2) {
%0 = "test.make_tuple"() : () -> tuple<>
%1 = "test.make_tuple"(%arg1) : (i2) -> tuple<i2>
%2 = "test.make_tuple"(%1) : (tuple<i2>) -> tuple<tuple<i2>>
%3 = "test.make_tuple"(%0, %arg0, %2) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
%4 = "test.get_tuple_element"(%3) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
%5 = "test.get_tuple_element"(%3) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
%6 = "test.get_tuple_element"(%3) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
%7 = "test.get_tuple_element"(%6) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
%8 = "test.get_tuple_element"(%7) {index = 0 : i32} : (tuple<i2>) -> i2
return %5, %8 : i1, i2
}
// -----
// Test case: Appropriate materializations are created depending on which ops
// are converted.
// If we only convert the tuple ops, the original `get_tuple_element` ops will
// disappear but one target materialization will be inserted from the
// unconverted function arguments to each of the return values (which have
// redundancy among themselves).
//
// CHECK-TUP-LABEL: func.func @materializations_tuple_args(
// CHECK-TUP-SAME: %[[ARG0:.*]]: tuple<tuple<>, i1, tuple<tuple<i2>>>) -> (i1, i2) {
// CHECK-TUP-DAG: %[[V0:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
// CHECK-TUP-DAG: %[[V1:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
// CHECK-TUP-DAG: %[[V2:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
// CHECK-TUP-DAG: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
// CHECK-TUP-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
// CHECK-TUP-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
// CHECK-TUP-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
// CHECK-TUP-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
// CHECK-TUP-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
// CHECK-TUP-DAG: %[[V9:.*]] = "test.get_tuple_element"(%[[V8]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
// CHECK-TUP-DAG: return %[[V1]], %[[V9]] : i1, i2
// If we only convert the func ops, argument materializations are created from
// the converted tuple elements back to the tuples that the `get_tuple_element`
// ops expect.
//
// CHECK-FUNC-LABEL: func.func @materializations_tuple_args(
// CHECK-FUNC-SAME: %[[ARG0:.*]]: i1,
// CHECK-FUNC-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) {
// CHECK-FUNC-DAG: %[[V0:.*]] = "test.make_tuple"() : () -> tuple<>
// CHECK-FUNC-DAG: %[[V1:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
// CHECK-FUNC-DAG: %[[V2:.*]] = "test.make_tuple"(%[[V1]]) : (tuple<i2>) -> tuple<tuple<i2>>
// CHECK-FUNC-DAG: %[[V3:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]], %[[V2]]) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
// CHECK-FUNC-DAG: return %[[V5]], %[[V8]] : i1, i2
// If we convert both tuple and func ops, basically everything disappears.
//
// CHECK-BOTH-LABEL: func.func @materializations_tuple_args(
// CHECK-BOTH-SAME: %[[ARG0:.*]]: i1,
// CHECK-BOTH-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) {
// CHECK-BOTH-DAG: return %[[ARG0]], %[[ARG1]] : i1, i2
func.func @materializations_tuple_args(%arg0: tuple<tuple<>, i1, tuple<tuple<i2>>>) -> (i1, i2) {
%0 = "test.get_tuple_element"(%arg0) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
%1 = "test.get_tuple_element"(%arg0) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
%2 = "test.get_tuple_element"(%arg0) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
%3 = "test.get_tuple_element"(%2) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
%4 = "test.get_tuple_element"(%3) {index = 0 : i32} : (tuple<i2>) -> i2
return %1, %4 : i1, i2
}
// -----
// Test case: Appropriate materializations are created depending on which ops
// are converted.
// If we only convert the tuple ops, the original `make_tuple` ops will
// disappear but a source materialization will be inserted from the result of
// conversion (which, for `make_tuple`, are the original ops that get forwarded)
// to the operands of the unconverted op with the original type (i.e.,
// `return`).
// CHECK-TUP-LABEL: func.func @materializations_tuple_return(
// CHECK-TUP-SAME: %[[ARG0:.*]]: i1,
// CHECK-TUP-SAME: %[[ARG1:.*]]: i2) -> tuple<tuple<>, i1, tuple<tuple<i2>>> {
// CHECK-TUP-DAG: %[[V0:.*]] = "test.make_tuple"() : () -> tuple<>
// CHECK-TUP-DAG: %[[V1:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
// CHECK-TUP-DAG: %[[V2:.*]] = "test.make_tuple"(%[[V1]]) : (tuple<i2>) -> tuple<tuple<i2>>
// CHECK-TUP-DAG: %[[V3:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]], %[[V2]]) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
// CHECK-TUP-DAG: return %[[V3]] : tuple<tuple<>, i1, tuple<tuple<i2>>>
// If we only convert the func ops, target materializations are created from
// original tuples produced by `make_tuple` to its constituent elements that the
// converted op (i.e., `return`) expect.
//
// CHECK-FUNC-LABEL: func.func @materializations_tuple_return(
// CHECK-FUNC-SAME: %[[ARG0:.*]]: i1,
// CHECK-FUNC-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) {
// CHECK-FUNC-DAG: %[[V0:.*]] = "test.make_tuple"() : () -> tuple<>
// CHECK-FUNC-DAG: %[[V1:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
// CHECK-FUNC-DAG: %[[V2:.*]] = "test.make_tuple"(%[[V1]]) : (tuple<i2>) -> tuple<tuple<i2>>
// CHECK-FUNC-DAG: %[[V3:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]], %[[V2]]) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
// CHECK-FUNC-DAG: return %[[V5]], %[[V8]] : i1, i2
// If we convert both tuple and func ops, basically everything disappears.
//
// CHECK-BOTH-LABEL: func.func @materializations_tuple_return(
// CHECK-BOTH-SAME: %[[ARG0:.*]]: i1,
// CHECK-BOTH-SAME: %[[ARG1:.*]]: i2) -> (i1, i2) {
// CHECK-BOTH-DAG: return %[[ARG0]], %[[ARG1]] : i1, i2
func.func @materializations_tuple_return(%arg0: i1, %arg1: i2) -> tuple<tuple<>, i1, tuple<tuple<i2>>> {
%0 = "test.make_tuple"() : () -> tuple<>
%1 = "test.make_tuple"(%arg1) : (i2) -> tuple<i2>
%2 = "test.make_tuple"(%1) : (tuple<i2>) -> tuple<tuple<i2>>
%3 = "test.make_tuple"(%0, %arg0, %2) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
return %3 : tuple<tuple<>, i1, tuple<tuple<i2>>>
}
|