blob: 37553fd4f23a0d43561a39f88528756e1f7be8a6 [file] [log] [blame]
// RUN: mlir-opt %s -split-input-file -pass-pipeline='builtin.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.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
%1 = spv.AccessChain %0[%c0] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
%2 = spv.AccessChain %1[%c0, %c0] : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, 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.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
%1 = spv.AccessChain %0[%c0] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
%2 = spv.AccessChain %1[%c0] : !spv.ptr<!spv.array<4x!spv.array<4xf32>>, Function>, i32
%3 = spv.AccessChain %2[%c0] : !spv.ptr<!spv.array<4xf32>, 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.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
%1 = spv.Variable : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>
%2 = spv.AccessChain %0[%c1] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !spv.array<4xi32>)>, Function>, i32
%3 = spv.AccessChain %1[%c1] : !spv.ptr<!spv.struct<(!spv.array<4x!spv.array<4xf32>>, !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<i64, Uniform>) -> 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-DAG: spv.Constant 6 : i32
// CHECK-DAG: spv.Constant -33 : i32
// CHECK-DAG: spv.Constant 42 : 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-DAG: spv.Constant -5 : i32
// CHECK-DAG: spv.Constant 4 : 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<vector<3xi32>, 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-DAG: spv.Constant -3
// CHECK-DAG: spv.Constant -16
// CHECK-DAG: spv.Constant 10
%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
// 0x8000 0000 + 0xffff fffe = 0x1 7fff fffe -> 0x7fff fffe
// CHECK-DAG: spv.Constant 2147483646
// 0x8000 0000 + 0xffff ffff = 0x1 7fff ffff -> 0x7fff ffff
// CHECK-DAG: spv.Constant 2147483647
// 0x0000 0002 + 0xffff ffff = 0x1 0000 0001 -> 0x0000 0001
// CHECK-DAG: spv.Constant 1
// 0x0000 0001 + 0xffff ffff = 0x1 0000 0000 -> 0x0000 0000
// CHECK-DAG: spv.Constant 0
%0 = spv.IAdd %c1, %c3 : i32
%1 = spv.IAdd %c2, %c3 : i32
%2 = spv.IAdd %c4, %c5 : i32
%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-DAG: spv.Constant -56
// CHECK-DAG: spv.Constant -40
// CHECK-DAG: spv.Constant 35
%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
// (0x7fff ffff << 2) = 0x1 ffff fffc -> 0xffff fffc
// CHECK-DAG: %[[CST4:.*]] = spv.Constant -4
// (0xffff ffff << 1) = 0x1 ffff fffe -> 0xffff fffe
// CHECK-DAG: %[[CST2:.*]] = spv.Constant -2
%0 = spv.IMul %c1, %c3 : i32
// (0x7fff ffff << 1) = 0x0 ffff fffe -> 0xffff fffe
%1 = spv.IMul %c1, %c4 : i32
%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-DAG: spv.Constant -15
// CHECK-DAG: spv.Constant 13
// CHECK-DAG: spv.Constant 2
%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
// 0xffff ffff - 0x7fff ffff -> 0xffff ffff + 0x8000 0001 = 0x1 8000 0000
// CHECK-DAG: spv.Constant -2147483648
// 0x0000 0001 - 0xffff ffff -> 0x0000 0001 + 0x0000 0001 = 0x0000 0002
// CHECK-DAG: spv.Constant 2 :
// 0x0000 0000 - 0xffff ffff -> 0x0000 0000 + 0x0000 0001 = 0x0000 0001
// CHECK-DAG: spv.Constant 1 :
// 0xffff fffe - 0x7fff ffff -> 0xffff fffe + 0x8000 0001 = 0x1 7fff ffff
// CHECK-DAG: spv.Constant 2147483647
%0 = spv.ISub %c1, %c3 : i32
%1 = spv.ISub %c2, %c3 : i32
%2 = spv.ISub %c5, %c4 : i32
%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<true> : vector<3xi1>
// CHECK: %[[FALSE:.+]] = spv.Constant dense<false>
%false = spv.Constant dense<false> : 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<vector<3xi1>, 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>
%true = spv.Constant dense<true> : vector<3xi1>
%false = spv.Constant dense<false> : 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.mlir.selection
//===----------------------------------------------------------------------===//
func @canonicalize_selection_op_scalar_type(%cond: i1) -> () {
%0 = spv.Constant 0: i32
// CHECK-DAG: %[[TRUE_VALUE:.*]] = spv.Constant 1 : i32
%1 = spv.Constant 1: i32
// CHECK-DAG: %[[FALSE_VALUE:.*]] = spv.Constant 2 : i32
%2 = spv.Constant 2: i32
// CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<i32, Function>
%3 = spv.Variable init(%0) : !spv.ptr<i32, Function>
// 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.mlir.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-DAG: %[[TRUE_VALUE:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[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<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, 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.mlir.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
}
// -----
// CHECK-LABEL: cannot_canonicalize_selection_op_0
// Store to a different variables.
func @cannot_canonicalize_selection_op_0(%cond: i1) -> () {
%0 = spv.Constant dense<[0, 1, 2]> : vector<3xi32>
// CHECK-DAG: %[[SRC_VALUE_1:.*]] = spv.Constant dense<[2, 3, 4]> : vector<3xi32>
// CHECK-DAG: %[[SRC_VALUE_0:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%2 = spv.Constant dense<[2, 3, 4]> : vector<3xi32>
// CHECK: %[[DST_VAR_0:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
%4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: spv.mlir.selection {
spv.mlir.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<vector<3xi32>, 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
}
// -----
// CHECK-LABEL: cannot_canonicalize_selection_op_1
// 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-DAG: %[[SRC_VALUE_0:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[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<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
%4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: spv.mlir.selection {
spv.mlir.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
}
// -----
// CHECK-LABEL: cannot_canonicalize_selection_op_2
// 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-DAG: %[[SRC_VALUE_0:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[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<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: spv.mlir.selection {
spv.mlir.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
}
// -----
// CHECK-LABEL: cannot_canonicalize_selection_op_3
// `spv.Return` as a block terminator.
func @cannot_canonicalize_selection_op_3(%cond: i1) -> () {
%0 = spv.Constant dense<[0, 1, 2]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[SRC_VALUE_0:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[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<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: spv.mlir.selection {
spv.mlir.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
}
// -----
// CHECK-LABEL: cannot_canonicalize_selection_op_4
// Different memory access attributes.
func @cannot_canonicalize_selection_op_4(%cond: i1) -> () {
%0 = spv.Constant dense<[0, 1, 2]> : vector<3xi32>
// CHECK-DAG: %[[SRC_VALUE_0:.*]] = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
%1 = spv.Constant dense<[1, 2, 3]> : vector<3xi32>
// CHECK-DAG: %[[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<vector<3xi32>, Function>
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
// CHECK: spv.mlir.selection {
spv.mlir.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
}