// RUN: mlir-opt %s -split-input-file -pass-pipeline='func(canonicalize)' | FileCheck %s //===----------------------------------------------------------------------===// // spv.AccessChain //===----------------------------------------------------------------------===// func @combine_full_access_chain() -> f32 { // CHECK: %[[INDEX:.*]] = spv.constant 0 // CHECK-NEXT: %[[VAR:.*]] = spv.Variable // CHECK-NEXT: %[[PTR:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]] // CHECK-NEXT: spv.Load "Function" %[[PTR]] %c0 = spv.constant 0: i32 %0 = spv.Variable : !spv.ptr>, !spv.array<4xi32>)>, Function> %1 = spv.AccessChain %0[%c0] : !spv.ptr>, !spv.array<4xi32>)>, Function>, i32 %2 = spv.AccessChain %1[%c0, %c0] : !spv.ptr>, Function>, i32, i32 %3 = spv.Load "Function" %2 : f32 spv.ReturnValue %3 : f32 } // ----- func @combine_access_chain_multi_use() -> !spv.array<4xf32> { // CHECK: %[[INDEX:.*]] = spv.constant 0 // CHECK-NEXT: %[[VAR:.*]] = spv.Variable // CHECK-NEXT: %[[PTR_0:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]]] // CHECK-NEXT: %[[PTR_1:.*]] = spv.AccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]] // CHECK-NEXT: spv.Load "Function" %[[PTR_0]] // CHECK-NEXT: spv.Load "Function" %[[PTR_1]] %c0 = spv.constant 0: i32 %0 = spv.Variable : !spv.ptr>, !spv.array<4xi32>)>, Function> %1 = spv.AccessChain %0[%c0] : !spv.ptr>, !spv.array<4xi32>)>, Function>, i32 %2 = spv.AccessChain %1[%c0] : !spv.ptr>, Function>, i32 %3 = spv.AccessChain %2[%c0] : !spv.ptr, Function>, i32 %4 = spv.Load "Function" %2 : !spv.array<4xf32> %5 = spv.Load "Function" %3 : f32 spv.ReturnValue %4: !spv.array<4xf32> } // ----- func @dont_combine_access_chain_without_common_base() -> !spv.array<4xi32> { // CHECK: %[[INDEX:.*]] = spv.constant 1 // CHECK-NEXT: %[[VAR_0:.*]] = spv.Variable // CHECK-NEXT: %[[VAR_1:.*]] = spv.Variable // CHECK-NEXT: %[[VAR_0_PTR:.*]] = spv.AccessChain %[[VAR_0]][%[[INDEX]]] // CHECK-NEXT: %[[VAR_1_PTR:.*]] = spv.AccessChain %[[VAR_1]][%[[INDEX]]] // CHECK-NEXT: spv.Load "Function" %[[VAR_0_PTR]] // CHECK-NEXT: spv.Load "Function" %[[VAR_1_PTR]] %c1 = spv.constant 1: i32 %0 = spv.Variable : !spv.ptr>, !spv.array<4xi32>)>, Function> %1 = spv.Variable : !spv.ptr>, !spv.array<4xi32>)>, Function> %2 = spv.AccessChain %0[%c1] : !spv.ptr>, !spv.array<4xi32>)>, Function>, i32 %3 = spv.AccessChain %1[%c1] : !spv.ptr>, !spv.array<4xi32>)>, Function>, i32 %4 = spv.Load "Function" %2 : !spv.array<4xi32> %5 = spv.Load "Function" %3 : !spv.array<4xi32> spv.ReturnValue %4 : !spv.array<4xi32> } // ----- //===----------------------------------------------------------------------===// // spv.Bitcast //===----------------------------------------------------------------------===// func @convert_bitcast_full(%arg0 : vector<2xf32>) -> f64 { // CHECK: %[[RESULT:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to f64 // CHECK-NEXT: spv.ReturnValue %[[RESULT]] %0 = spv.Bitcast %arg0 : vector<2xf32> to vector<2xi32> %1 = spv.Bitcast %0 : vector<2xi32> to i64 %2 = spv.Bitcast %1 : i64 to f64 spv.ReturnValue %2 : f64 } // ----- func @convert_bitcast_multi_use(%arg0 : vector<2xf32>, %arg1 : !spv.ptr) -> f64 { // CHECK: %[[RESULT_0:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to i64 // CHECK-NEXT: %[[RESULT_1:.*]] = spv.Bitcast {{%.*}} : vector<2xf32> to f64 // CHECK-NEXT: spv.Store {{".*"}} {{%.*}}, %[[RESULT_0]] // CHECK-NEXT: spv.ReturnValue %[[RESULT_1]] %0 = spv.Bitcast %arg0 : vector<2xf32> to i64 %1 = spv.Bitcast %0 : i64 to f64 spv.Store "Uniform" %arg1, %0 : i64 spv.ReturnValue %1 : f64 } // ----- //===----------------------------------------------------------------------===// // spv.CompositeExtract //===----------------------------------------------------------------------===// // CHECK-LABEL: extract_vector func @extract_vector() -> (i32, i32, i32) { // CHECK: spv.constant 42 : i32 // CHECK: spv.constant -33 : i32 // CHECK: spv.constant 6 : i32 %0 = spv.constant dense<[42, -33, 6]> : vector<3xi32> %1 = spv.CompositeExtract %0[0 : i32] : vector<3xi32> %2 = spv.CompositeExtract %0[1 : i32] : vector<3xi32> %3 = spv.CompositeExtract %0[2 : i32] : vector<3xi32> return %1, %2, %3 : i32, i32, i32 } // ----- // CHECK-LABEL: extract_array_final func @extract_array_final() -> (i32, i32) { // CHECK: spv.constant 4 : i32 // CHECK: spv.constant -5 : i32 %0 = spv.constant [dense<[4, -5]> : vector<2xi32>] : !spv.array<1 x vector<2xi32>> %1 = spv.CompositeExtract %0[0 : i32, 0 : i32] : !spv.array<1 x vector<2 x i32>> %2 = spv.CompositeExtract %0[0 : i32, 1 : i32] : !spv.array<1 x vector<2 x i32>> return %1, %2 : i32, i32 } // ----- // CHECK-LABEL: extract_array_interm func @extract_array_interm() -> (vector<2xi32>) { // CHECK: spv.constant dense<[4, -5]> : vector<2xi32> %0 = spv.constant [dense<[4, -5]> : vector<2xi32>] : !spv.array<1 x vector<2xi32>> %1 = spv.CompositeExtract %0[0 : i32] : !spv.array<1 x vector<2 x i32>> return %1 : vector<2xi32> } // ----- // CHECK-LABEL: extract_from_not_constant func @extract_from_not_constant() -> i32 { %0 = spv.Variable : !spv.ptr, Function> %1 = spv.Load "Function" %0 : vector<3xi32> // CHECK: spv.CompositeExtract %2 = spv.CompositeExtract %1[0 : i32] : vector<3xi32> spv.ReturnValue %2 : i32 } // ----- //===----------------------------------------------------------------------===// // spv.constant //===----------------------------------------------------------------------===// // TODO: test constants in different blocks func @deduplicate_scalar_constant() -> (i32, i32) { // CHECK: %[[CST:.*]] = spv.constant 42 : i32 %0 = spv.constant 42 : i32 %1 = spv.constant 42 : i32 // CHECK-NEXT: return %[[CST]], %[[CST]] return %0, %1 : i32, i32 } // ----- func @deduplicate_vector_constant() -> (vector<3xi32>, vector<3xi32>) { // CHECK: %[[CST:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %0 = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK-NEXT: return %[[CST]], %[[CST]] return %0, %1 : vector<3xi32>, vector<3xi32> } // ----- func @deduplicate_composite_constant() -> (!spv.array<1 x vector<2xi32>>, !spv.array<1 x vector<2xi32>>) { // CHECK: %[[CST:.*]] = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>> %0 = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>> %1 = spv.constant [dense<5> : vector<2xi32>] : !spv.array<1 x vector<2xi32>> // CHECK-NEXT: return %[[CST]], %[[CST]] return %0, %1 : !spv.array<1 x vector<2xi32>>, !spv.array<1 x vector<2xi32>> } // ----- //===----------------------------------------------------------------------===// // spv.IAdd //===----------------------------------------------------------------------===// // CHECK-LABEL: @iadd_zero // CHECK-SAME: (%[[ARG:.*]]: i32) func @iadd_zero(%arg0: i32) -> (i32, i32) { %zero = spv.constant 0 : i32 %0 = spv.IAdd %arg0, %zero : i32 %1 = spv.IAdd %zero, %arg0 : i32 // CHECK: return %[[ARG]], %[[ARG]] return %0, %1: i32, i32 } // CHECK-LABEL: @const_fold_scalar_iadd_normal func @const_fold_scalar_iadd_normal() -> (i32, i32, i32) { %c5 = spv.constant 5 : i32 %cn8 = spv.constant -8 : i32 // CHECK: spv.constant 10 // CHECK: spv.constant -16 // CHECK: spv.constant -3 %0 = spv.IAdd %c5, %c5 : i32 %1 = spv.IAdd %cn8, %cn8 : i32 %2 = spv.IAdd %c5, %cn8 : i32 return %0, %1, %2: i32, i32, i32 } // CHECK-LABEL: @const_fold_scalar_iadd_flow func @const_fold_scalar_iadd_flow() -> (i32, i32, i32, i32) { %c1 = spv.constant 1 : i32 %c2 = spv.constant 2 : i32 %c3 = spv.constant 4294967295 : i32 // 2^32 - 1: 0xffff ffff %c4 = spv.constant -2147483648 : i32 // -2^31 : 0x8000 0000 %c5 = spv.constant -1 : i32 // : 0xffff ffff %c6 = spv.constant -2 : i32 // : 0xffff fffe // 0x0000 0001 + 0xffff ffff = 0x1 0000 0000 -> 0x0000 0000 // CHECK: spv.constant 0 %0 = spv.IAdd %c1, %c3 : i32 // 0x0000 0002 + 0xffff ffff = 0x1 0000 0001 -> 0x0000 0001 // CHECK: spv.constant 1 %1 = spv.IAdd %c2, %c3 : i32 // 0x8000 0000 + 0xffff ffff = 0x1 7fff ffff -> 0x7fff ffff // CHECK: spv.constant 2147483647 %2 = spv.IAdd %c4, %c5 : i32 // 0x8000 0000 + 0xffff fffe = 0x1 7fff fffe -> 0x7fff fffe // CHECK: spv.constant 2147483646 %3 = spv.IAdd %c4, %c6 : i32 return %0, %1, %2, %3: i32, i32, i32, i32 } // CHECK-LABEL: @const_fold_vector_iadd func @const_fold_vector_iadd() -> vector<3xi32> { %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32> %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32> // CHECK: spv.constant dense<[39, -70, 155]> %0 = spv.IAdd %vc1, %vc2 : vector<3xi32> return %0: vector<3xi32> } // ----- //===----------------------------------------------------------------------===// // spv.IMul //===----------------------------------------------------------------------===// // CHECK-LABEL: @imul_zero_one // CHECK-SAME: (%[[ARG:.*]]: i32) func @imul_zero_one(%arg0: i32) -> (i32, i32) { // CHECK: %[[ZERO:.*]] = spv.constant 0 %zero = spv.constant 0 : i32 %one = spv.constant 1: i32 %0 = spv.IMul %arg0, %zero : i32 %1 = spv.IMul %one, %arg0 : i32 // CHECK: return %[[ZERO]], %[[ARG]] return %0, %1: i32, i32 } // CHECK-LABEL: @const_fold_scalar_imul_normal func @const_fold_scalar_imul_normal() -> (i32, i32, i32) { %c5 = spv.constant 5 : i32 %cn8 = spv.constant -8 : i32 %c7 = spv.constant 7 : i32 // CHECK: spv.constant 35 // CHECK: spv.constant -40 // CHECK: spv.constant -56 %0 = spv.IMul %c7, %c5 : i32 %1 = spv.IMul %c5, %cn8 : i32 %2 = spv.IMul %cn8, %c7 : i32 return %0, %1, %2: i32, i32, i32 } // CHECK-LABEL: @const_fold_scalar_imul_flow func @const_fold_scalar_imul_flow() -> (i32, i32, i32) { %c1 = spv.constant 2 : i32 %c2 = spv.constant 4 : i32 %c3 = spv.constant 4294967295 : i32 // 2^32 - 1 : 0xffff ffff %c4 = spv.constant 2147483647 : i32 // 2^31 - 1 : 0x7fff ffff // (0xffff ffff << 1) = 0x1 ffff fffe -> 0xffff fffe // CHECK: %[[CST2:.*]] = spv.constant -2 %0 = spv.IMul %c1, %c3 : i32 // (0x7fff ffff << 1) = 0x0 ffff fffe -> 0xffff fffe %1 = spv.IMul %c1, %c4 : i32 // (0x7fff ffff << 2) = 0x1 ffff fffc -> 0xffff fffc // CHECK: %[[CST4:.*]] = spv.constant -4 %2 = spv.IMul %c4, %c2 : i32 // CHECK: return %[[CST2]], %[[CST2]], %[[CST4]] return %0, %1, %2: i32, i32, i32 } // CHECK-LABEL: @const_fold_vector_imul func @const_fold_vector_imul() -> vector<3xi32> { %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32> %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32> // CHECK: spv.constant dense<[-126, 825, 3556]> %0 = spv.IMul %vc1, %vc2 : vector<3xi32> return %0: vector<3xi32> } // ----- //===----------------------------------------------------------------------===// // spv.ISub //===----------------------------------------------------------------------===// // CHECK-LABEL: @isub_x_x func @isub_x_x(%arg0: i32) -> i32 { // CHECK: spv.constant 0 %0 = spv.ISub %arg0, %arg0: i32 return %0: i32 } // CHECK-LABEL: @const_fold_scalar_isub_normal func @const_fold_scalar_isub_normal() -> (i32, i32, i32) { %c5 = spv.constant 5 : i32 %cn8 = spv.constant -8 : i32 %c7 = spv.constant 7 : i32 // CHECK: spv.constant 2 // CHECK: spv.constant 13 // CHECK: spv.constant -15 %0 = spv.ISub %c7, %c5 : i32 %1 = spv.ISub %c5, %cn8 : i32 %2 = spv.ISub %cn8, %c7 : i32 return %0, %1, %2: i32, i32, i32 } // CHECK-LABEL: @const_fold_scalar_isub_flow func @const_fold_scalar_isub_flow() -> (i32, i32, i32, i32) { %c1 = spv.constant 0 : i32 %c2 = spv.constant 1 : i32 %c3 = spv.constant 4294967295 : i32 // 2^32 - 1 : 0xffff ffff %c4 = spv.constant 2147483647 : i32 // 2^31 : 0x7fff ffff %c5 = spv.constant -1 : i32 // : 0xffff ffff %c6 = spv.constant -2 : i32 // : 0xffff fffe // 0x0000 0000 - 0xffff ffff -> 0x0000 0000 + 0x0000 0001 = 0x0000 0001 // CHECK: spv.constant 1 %0 = spv.ISub %c1, %c3 : i32 // 0x0000 0001 - 0xffff ffff -> 0x0000 0001 + 0x0000 0001 = 0x0000 0002 // CHECK: spv.constant 2 %1 = spv.ISub %c2, %c3 : i32 // 0xffff ffff - 0x7fff ffff -> 0xffff ffff + 0x8000 0001 = 0x1 8000 0000 // CHECK: spv.constant -2147483648 %2 = spv.ISub %c5, %c4 : i32 // 0xffff fffe - 0x7fff ffff -> 0xffff fffe + 0x8000 0001 = 0x1 7fff ffff // CHECK: spv.constant 2147483647 %3 = spv.ISub %c6, %c4 : i32 return %0, %1, %2, %3: i32, i32, i32, i32 } // CHECK-LABEL: @const_fold_vector_isub func @const_fold_vector_isub() -> vector<3xi32> { %vc1 = spv.constant dense<[42, -55, 127]> : vector<3xi32> %vc2 = spv.constant dense<[-3, -15, 28]> : vector<3xi32> // CHECK: spv.constant dense<[45, -40, 99]> %0 = spv.ISub %vc1, %vc2 : vector<3xi32> return %0: vector<3xi32> } // ----- //===----------------------------------------------------------------------===// // spv.LogicalAnd //===----------------------------------------------------------------------===// // CHECK-LABEL: @convert_logical_and_true_false_scalar // CHECK-SAME: %[[ARG:.+]]: i1 func @convert_logical_and_true_false_scalar(%arg: i1) -> (i1, i1) { %true = spv.constant true // CHECK: %[[FALSE:.+]] = spv.constant false %false = spv.constant false %0 = spv.LogicalAnd %true, %arg: i1 %1 = spv.LogicalAnd %arg, %false: i1 // CHECK: return %[[ARG]], %[[FALSE]] return %0, %1: i1, i1 } // CHECK-LABEL: @convert_logical_and_true_false_vector // CHECK-SAME: %[[ARG:.+]]: vector<3xi1> func @convert_logical_and_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) { %true = spv.constant dense : vector<3xi1> // CHECK: %[[FALSE:.+]] = spv.constant dense %false = spv.constant dense : vector<3xi1> %0 = spv.LogicalAnd %true, %arg: vector<3xi1> %1 = spv.LogicalAnd %arg, %false: vector<3xi1> // CHECK: return %[[ARG]], %[[FALSE]] return %0, %1: vector<3xi1>, vector<3xi1> } // ----- //===----------------------------------------------------------------------===// // spv.LogicalNot //===----------------------------------------------------------------------===// func @convert_logical_not_to_not_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> { // CHECK: %[[RESULT:.*]] = spv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64> // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1> %2 = spv.IEqual %arg0, %arg1 : vector<3xi64> %3 = spv.LogicalNot %2 : vector<3xi1> spv.ReturnValue %3 : vector<3xi1> } // ----- func @convert_logical_not_to_equal(%arg0: vector<3xi64>, %arg1: vector<3xi64>) -> vector<3xi1> { // CHECK: %[[RESULT:.*]] = spv.IEqual {{%.*}}, {{%.*}} : vector<3xi64> // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1> %2 = spv.INotEqual %arg0, %arg1 : vector<3xi64> %3 = spv.LogicalNot %2 : vector<3xi1> spv.ReturnValue %3 : vector<3xi1> } // ----- func @convert_logical_not_parent_multi_use(%arg0: vector<3xi64>, %arg1: vector<3xi64>, %arg2: !spv.ptr, Uniform>) -> vector<3xi1> { // CHECK: %[[RESULT_0:.*]] = spv.INotEqual {{%.*}}, {{%.*}} : vector<3xi64> // CHECK-NEXT: %[[RESULT_1:.*]] = spv.IEqual {{%.*}}, {{%.*}} : vector<3xi64> // CHECK-NEXT: spv.Store "Uniform" {{%.*}}, %[[RESULT_0]] // CHECK-NEXT: spv.ReturnValue %[[RESULT_1]] %0 = spv.INotEqual %arg0, %arg1 : vector<3xi64> %1 = spv.LogicalNot %0 : vector<3xi1> spv.Store "Uniform" %arg2, %0 : vector<3xi1> spv.ReturnValue %1 : vector<3xi1> } // ----- func @convert_logical_not_to_logical_not_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> { // CHECK: %[[RESULT:.*]] = spv.LogicalNotEqual {{%.*}}, {{%.*}} : vector<3xi1> // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1> %2 = spv.LogicalEqual %arg0, %arg1 : vector<3xi1> %3 = spv.LogicalNot %2 : vector<3xi1> spv.ReturnValue %3 : vector<3xi1> } // ----- func @convert_logical_not_to_logical_equal(%arg0: vector<3xi1>, %arg1: vector<3xi1>) -> vector<3xi1> { // CHECK: %[[RESULT:.*]] = spv.LogicalEqual {{%.*}}, {{%.*}} : vector<3xi1> // CHECK-NEXT: spv.ReturnValue %[[RESULT]] : vector<3xi1> %2 = spv.LogicalNotEqual %arg0, %arg1 : vector<3xi1> %3 = spv.LogicalNot %2 : vector<3xi1> spv.ReturnValue %3 : vector<3xi1> } // ----- //===----------------------------------------------------------------------===// // spv.LogicalOr //===----------------------------------------------------------------------===// // CHECK-LABEL: @convert_logical_or_true_false_scalar // CHECK-SAME: %[[ARG:.+]]: i1 func @convert_logical_or_true_false_scalar(%arg: i1) -> (i1, i1) { // CHECK: %[[TRUE:.+]] = spv.constant true %true = spv.constant true %false = spv.constant false %0 = spv.LogicalOr %true, %arg: i1 %1 = spv.LogicalOr %arg, %false: i1 // CHECK: return %[[TRUE]], %[[ARG]] return %0, %1: i1, i1 } // CHECK-LABEL: @convert_logical_or_true_false_vector // CHECK-SAME: %[[ARG:.+]]: vector<3xi1> func @convert_logical_or_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>, vector<3xi1>) { // CHECK: %[[TRUE:.+]] = spv.constant dense %true = spv.constant dense : vector<3xi1> %false = spv.constant dense : vector<3xi1> %0 = spv.LogicalOr %true, %arg: vector<3xi1> %1 = spv.LogicalOr %arg, %false: vector<3xi1> // CHECK: return %[[TRUE]], %[[ARG]] return %0, %1: vector<3xi1>, vector<3xi1> } // ----- //===----------------------------------------------------------------------===// // spv.selection //===----------------------------------------------------------------------===// func @canonicalize_selection_op_scalar_type(%cond: i1) -> () { %0 = spv.constant 0: i32 // CHECK: %[[TRUE_VALUE:.*]] = spv.constant 1 : i32 %1 = spv.constant 1: i32 // CHECK: %[[FALSE_VALUE:.*]] = spv.constant 2 : i32 %2 = spv.constant 2: i32 // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr %3 = spv.Variable init(%0) : !spv.ptr // CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, i32 // CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 4] : i32 // CHECK-NEXT: spv.Return spv.selection { spv.BranchConditional %cond, ^then, ^else ^else: spv.Store "Function" %3, %2 ["Aligned", 4]: i32 spv.Branch ^merge ^then: spv.Store "Function" %3, %1 ["Aligned", 4]: i32 spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return } // ----- func @canonicalize_selection_op_vector_type(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[TRUE_VALUE:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[FALSE_VALUE:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, vector<3xi32> // CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 8] : vector<3xi32> // CHECK-NEXT: spv.Return spv.selection { spv.BranchConditional %cond, ^then, ^else ^then: spv.Store "Function" %3, %1 ["Aligned", 8]: vector<3xi32> spv.Branch ^merge ^else: spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return } // ----- // Store to a different variables. func @cannot_canonicalize_selection_op_0(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR_0:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %4 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: spv.selection { spv.selection { // CHECK: spv.BranchConditional // CHECK-SAME: ^bb1(%[[DST_VAR_0]], %[[SRC_VALUE_0]] // CHECK-SAME: ^bb1(%[[DST_VAR_1]], %[[SRC_VALUE_1]] spv.BranchConditional %cond, ^then, ^else ^then: // CHECK: ^bb1(%[[ARG0:.*]]: !spv.ptr, Function>, %[[ARG1:.*]]: vector<3xi32>): // CHECK: spv.Store "Function" %[[ARG0]], %[[ARG1]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %1 ["Aligned", 8]: vector<3xi32> spv.Branch ^merge ^else: spv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return } // ----- // A conditional block consists of more than 2 operations. func @cannot_canonicalize_selection_op_1(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR_0:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %4 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: spv.selection { spv.selection { spv.BranchConditional %cond, ^then, ^else ^then: // CHECK: spv.Store "Function" %[[DST_VAR_0]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %1 ["Aligned", 8] : vector<3xi32> // CHECK: spv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %4, %1 ["Aligned", 8]: vector<3xi32> spv.Branch ^merge ^else: // CHECK: spv.Store "Function" %[[DST_VAR_1]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %4, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return } // ----- // A control-flow goes into `^then` block from `^else` block. func @cannot_canonicalize_selection_op_2(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: spv.selection { spv.selection { spv.BranchConditional %cond, ^then, ^else ^then: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %1 ["Aligned", 8]: vector<3xi32> spv.Branch ^merge ^else: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^then ^merge: spv.mlir.merge } spv.Return } // ----- // `spv.Return` as a block terminator. func @cannot_canonicalize_selection_op_3(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: spv.selection { spv.selection { spv.BranchConditional %cond, ^then, ^else ^then: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %1 ["Aligned", 8]: vector<3xi32> spv.Return ^else: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return } // ----- // Different memory access attributes. func @cannot_canonicalize_selection_op_4(%cond: i1) -> () { %0 = spv.constant dense<[0, 1, 2]> : vector<3xi32> // CHECK: %[[SRC_VALUE_0:.*]] = spv.constant dense<[1, 2, 3]> : vector<3xi32> %1 = spv.constant dense<[1, 2, 3]> : vector<3xi32> // CHECK: %[[SRC_VALUE_1:.*]] = spv.constant dense<[2, 3, 4]> : vector<3xi32> %2 = spv.constant dense<[2, 3, 4]> : vector<3xi32> // CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr, Function> %3 = spv.Variable init(%0) : !spv.ptr, Function> // CHECK: spv.selection { spv.selection { spv.BranchConditional %cond, ^then, ^else ^then: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_0]] ["Aligned", 4] : vector<3xi32> spv.Store "Function" %3, %1 ["Aligned", 4]: vector<3xi32> spv.Branch ^merge ^else: // CHECK: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE_1]] ["Aligned", 8] : vector<3xi32> spv.Store "Function" %3, %2 ["Aligned", 8] : vector<3xi32> spv.Branch ^merge ^merge: spv.mlir.merge } spv.Return }