Files
clang-p2996/mlir/test/Conversion/ArithmeticToSPIRV/arithmetic-to-spirv.mlir
River Riddle 3ba66435d9 [mlir][SPIRV] Split up StandardToSPIRV now that the Standard dialect is gone
StandardToSPIRV currently contains an assortment of patterns converting from
different dialects to SPIRV. This commit splits up StandardToSPIRV into separate
conversions for each of the dialects involved (some of which already exist).

Differential Revision: https://reviews.llvm.org/D120767
2022-03-02 13:14:36 -08:00

1757 lines
54 KiB
MLIR

// RUN: mlir-opt -split-input-file -convert-arith-to-spirv -verify-diagnostics %s | FileCheck %s
//===----------------------------------------------------------------------===//
// arithmetic ops
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64, Shader], []>, {}>
} {
// Check integer operation conversions.
// CHECK-LABEL: @int32_scalar
func @int32_scalar(%lhs: i32, %rhs: i32) {
// CHECK: spv.IAdd %{{.*}}, %{{.*}}: i32
%0 = arith.addi %lhs, %rhs: i32
// CHECK: spv.ISub %{{.*}}, %{{.*}}: i32
%1 = arith.subi %lhs, %rhs: i32
// CHECK: spv.IMul %{{.*}}, %{{.*}}: i32
%2 = arith.muli %lhs, %rhs: i32
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: i32
%3 = arith.divsi %lhs, %rhs: i32
// CHECK: spv.UDiv %{{.*}}, %{{.*}}: i32
%4 = arith.divui %lhs, %rhs: i32
// CHECK: spv.UMod %{{.*}}, %{{.*}}: i32
%5 = arith.remui %lhs, %rhs: i32
return
}
// CHECK-LABEL: @scalar_srem
// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
func @scalar_srem(%lhs: i32, %rhs: i32) {
// CHECK: %[[LABS:.+]] = spv.GLSL.SAbs %[[LHS]] : i32
// CHECK: %[[RABS:.+]] = spv.GLSL.SAbs %[[RHS]] : i32
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : i32
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : i32
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : i32
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
%0 = arith.remsi %lhs, %rhs: i32
return
}
// Check float unary operation conversions.
// CHECK-LABEL: @float32_unary_scalar
func @float32_unary_scalar(%arg0: f32) {
// CHECK: spv.FNegate %{{.*}}: f32
%0 = arith.negf %arg0 : f32
return
}
// Check float binary operation conversions.
// CHECK-LABEL: @float32_binary_scalar
func @float32_binary_scalar(%lhs: f32, %rhs: f32) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: f32
%0 = arith.addf %lhs, %rhs: f32
// CHECK: spv.FSub %{{.*}}, %{{.*}}: f32
%1 = arith.subf %lhs, %rhs: f32
// CHECK: spv.FMul %{{.*}}, %{{.*}}: f32
%2 = arith.mulf %lhs, %rhs: f32
// CHECK: spv.FDiv %{{.*}}, %{{.*}}: f32
%3 = arith.divf %lhs, %rhs: f32
// CHECK: spv.FRem %{{.*}}, %{{.*}}: f32
%4 = arith.remf %lhs, %rhs: f32
return
}
// Check int vector types.
// CHECK-LABEL: @int_vector234
func @int_vector234(%arg0: vector<2xi8>, %arg1: vector<4xi64>) {
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<2xi8>
%0 = arith.divsi %arg0, %arg0: vector<2xi8>
// CHECK: spv.UDiv %{{.*}}, %{{.*}}: vector<4xi64>
%1 = arith.divui %arg1, %arg1: vector<4xi64>
return
}
// CHECK-LABEL: @vector_srem
// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
// CHECK: %[[LABS:.+]] = spv.GLSL.SAbs %[[LHS]] : vector<3xi16>
// CHECK: %[[RABS:.+]] = spv.GLSL.SAbs %[[RHS]] : vector<3xi16>
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : vector<3xi16>
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
%0 = arith.remsi %arg0, %arg1: vector<3xi16>
return
}
// Check float vector types.
// CHECK-LABEL: @float_vector234
func @float_vector234(%arg0: vector<2xf16>, %arg1: vector<3xf64>) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: vector<2xf16>
%0 = arith.addf %arg0, %arg0: vector<2xf16>
// CHECK: spv.FMul %{{.*}}, %{{.*}}: vector<3xf64>
%1 = arith.mulf %arg1, %arg1: vector<3xf64>
return
}
// CHECK-LABEL: @one_elem_vector
func @one_elem_vector(%arg0: vector<1xi32>) {
// CHECK: spv.IAdd %{{.+}}, %{{.+}}: i32
%0 = arith.addi %arg0, %arg0: vector<1xi32>
return
}
// CHECK-LABEL: @unsupported_5elem_vector
func @unsupported_5elem_vector(%arg0: vector<5xi32>) {
// CHECK: arith.subi
%1 = arith.subi %arg0, %arg0: vector<5xi32>
return
}
// CHECK-LABEL: @unsupported_2x2elem_vector
func @unsupported_2x2elem_vector(%arg0: vector<2x2xi32>) {
// CHECK: arith.muli
%2 = arith.muli %arg0, %arg0: vector<2x2xi32>
return
}
} // end module
// -----
// Check that types are converted to 32-bit when no special capabilities.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @int_vector23
func @int_vector23(%arg0: vector<2xi8>, %arg1: vector<3xi16>) {
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<2xi32>
%0 = arith.divsi %arg0, %arg0: vector<2xi8>
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<3xi32>
%1 = arith.divsi %arg1, %arg1: vector<3xi16>
return
}
// CHECK-LABEL: @float_scalar
func @float_scalar(%arg0: f16, %arg1: f64) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: f32
%0 = arith.addf %arg0, %arg0: f16
// CHECK: spv.FMul %{{.*}}, %{{.*}}: f32
%1 = arith.mulf %arg1, %arg1: f64
return
}
} // end module
// -----
// Check that types are converted to 32-bit when no special capabilities that
// are not supported.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// expected-error @+1 {{failed to materialize conversion for block argument #0 that remained live after conversion, type was 'vector<4xi64>', with target type 'vector<4xi32>'}}
func @int_vector4_invalid(%arg0: vector<4xi64>) {
// expected-error @+2 {{bitwidth emulation is not implemented yet on unsigned op}}
// expected-note @+1 {{see existing live user here}}
%0 = arith.divui %arg0, %arg0: vector<4xi64>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// std bit ops
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @bitwise_scalar
func @bitwise_scalar(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.BitwiseAnd
%0 = arith.andi %arg0, %arg1 : i32
// CHECK: spv.BitwiseOr
%1 = arith.ori %arg0, %arg1 : i32
// CHECK: spv.BitwiseXor
%2 = arith.xori %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @bitwise_vector
func @bitwise_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
// CHECK: spv.BitwiseAnd
%0 = arith.andi %arg0, %arg1 : vector<4xi32>
// CHECK: spv.BitwiseOr
%1 = arith.ori %arg0, %arg1 : vector<4xi32>
// CHECK: spv.BitwiseXor
%2 = arith.xori %arg0, %arg1 : vector<4xi32>
return
}
// CHECK-LABEL: @logical_scalar
func @logical_scalar(%arg0 : i1, %arg1 : i1) {
// CHECK: spv.LogicalAnd
%0 = arith.andi %arg0, %arg1 : i1
// CHECK: spv.LogicalOr
%1 = arith.ori %arg0, %arg1 : i1
// CHECK: spv.LogicalNotEqual
%2 = arith.xori %arg0, %arg1 : i1
return
}
// CHECK-LABEL: @logical_vector
func @logical_vector(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
// CHECK: spv.LogicalAnd
%0 = arith.andi %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalOr
%1 = arith.ori %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalNotEqual
%2 = arith.xori %arg0, %arg1 : vector<4xi1>
return
}
// CHECK-LABEL: @shift_scalar
func @shift_scalar(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.ShiftLeftLogical
%0 = arith.shli %arg0, %arg1 : i32
// CHECK: spv.ShiftRightArithmetic
%1 = arith.shrsi %arg0, %arg1 : i32
// CHECK: spv.ShiftRightLogical
%2 = arith.shrui %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @shift_vector
func @shift_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
// CHECK: spv.ShiftLeftLogical
%0 = arith.shli %arg0, %arg1 : vector<4xi32>
// CHECK: spv.ShiftRightArithmetic
%1 = arith.shrsi %arg0, %arg1 : vector<4xi32>
// CHECK: spv.ShiftRightLogical
%2 = arith.shrui %arg0, %arg1 : vector<4xi32>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.cmpf
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpf
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: spv.FOrdEqual
%1 = arith.cmpf oeq, %arg0, %arg1 : f32
// CHECK: spv.FOrdGreaterThan
%2 = arith.cmpf ogt, %arg0, %arg1 : f32
// CHECK: spv.FOrdGreaterThanEqual
%3 = arith.cmpf oge, %arg0, %arg1 : f32
// CHECK: spv.FOrdLessThan
%4 = arith.cmpf olt, %arg0, %arg1 : f32
// CHECK: spv.FOrdLessThanEqual
%5 = arith.cmpf ole, %arg0, %arg1 : f32
// CHECK: spv.FOrdNotEqual
%6 = arith.cmpf one, %arg0, %arg1 : f32
// CHECK: spv.FUnordEqual
%7 = arith.cmpf ueq, %arg0, %arg1 : f32
// CHECK: spv.FUnordGreaterThan
%8 = arith.cmpf ugt, %arg0, %arg1 : f32
// CHECK: spv.FUnordGreaterThanEqual
%9 = arith.cmpf uge, %arg0, %arg1 : f32
// CHECK: spv.FUnordLessThan
%10 = arith.cmpf ult, %arg0, %arg1 : f32
// CHECK: FUnordLessThanEqual
%11 = arith.cmpf ule, %arg0, %arg1 : f32
// CHECK: spv.FUnordNotEqual
%12 = arith.cmpf une, %arg0, %arg1 : f32
return
}
} // end module
// -----
// With Kernel capability, we can convert NaN check to spv.Ordered/spv.Unordered.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Kernel], []>, {}>
} {
// CHECK-LABEL: @cmpf
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: spv.Ordered
%0 = arith.cmpf ord, %arg0, %arg1 : f32
// CHECK: spv.Unordered
%1 = arith.cmpf uno, %arg0, %arg1 : f32
return
}
} // end module
// -----
// Without Kernel capability, we need to convert NaN check to spv.IsNan.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpf
// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: %[[LHS_NAN:.+]] = spv.IsNan %[[LHS]] : f32
// CHECK-NEXT: %[[RHS_NAN:.+]] = spv.IsNan %[[RHS]] : f32
// CHECK-NEXT: %[[OR:.+]] = spv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
// CHECK-NEXT: %{{.+}} = spv.LogicalNot %[[OR]] : i1
%0 = arith.cmpf ord, %arg0, %arg1 : f32
// CHECK-NEXT: %[[LHS_NAN:.+]] = spv.IsNan %[[LHS]] : f32
// CHECK-NEXT: %[[RHS_NAN:.+]] = spv.IsNan %[[RHS]] : f32
// CHECK-NEXT: %{{.+}} = spv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
%1 = arith.cmpf uno, %arg0, %arg1 : f32
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.cmpi
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpi
func @cmpi(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.IEqual
%0 = arith.cmpi eq, %arg0, %arg1 : i32
// CHECK: spv.INotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : i32
// CHECK: spv.SLessThan
%2 = arith.cmpi slt, %arg0, %arg1 : i32
// CHECK: spv.SLessThanEqual
%3 = arith.cmpi sle, %arg0, %arg1 : i32
// CHECK: spv.SGreaterThan
%4 = arith.cmpi sgt, %arg0, %arg1 : i32
// CHECK: spv.SGreaterThanEqual
%5 = arith.cmpi sge, %arg0, %arg1 : i32
// CHECK: spv.ULessThan
%6 = arith.cmpi ult, %arg0, %arg1 : i32
// CHECK: spv.ULessThanEqual
%7 = arith.cmpi ule, %arg0, %arg1 : i32
// CHECK: spv.UGreaterThan
%8 = arith.cmpi ugt, %arg0, %arg1 : i32
// CHECK: spv.UGreaterThanEqual
%9 = arith.cmpi uge, %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @boolcmpi
func @boolcmpi(%arg0 : i1, %arg1 : i1) {
// CHECK: spv.LogicalEqual
%0 = arith.cmpi eq, %arg0, %arg1 : i1
// CHECK: spv.LogicalNotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : i1
return
}
// CHECK-LABEL: @vecboolcmpi
func @vecboolcmpi(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
// CHECK: spv.LogicalEqual
%0 = arith.cmpi eq, %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalNotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : vector<4xi1>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.constant
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, {}>
} {
// CHECK-LABEL: @constant
func @constant() {
// CHECK: spv.Constant true
%0 = arith.constant true
// CHECK: spv.Constant 42 : i32
%1 = arith.constant 42 : i32
// CHECK: spv.Constant 5.000000e-01 : f32
%2 = arith.constant 0.5 : f32
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%3 = arith.constant dense<[2, 3]> : vector<2xi32>
// CHECK: spv.Constant 1 : i32
%4 = arith.constant 1 : index
// CHECK: spv.Constant dense<1> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%5 = arith.constant dense<1> : tensor<2x3xi32>
// CHECK: spv.Constant dense<1.000000e+00> : tensor<6xf32> : !spv.array<6 x f32, stride=4>
%6 = arith.constant dense<1.0> : tensor<2x3xf32>
// CHECK: spv.Constant dense<{{\[}}1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf32> : !spv.array<6 x f32, stride=4>
%7 = arith.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%8 = arith.constant dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%9 = arith.constant dense<[[1, 2], [3, 4], [5, 6]]> : tensor<3x2xi32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%10 = arith.constant dense<[1, 2, 3, 4, 5, 6]> : tensor<6xi32>
return
}
// CHECK-LABEL: @constant_16bit
func @constant_16bit() {
// CHECK: spv.Constant 4 : i16
%0 = arith.constant 4 : i16
// CHECK: spv.Constant 5.000000e+00 : f16
%1 = arith.constant 5.0 : f16
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi16>
%2 = arith.constant dense<[2, 3]> : vector<2xi16>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf16> : !spv.array<5 x f16, stride=2>
%3 = arith.constant dense<4.0> : tensor<5xf16>
return
}
// CHECK-LABEL: @constant_64bit
func @constant_64bit() {
// CHECK: spv.Constant 4 : i64
%0 = arith.constant 4 : i64
// CHECK: spv.Constant 5.000000e+00 : f64
%1 = arith.constant 5.0 : f64
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi64>
%2 = arith.constant dense<[2, 3]> : vector<2xi64>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf64> : !spv.array<5 x f64, stride=8>
%3 = arith.constant dense<4.0> : tensor<5xf64>
return
}
// CHECK-LABEL: @constant_size1
func @constant_size1() {
// CHECK: spv.Constant true
%0 = arith.constant dense<true> : tensor<1xi1>
// CHECK: spv.Constant 4 : i64
%1 = arith.constant dense<4> : vector<1xi64>
// CHECK: spv.Constant 5.000000e+00 : f64
%2 = arith.constant dense<5.0> : tensor<1xf64>
return
}
} // end module
// -----
// Check that constants are converted to 32-bit when no special capability.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @constant_16bit
func @constant_16bit() {
// CHECK: spv.Constant 4 : i32
%0 = arith.constant 4 : i16
// CHECK: spv.Constant 5.000000e+00 : f32
%1 = arith.constant 5.0 : f16
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%2 = arith.constant dense<[2, 3]> : vector<2xi16>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf32> : !spv.array<5 x f32, stride=4>
%3 = arith.constant dense<4.0> : tensor<5xf16>
// CHECK: spv.Constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32> : !spv.array<4 x f32, stride=4>
%4 = arith.constant dense<[[1.0, 2.0], [3.0, 4.0]]> : tensor<2x2xf16>
return
}
// CHECK-LABEL: @constant_64bit
func @constant_64bit() {
// CHECK: spv.Constant 4 : i32
%0 = arith.constant 4 : i64
// CHECK: spv.Constant 5.000000e+00 : f32
%1 = arith.constant 5.0 : f64
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%2 = arith.constant dense<[2, 3]> : vector<2xi64>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf32> : !spv.array<5 x f32, stride=4>
%3 = arith.constant dense<4.0> : tensor<5xf64>
// CHECK: spv.Constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32> : !spv.array<4 x f32, stride=4>
%4 = arith.constant dense<[[1.0, 2.0], [3.0, 4.0]]> : tensor<2x2xf16>
return
}
// CHECK-LABEL: @constant_size1
func @constant_size1() {
// CHECK: spv.Constant 4 : i32
%0 = arith.constant dense<4> : vector<1xi64>
// CHECK: spv.Constant 5.000000e+00 : f32
%1 = arith.constant dense<5.0> : tensor<1xf64>
return
}
// CHECK-LABEL: @corner_cases
func @corner_cases() {
// CHECK: %{{.*}} = spv.Constant -1 : i32
%0 = arith.constant 4294967295 : i64 // 2^32 - 1
// CHECK: %{{.*}} = spv.Constant 2147483647 : i32
%1 = arith.constant 2147483647 : i64 // 2^31 - 1
// CHECK: %{{.*}} = spv.Constant -2147483648 : i32
%2 = arith.constant 2147483648 : i64 // 2^31
// CHECK: %{{.*}} = spv.Constant -2147483648 : i32
%3 = arith.constant -2147483648 : i64 // -2^31
// CHECK: %{{.*}} = spv.Constant -1 : i32
%5 = arith.constant -1 : i64
// CHECK: %{{.*}} = spv.Constant -2 : i32
%6 = arith.constant -2 : i64
// CHECK: %{{.*}} = spv.Constant -1 : i32
%7 = arith.constant -1 : index
// CHECK: %{{.*}} = spv.Constant -2 : i32
%8 = arith.constant -2 : index
// CHECK: spv.Constant false
%9 = arith.constant false
// CHECK: spv.Constant true
%10 = arith.constant true
return
}
// CHECK-LABEL: @unsupported_cases
func @unsupported_cases() {
// CHECK: %{{.*}} = arith.constant 4294967296 : i64
%0 = arith.constant 4294967296 : i64 // 2^32
// CHECK: %{{.*}} = arith.constant -2147483649 : i64
%1 = arith.constant -2147483649 : i64 // -2^31 - 1
// CHECK: %{{.*}} = arith.constant 1.0000000000000002 : f64
%2 = arith.constant 0x3FF0000000000001 : f64 // smallest number > 1
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// std cast ops
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, {}>
} {
// CHECK-LABEL: index_cast1
func @index_cast1(%arg0: i16) {
// CHECK: spv.SConvert %{{.+}} : i16 to i32
%0 = arith.index_cast %arg0 : i16 to index
return
}
// CHECK-LABEL: index_cast2
func @index_cast2(%arg0: index) {
// CHECK: spv.SConvert %{{.+}} : i32 to i16
%0 = arith.index_cast %arg0 : index to i16
return
}
// CHECK-LABEL: index_cast3
func @index_cast3(%arg0: i32) {
// CHECK-NOT: spv.SConvert
%0 = arith.index_cast %arg0 : i32 to index
return
}
// CHECK-LABEL: index_cast4
func @index_cast4(%arg0: index) {
// CHECK-NOT: spv.SConvert
%0 = arith.index_cast %arg0 : index to i32
return
}
// CHECK-LABEL: @bit_cast
func @bit_cast(%arg0: vector<2xf32>, %arg1: i64) {
// CHECK: spv.Bitcast %{{.+}} : vector<2xf32> to vector<2xi32>
%0 = arith.bitcast %arg0 : vector<2xf32> to vector<2xi32>
// CHECK: spv.Bitcast %{{.+}} : i64 to f64
%1 = arith.bitcast %arg1 : i64 to f64
return
}
// CHECK-LABEL: @fpext1
func @fpext1(%arg0: f16) -> f64 {
// CHECK: spv.FConvert %{{.*}} : f16 to f64
%0 = arith.extf %arg0 : f16 to f64
return %0 : f64
}
// CHECK-LABEL: @fpext2
func @fpext2(%arg0 : f32) -> f64 {
// CHECK: spv.FConvert %{{.*}} : f32 to f64
%0 = arith.extf %arg0 : f32 to f64
return %0 : f64
}
// CHECK-LABEL: @fptrunc1
func @fptrunc1(%arg0 : f64) -> f16 {
// CHECK: spv.FConvert %{{.*}} : f64 to f16
%0 = arith.truncf %arg0 : f64 to f16
return %0 : f16
}
// CHECK-LABEL: @fptrunc2
func @fptrunc2(%arg0: f32) -> f16 {
// CHECK: spv.FConvert %{{.*}} : f32 to f16
%0 = arith.truncf %arg0 : f32 to f16
return %0 : f16
}
// CHECK-LABEL: @sitofp1
func @sitofp1(%arg0 : i32) -> f32 {
// CHECK: spv.ConvertSToF %{{.*}} : i32 to f32
%0 = arith.sitofp %arg0 : i32 to f32
return %0 : f32
}
// CHECK-LABEL: @sitofp2
func @sitofp2(%arg0 : i64) -> f64 {
// CHECK: spv.ConvertSToF %{{.*}} : i64 to f64
%0 = arith.sitofp %arg0 : i64 to f64
return %0 : f64
}
// CHECK-LABEL: @uitofp_i16_f32
func @uitofp_i16_f32(%arg0: i16) -> f32 {
// CHECK: spv.ConvertUToF %{{.*}} : i16 to f32
%0 = arith.uitofp %arg0 : i16 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i32_f32
func @uitofp_i32_f32(%arg0 : i32) -> f32 {
// CHECK: spv.ConvertUToF %{{.*}} : i32 to f32
%0 = arith.uitofp %arg0 : i32 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i1_f32
func @uitofp_i1_f32(%arg0 : i1) -> f32 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0.000000e+00 : f32
// CHECK: %[[ONE:.+]] = spv.Constant 1.000000e+00 : f32
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f32
%0 = arith.uitofp %arg0 : i1 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i1_f64
func @uitofp_i1_f64(%arg0 : i1) -> f64 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0.000000e+00 : f64
// CHECK: %[[ONE:.+]] = spv.Constant 1.000000e+00 : f64
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f64
%0 = arith.uitofp %arg0 : i1 to f64
return %0 : f64
}
// CHECK-LABEL: @uitofp_vec_i1_f32
func @uitofp_vec_i1_f32(%arg0 : vector<4xi1>) -> vector<4xf32> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0.000000e+00> : vector<4xf32>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1.000000e+00> : vector<4xf32>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf32>
%0 = arith.uitofp %arg0 : vector<4xi1> to vector<4xf32>
return %0 : vector<4xf32>
}
// CHECK-LABEL: @uitofp_vec_i1_f64
spv.func @uitofp_vec_i1_f64(%arg0: vector<4xi1>) -> vector<4xf64> "None" {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0.000000e+00> : vector<4xf64>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1.000000e+00> : vector<4xf64>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf64>
%0 = spv.Constant dense<0.000000e+00> : vector<4xf64>
%1 = spv.Constant dense<1.000000e+00> : vector<4xf64>
%2 = spv.Select %arg0, %1, %0 : vector<4xi1>, vector<4xf64>
spv.ReturnValue %2 : vector<4xf64>
}
// CHECK-LABEL: @sexti1
func @sexti1(%arg0: i16) -> i64 {
// CHECK: spv.SConvert %{{.*}} : i16 to i64
%0 = arith.extsi %arg0 : i16 to i64
return %0 : i64
}
// CHECK-LABEL: @sexti2
func @sexti2(%arg0 : i32) -> i64 {
// CHECK: spv.SConvert %{{.*}} : i32 to i64
%0 = arith.extsi %arg0 : i32 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti1
func @zexti1(%arg0: i16) -> i64 {
// CHECK: spv.UConvert %{{.*}} : i16 to i64
%0 = arith.extui %arg0 : i16 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti2
func @zexti2(%arg0 : i32) -> i64 {
// CHECK: spv.UConvert %{{.*}} : i32 to i64
%0 = arith.extui %arg0 : i32 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti3
func @zexti3(%arg0 : i1) -> i32 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0 : i32
// CHECK: %[[ONE:.+]] = spv.Constant 1 : i32
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, i32
%0 = arith.extui %arg0 : i1 to i32
return %0 : i32
}
// CHECK-LABEL: @zexti4
func @zexti4(%arg0 : vector<4xi1>) -> vector<4xi32> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0> : vector<4xi32>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1> : vector<4xi32>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi32>
%0 = arith.extui %arg0 : vector<4xi1> to vector<4xi32>
return %0 : vector<4xi32>
}
// CHECK-LABEL: @zexti5
func @zexti5(%arg0 : vector<4xi1>) -> vector<4xi64> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0> : vector<4xi64>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1> : vector<4xi64>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi64>
%0 = arith.extui %arg0 : vector<4xi1> to vector<4xi64>
return %0 : vector<4xi64>
}
// CHECK-LABEL: @trunci1
func @trunci1(%arg0 : i64) -> i16 {
// CHECK: spv.SConvert %{{.*}} : i64 to i16
%0 = arith.trunci %arg0 : i64 to i16
return %0 : i16
}
// CHECK-LABEL: @trunci2
func @trunci2(%arg0: i32) -> i16 {
// CHECK: spv.SConvert %{{.*}} : i32 to i16
%0 = arith.trunci %arg0 : i32 to i16
return %0 : i16
}
// CHECK-LABEL: @trunc_to_i1
func @trunc_to_i1(%arg0: i32) -> i1 {
// CHECK: %[[MASK:.*]] = spv.Constant 1 : i32
// CHECK: %[[MASKED_SRC:.*]] = spv.BitwiseAnd %{{.*}}, %[[MASK]] : i32
// CHECK: %[[IS_ONE:.*]] = spv.IEqual %[[MASKED_SRC]], %[[MASK]] : i32
// CHECK-DAG: %[[TRUE:.*]] = spv.Constant true
// CHECK-DAG: %[[FALSE:.*]] = spv.Constant false
// CHECK: spv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : i1, i1
%0 = arith.trunci %arg0 : i32 to i1
return %0 : i1
}
// CHECK-LABEL: @trunc_to_veci1
func @trunc_to_veci1(%arg0: vector<4xi32>) -> vector<4xi1> {
// CHECK: %[[MASK:.*]] = spv.Constant dense<1> : vector<4xi32>
// CHECK: %[[MASKED_SRC:.*]] = spv.BitwiseAnd %{{.*}}, %[[MASK]] : vector<4xi32>
// CHECK: %[[IS_ONE:.*]] = spv.IEqual %[[MASKED_SRC]], %[[MASK]] : vector<4xi32>
// CHECK-DAG: %[[TRUE:.*]] = spv.Constant dense<true> : vector<4xi1>
// CHECK-DAG: %[[FALSE:.*]] = spv.Constant dense<false> : vector<4xi1>
// CHECK: spv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : vector<4xi1>, vector<4xi1>
%0 = arith.trunci %arg0 : vector<4xi32> to vector<4xi1>
return %0 : vector<4xi1>
}
// CHECK-LABEL: @fptosi1
func @fptosi1(%arg0 : f32) -> i32 {
// CHECK: spv.ConvertFToS %{{.*}} : f32 to i32
%0 = arith.fptosi %arg0 : f32 to i32
return %0 : i32
}
// CHECK-LABEL: @fptosi2
func @fptosi2(%arg0 : f16) -> i16 {
// CHECK: spv.ConvertFToS %{{.*}} : f16 to i16
%0 = arith.fptosi %arg0 : f16 to i16
return %0 : i16
}
} // end module
// -----
// Checks that cast types will be adjusted when missing special capabilities for
// certain non-32-bit scalar types.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Float64], []>, {}>
} {
// CHECK-LABEL: @fpext1
// CHECK-SAME: %[[ARG:.*]]: f32
func @fpext1(%arg0: f16) -> f64 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f64
%0 = arith.extf %arg0 : f16 to f64
return %0: f64
}
// CHECK-LABEL: @fpext2
// CHECK-SAME: %[[ARG:.*]]: f32
func @fpext2(%arg0 : f32) -> f64 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f64
%0 = arith.extf %arg0 : f32 to f64
return %0: f64
}
} // end module
// -----
// Checks that cast types will be adjusted when missing special capabilities for
// certain non-32-bit scalar types.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Float16], []>, {}>
} {
// CHECK-LABEL: @fptrunc1
// CHECK-SAME: %[[ARG:.*]]: f32
func @fptrunc1(%arg0 : f64) -> f16 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f16
%0 = arith.truncf %arg0 : f64 to f16
return %0: f16
}
// CHECK-LABEL: @fptrunc2
// CHECK-SAME: %[[ARG:.*]]: f32
func @fptrunc2(%arg0: f32) -> f16 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f16
%0 = arith.truncf %arg0 : f32 to f16
return %0: f16
}
// CHECK-LABEL: @sitofp
func @sitofp(%arg0 : i64) -> f64 {
// CHECK: spv.ConvertSToF %{{.*}} : i32 to f32
%0 = arith.sitofp %arg0 : i64 to f64
return %0: f64
}
} // end module
// -----
// Check OpenCL lowering of arith.remsi
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int16, Kernel], []>, {}>
} {
// CHECK-LABEL: @scalar_srem
// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
func @scalar_srem(%lhs: i32, %rhs: i32) {
// CHECK: %[[LABS:.+]] = spv.OCL.s_abs %[[LHS]] : i32
// CHECK: %[[RABS:.+]] = spv.OCL.s_abs %[[RHS]] : i32
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : i32
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : i32
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : i32
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
%0 = arith.remsi %lhs, %rhs: i32
return
}
// CHECK-LABEL: @vector_srem
// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
// CHECK: %[[LABS:.+]] = spv.OCL.s_abs %[[LHS]] : vector<3xi16>
// CHECK: %[[RABS:.+]] = spv.OCL.s_abs %[[RHS]] : vector<3xi16>
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : vector<3xi16>
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
%0 = arith.remsi %arg0, %arg1: vector<3xi16>
return
}
} // end module
// -----
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Shader, Int8, Int16, Int64, Float16, Float64],
[SPV_KHR_storage_buffer_storage_class]>, {}>
} {
// CHECK-LABEL: @select
func @select(%arg0 : i32, %arg1 : i32) {
%0 = arith.cmpi sle, %arg0, %arg1 : i32
// CHECK: spv.Select
%1 = arith.select %0, %arg0, %arg1 : i32
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.select
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64, Shader], []>, {}>
} {
// Check integer operation conversions.
// CHECK-LABEL: @int32_scalar
func @int32_scalar(%lhs: i32, %rhs: i32) {
// CHECK: spv.IAdd %{{.*}}, %{{.*}}: i32
%0 = arith.addi %lhs, %rhs: i32
// CHECK: spv.ISub %{{.*}}, %{{.*}}: i32
%1 = arith.subi %lhs, %rhs: i32
// CHECK: spv.IMul %{{.*}}, %{{.*}}: i32
%2 = arith.muli %lhs, %rhs: i32
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: i32
%3 = arith.divsi %lhs, %rhs: i32
// CHECK: spv.UDiv %{{.*}}, %{{.*}}: i32
%4 = arith.divui %lhs, %rhs: i32
// CHECK: spv.UMod %{{.*}}, %{{.*}}: i32
%5 = arith.remui %lhs, %rhs: i32
// CHECK: spv.GLSL.SMax %{{.*}}, %{{.*}}: i32
%6 = arith.maxsi %lhs, %rhs : i32
// CHECK: spv.GLSL.UMax %{{.*}}, %{{.*}}: i32
%7 = arith.maxui %lhs, %rhs : i32
// CHECK: spv.GLSL.SMin %{{.*}}, %{{.*}}: i32
%8 = arith.minsi %lhs, %rhs : i32
// CHECK: spv.GLSL.UMin %{{.*}}, %{{.*}}: i32
%9 = arith.minui %lhs, %rhs : i32
return
}
// CHECK-LABEL: @scalar_srem
// CHECK-SAME: (%[[LHS:.+]]: i32, %[[RHS:.+]]: i32)
func @scalar_srem(%lhs: i32, %rhs: i32) {
// CHECK: %[[LABS:.+]] = spv.GLSL.SAbs %[[LHS]] : i32
// CHECK: %[[RABS:.+]] = spv.GLSL.SAbs %[[RHS]] : i32
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : i32
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : i32
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : i32
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : i1, i32
%0 = arith.remsi %lhs, %rhs: i32
return
}
// Check float unary operation conversions.
// CHECK-LABEL: @float32_unary_scalar
func @float32_unary_scalar(%arg0: f32) {
// CHECK: spv.FNegate %{{.*}}: f32
%5 = arith.negf %arg0 : f32
return
}
// Check float binary operation conversions.
// CHECK-LABEL: @float32_binary_scalar
func @float32_binary_scalar(%lhs: f32, %rhs: f32) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: f32
%0 = arith.addf %lhs, %rhs: f32
// CHECK: spv.FSub %{{.*}}, %{{.*}}: f32
%1 = arith.subf %lhs, %rhs: f32
// CHECK: spv.FMul %{{.*}}, %{{.*}}: f32
%2 = arith.mulf %lhs, %rhs: f32
// CHECK: spv.FDiv %{{.*}}, %{{.*}}: f32
%3 = arith.divf %lhs, %rhs: f32
// CHECK: spv.FRem %{{.*}}, %{{.*}}: f32
%4 = arith.remf %lhs, %rhs: f32
// CHECK: spv.GLSL.FMax %{{.*}}, %{{.*}}: f32
%5 = arith.maxf %lhs, %rhs: f32
// CHECK: spv.GLSL.FMin %{{.*}}, %{{.*}}: f32
%6 = arith.minf %lhs, %rhs: f32
return
}
// Check int vector types.
// CHECK-LABEL: @int_vector234
func @int_vector234(%arg0: vector<2xi8>, %arg1: vector<4xi64>) {
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<2xi8>
%0 = arith.divsi %arg0, %arg0: vector<2xi8>
// CHECK: spv.UDiv %{{.*}}, %{{.*}}: vector<4xi64>
%1 = arith.divui %arg1, %arg1: vector<4xi64>
return
}
// CHECK-LABEL: @vector_srem
// CHECK-SAME: (%[[LHS:.+]]: vector<3xi16>, %[[RHS:.+]]: vector<3xi16>)
func @vector_srem(%arg0: vector<3xi16>, %arg1: vector<3xi16>) {
// CHECK: %[[LABS:.+]] = spv.GLSL.SAbs %[[LHS]] : vector<3xi16>
// CHECK: %[[RABS:.+]] = spv.GLSL.SAbs %[[RHS]] : vector<3xi16>
// CHECK: %[[ABS:.+]] = spv.UMod %[[LABS]], %[[RABS]] : vector<3xi16>
// CHECK: %[[POS:.+]] = spv.IEqual %[[LHS]], %[[LABS]] : vector<3xi16>
// CHECK: %[[NEG:.+]] = spv.SNegate %[[ABS]] : vector<3xi16>
// CHECK: %{{.+}} = spv.Select %[[POS]], %[[ABS]], %[[NEG]] : vector<3xi1>, vector<3xi16>
%0 = arith.remsi %arg0, %arg1: vector<3xi16>
return
}
// Check float vector types.
// CHECK-LABEL: @float_vector234
func @float_vector234(%arg0: vector<2xf16>, %arg1: vector<3xf64>) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: vector<2xf16>
%0 = arith.addf %arg0, %arg0: vector<2xf16>
// CHECK: spv.FMul %{{.*}}, %{{.*}}: vector<3xf64>
%1 = arith.mulf %arg1, %arg1: vector<3xf64>
return
}
// CHECK-LABEL: @one_elem_vector
func @one_elem_vector(%arg0: vector<1xi32>) {
// CHECK: spv.IAdd %{{.+}}, %{{.+}}: i32
%0 = arith.addi %arg0, %arg0: vector<1xi32>
return
}
// CHECK-LABEL: @unsupported_5elem_vector
func @unsupported_5elem_vector(%arg0: vector<5xi32>) {
// CHECK: subi
%1 = arith.subi %arg0, %arg0: vector<5xi32>
return
}
// CHECK-LABEL: @unsupported_2x2elem_vector
func @unsupported_2x2elem_vector(%arg0: vector<2x2xi32>) {
// CHECK: muli
%2 = arith.muli %arg0, %arg0: vector<2x2xi32>
return
}
} // end module
// -----
// Check that types are converted to 32-bit when no special capabilities.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @int_vector23
func @int_vector23(%arg0: vector<2xi8>, %arg1: vector<3xi16>) {
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<2xi32>
%0 = arith.divsi %arg0, %arg0: vector<2xi8>
// CHECK: spv.SDiv %{{.*}}, %{{.*}}: vector<3xi32>
%1 = arith.divsi %arg1, %arg1: vector<3xi16>
return
}
// CHECK-LABEL: @float_scalar
func @float_scalar(%arg0: f16, %arg1: f64) {
// CHECK: spv.FAdd %{{.*}}, %{{.*}}: f32
%0 = arith.addf %arg0, %arg0: f16
// CHECK: spv.FMul %{{.*}}, %{{.*}}: f32
%1 = arith.mulf %arg1, %arg1: f64
return
}
} // end module
// -----
// Check that types are converted to 32-bit when no special capabilities that
// are not supported.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// expected-error@below {{failed to materialize conversion for block argument #0 that remained live after conversion}}
func @int_vector4_invalid(%arg0: vector<4xi64>) {
// expected-error@below {{bitwidth emulation is not implemented yet on unsigned op}}
// expected-note@below {{see existing live user here}}
%0 = arith.divui %arg0, %arg0: vector<4xi64>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// std bit ops
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @bitwise_scalar
func @bitwise_scalar(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.BitwiseAnd
%0 = arith.andi %arg0, %arg1 : i32
// CHECK: spv.BitwiseOr
%1 = arith.ori %arg0, %arg1 : i32
// CHECK: spv.BitwiseXor
%2 = arith.xori %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @bitwise_vector
func @bitwise_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
// CHECK: spv.BitwiseAnd
%0 = arith.andi %arg0, %arg1 : vector<4xi32>
// CHECK: spv.BitwiseOr
%1 = arith.ori %arg0, %arg1 : vector<4xi32>
// CHECK: spv.BitwiseXor
%2 = arith.xori %arg0, %arg1 : vector<4xi32>
return
}
// CHECK-LABEL: @logical_scalar
func @logical_scalar(%arg0 : i1, %arg1 : i1) {
// CHECK: spv.LogicalAnd
%0 = arith.andi %arg0, %arg1 : i1
// CHECK: spv.LogicalOr
%1 = arith.ori %arg0, %arg1 : i1
// CHECK: spv.LogicalNotEqual
%2 = arith.xori %arg0, %arg1 : i1
return
}
// CHECK-LABEL: @logical_vector
func @logical_vector(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
// CHECK: spv.LogicalAnd
%0 = arith.andi %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalOr
%1 = arith.ori %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalNotEqual
%2 = arith.xori %arg0, %arg1 : vector<4xi1>
return
}
// CHECK-LABEL: @shift_scalar
func @shift_scalar(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.ShiftLeftLogical
%0 = arith.shli %arg0, %arg1 : i32
// CHECK: spv.ShiftRightArithmetic
%1 = arith.shrsi %arg0, %arg1 : i32
// CHECK: spv.ShiftRightLogical
%2 = arith.shrui %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @shift_vector
func @shift_vector(%arg0 : vector<4xi32>, %arg1 : vector<4xi32>) {
// CHECK: spv.ShiftLeftLogical
%0 = arith.shli %arg0, %arg1 : vector<4xi32>
// CHECK: spv.ShiftRightArithmetic
%1 = arith.shrsi %arg0, %arg1 : vector<4xi32>
// CHECK: spv.ShiftRightLogical
%2 = arith.shrui %arg0, %arg1 : vector<4xi32>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.cmpf
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpf
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: spv.FOrdEqual
%1 = arith.cmpf oeq, %arg0, %arg1 : f32
// CHECK: spv.FOrdGreaterThan
%2 = arith.cmpf ogt, %arg0, %arg1 : f32
// CHECK: spv.FOrdGreaterThanEqual
%3 = arith.cmpf oge, %arg0, %arg1 : f32
// CHECK: spv.FOrdLessThan
%4 = arith.cmpf olt, %arg0, %arg1 : f32
// CHECK: spv.FOrdLessThanEqual
%5 = arith.cmpf ole, %arg0, %arg1 : f32
// CHECK: spv.FOrdNotEqual
%6 = arith.cmpf one, %arg0, %arg1 : f32
// CHECK: spv.FUnordEqual
%7 = arith.cmpf ueq, %arg0, %arg1 : f32
// CHECK: spv.FUnordGreaterThan
%8 = arith.cmpf ugt, %arg0, %arg1 : f32
// CHECK: spv.FUnordGreaterThanEqual
%9 = arith.cmpf uge, %arg0, %arg1 : f32
// CHECK: spv.FUnordLessThan
%10 = arith.cmpf ult, %arg0, %arg1 : f32
// CHECK: FUnordLessThanEqual
%11 = arith.cmpf ule, %arg0, %arg1 : f32
// CHECK: spv.FUnordNotEqual
%12 = arith.cmpf une, %arg0, %arg1 : f32
return
}
} // end module
// -----
// With Kernel capability, we can convert NaN check to spv.Ordered/spv.Unordered.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Kernel], []>, {}>
} {
// CHECK-LABEL: @cmpf
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: spv.Ordered
%0 = arith.cmpf ord, %arg0, %arg1 : f32
// CHECK: spv.Unordered
%1 = arith.cmpf uno, %arg0, %arg1 : f32
return
}
} // end module
// -----
// Without Kernel capability, we need to convert NaN check to spv.IsNan.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpf
// CHECK-SAME: %[[LHS:.+]]: f32, %[[RHS:.+]]: f32
func @cmpf(%arg0 : f32, %arg1 : f32) {
// CHECK: %[[LHS_NAN:.+]] = spv.IsNan %[[LHS]] : f32
// CHECK-NEXT: %[[RHS_NAN:.+]] = spv.IsNan %[[RHS]] : f32
// CHECK-NEXT: %[[OR:.+]] = spv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
// CHECK-NEXT: %{{.+}} = spv.LogicalNot %[[OR]] : i1
%0 = arith.cmpf ord, %arg0, %arg1 : f32
// CHECK-NEXT: %[[LHS_NAN:.+]] = spv.IsNan %[[LHS]] : f32
// CHECK-NEXT: %[[RHS_NAN:.+]] = spv.IsNan %[[RHS]] : f32
// CHECK-NEXT: %{{.+}} = spv.LogicalOr %[[LHS_NAN]], %[[RHS_NAN]] : i1
%1 = arith.cmpf uno, %arg0, %arg1 : f32
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.cmpi
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @cmpi
func @cmpi(%arg0 : i32, %arg1 : i32) {
// CHECK: spv.IEqual
%0 = arith.cmpi eq, %arg0, %arg1 : i32
// CHECK: spv.INotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : i32
// CHECK: spv.SLessThan
%2 = arith.cmpi slt, %arg0, %arg1 : i32
// CHECK: spv.SLessThanEqual
%3 = arith.cmpi sle, %arg0, %arg1 : i32
// CHECK: spv.SGreaterThan
%4 = arith.cmpi sgt, %arg0, %arg1 : i32
// CHECK: spv.SGreaterThanEqual
%5 = arith.cmpi sge, %arg0, %arg1 : i32
// CHECK: spv.ULessThan
%6 = arith.cmpi ult, %arg0, %arg1 : i32
// CHECK: spv.ULessThanEqual
%7 = arith.cmpi ule, %arg0, %arg1 : i32
// CHECK: spv.UGreaterThan
%8 = arith.cmpi ugt, %arg0, %arg1 : i32
// CHECK: spv.UGreaterThanEqual
%9 = arith.cmpi uge, %arg0, %arg1 : i32
return
}
// CHECK-LABEL: @boolcmpi
func @boolcmpi(%arg0 : i1, %arg1 : i1) {
// CHECK: spv.LogicalEqual
%0 = arith.cmpi eq, %arg0, %arg1 : i1
// CHECK: spv.LogicalNotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : i1
return
}
// CHECK-LABEL: @vecboolcmpi
func @vecboolcmpi(%arg0 : vector<4xi1>, %arg1 : vector<4xi1>) {
// CHECK: spv.LogicalEqual
%0 = arith.cmpi eq, %arg0, %arg1 : vector<4xi1>
// CHECK: spv.LogicalNotEqual
%1 = arith.cmpi ne, %arg0, %arg1 : vector<4xi1>
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// arith.constant
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, {}>
} {
// CHECK-LABEL: @constant
func @constant() {
// CHECK: spv.Constant true
%0 = arith.constant true
// CHECK: spv.Constant 42 : i32
%1 = arith.constant 42 : i32
// CHECK: spv.Constant 5.000000e-01 : f32
%2 = arith.constant 0.5 : f32
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%3 = arith.constant dense<[2, 3]> : vector<2xi32>
// CHECK: spv.Constant 1 : i32
%4 = arith.constant 1 : index
// CHECK: spv.Constant dense<1> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%5 = arith.constant dense<1> : tensor<2x3xi32>
// CHECK: spv.Constant dense<1.000000e+00> : tensor<6xf32> : !spv.array<6 x f32, stride=4>
%6 = arith.constant dense<1.0> : tensor<2x3xf32>
// CHECK: spv.Constant dense<{{\[}}1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00]> : tensor<6xf32> : !spv.array<6 x f32, stride=4>
%7 = arith.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]> : tensor<2x3xf32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%8 = arith.constant dense<[[1, 2, 3], [4, 5, 6]]> : tensor<2x3xi32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%9 = arith.constant dense<[[1, 2], [3, 4], [5, 6]]> : tensor<3x2xi32>
// CHECK: spv.Constant dense<{{\[}}1, 2, 3, 4, 5, 6]> : tensor<6xi32> : !spv.array<6 x i32, stride=4>
%10 = arith.constant dense<[1, 2, 3, 4, 5, 6]> : tensor<6xi32>
return
}
// CHECK-LABEL: @constant_16bit
func @constant_16bit() {
// CHECK: spv.Constant 4 : i16
%0 = arith.constant 4 : i16
// CHECK: spv.Constant 5.000000e+00 : f16
%1 = arith.constant 5.0 : f16
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi16>
%2 = arith.constant dense<[2, 3]> : vector<2xi16>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf16> : !spv.array<5 x f16, stride=2>
%3 = arith.constant dense<4.0> : tensor<5xf16>
return
}
// CHECK-LABEL: @constant_64bit
func @constant_64bit() {
// CHECK: spv.Constant 4 : i64
%0 = arith.constant 4 : i64
// CHECK: spv.Constant 5.000000e+00 : f64
%1 = arith.constant 5.0 : f64
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi64>
%2 = arith.constant dense<[2, 3]> : vector<2xi64>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf64> : !spv.array<5 x f64, stride=8>
%3 = arith.constant dense<4.0> : tensor<5xf64>
return
}
} // end module
// -----
// Check that constants are converted to 32-bit when no special capability.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [], []>, {}>
} {
// CHECK-LABEL: @constant_16bit
func @constant_16bit() {
// CHECK: spv.Constant 4 : i32
%0 = arith.constant 4 : i16
// CHECK: spv.Constant 5.000000e+00 : f32
%1 = arith.constant 5.0 : f16
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%2 = arith.constant dense<[2, 3]> : vector<2xi16>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf32> : !spv.array<5 x f32, stride=4>
%3 = arith.constant dense<4.0> : tensor<5xf16>
// CHECK: spv.Constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32> : !spv.array<4 x f32, stride=4>
%4 = arith.constant dense<[[1.0, 2.0], [3.0, 4.0]]> : tensor<2x2xf16>
return
}
// CHECK-LABEL: @constant_64bit
func @constant_64bit() {
// CHECK: spv.Constant 4 : i32
%0 = arith.constant 4 : i64
// CHECK: spv.Constant 5.000000e+00 : f32
%1 = arith.constant 5.0 : f64
// CHECK: spv.Constant dense<[2, 3]> : vector<2xi32>
%2 = arith.constant dense<[2, 3]> : vector<2xi64>
// CHECK: spv.Constant dense<4.000000e+00> : tensor<5xf32> : !spv.array<5 x f32, stride=4>
%3 = arith.constant dense<4.0> : tensor<5xf64>
// CHECK: spv.Constant dense<[1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00]> : tensor<4xf32> : !spv.array<4 x f32, stride=4>
%4 = arith.constant dense<[[1.0, 2.0], [3.0, 4.0]]> : tensor<2x2xf16>
return
}
// CHECK-LABEL: @corner_cases
func @corner_cases() {
// CHECK: %{{.*}} = spv.Constant -1 : i32
%0 = arith.constant 4294967295 : i64 // 2^32 - 1
// CHECK: %{{.*}} = spv.Constant 2147483647 : i32
%1 = arith.constant 2147483647 : i64 // 2^31 - 1
// CHECK: %{{.*}} = spv.Constant -2147483648 : i32
%2 = arith.constant 2147483648 : i64 // 2^31
// CHECK: %{{.*}} = spv.Constant -2147483648 : i32
%3 = arith.constant -2147483648 : i64 // -2^31
// CHECK: %{{.*}} = spv.Constant -1 : i32
%5 = arith.constant -1 : i64
// CHECK: %{{.*}} = spv.Constant -2 : i32
%6 = arith.constant -2 : i64
// CHECK: %{{.*}} = spv.Constant -1 : i32
%7 = arith.constant -1 : index
// CHECK: %{{.*}} = spv.Constant -2 : i32
%8 = arith.constant -2 : index
// CHECK: spv.Constant false
%9 = arith.constant false
// CHECK: spv.Constant true
%10 = arith.constant true
return
}
// CHECK-LABEL: @unsupported_cases
func @unsupported_cases() {
// CHECK: %{{.*}} = arith.constant 4294967296 : i64
%0 = arith.constant 4294967296 : i64 // 2^32
// CHECK: %{{.*}} = arith.constant -2147483649 : i64
%1 = arith.constant -2147483649 : i64 // -2^31 - 1
// CHECK: %{{.*}} = arith.constant 1.0000000000000002 : f64
%2 = arith.constant 0x3FF0000000000001 : f64 // smallest number > 1
return
}
} // end module
// -----
//===----------------------------------------------------------------------===//
// std cast ops
//===----------------------------------------------------------------------===//
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int8, Int16, Int64, Float16, Float64], []>, {}>
} {
// CHECK-LABEL: index_cast1
func @index_cast1(%arg0: i16) {
// CHECK: spv.SConvert %{{.+}} : i16 to i32
%0 = arith.index_cast %arg0 : i16 to index
return
}
// CHECK-LABEL: index_cast2
func @index_cast2(%arg0: index) {
// CHECK: spv.SConvert %{{.+}} : i32 to i16
%0 = arith.index_cast %arg0 : index to i16
return
}
// CHECK-LABEL: index_cast3
func @index_cast3(%arg0: i32) {
// CHECK-NOT: spv.SConvert
%0 = arith.index_cast %arg0 : i32 to index
return
}
// CHECK-LABEL: index_cast4
func @index_cast4(%arg0: index) {
// CHECK-NOT: spv.SConvert
%0 = arith.index_cast %arg0 : index to i32
return
}
// CHECK-LABEL: @fpext1
func @fpext1(%arg0: f16) -> f64 {
// CHECK: spv.FConvert %{{.*}} : f16 to f64
%0 = arith.extf %arg0 : f16 to f64
return %0 : f64
}
// CHECK-LABEL: @fpext2
func @fpext2(%arg0 : f32) -> f64 {
// CHECK: spv.FConvert %{{.*}} : f32 to f64
%0 = arith.extf %arg0 : f32 to f64
return %0 : f64
}
// CHECK-LABEL: @fptrunc1
func @fptrunc1(%arg0 : f64) -> f16 {
// CHECK: spv.FConvert %{{.*}} : f64 to f16
%0 = arith.truncf %arg0 : f64 to f16
return %0 : f16
}
// CHECK-LABEL: @fptrunc2
func @fptrunc2(%arg0: f32) -> f16 {
// CHECK: spv.FConvert %{{.*}} : f32 to f16
%0 = arith.truncf %arg0 : f32 to f16
return %0 : f16
}
// CHECK-LABEL: @sitofp1
func @sitofp1(%arg0 : i32) -> f32 {
// CHECK: spv.ConvertSToF %{{.*}} : i32 to f32
%0 = arith.sitofp %arg0 : i32 to f32
return %0 : f32
}
// CHECK-LABEL: @sitofp2
func @sitofp2(%arg0 : i64) -> f64 {
// CHECK: spv.ConvertSToF %{{.*}} : i64 to f64
%0 = arith.sitofp %arg0 : i64 to f64
return %0 : f64
}
// CHECK-LABEL: @uitofp_i16_f32
func @uitofp_i16_f32(%arg0: i16) -> f32 {
// CHECK: spv.ConvertUToF %{{.*}} : i16 to f32
%0 = arith.uitofp %arg0 : i16 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i32_f32
func @uitofp_i32_f32(%arg0 : i32) -> f32 {
// CHECK: spv.ConvertUToF %{{.*}} : i32 to f32
%0 = arith.uitofp %arg0 : i32 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i1_f32
func @uitofp_i1_f32(%arg0 : i1) -> f32 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0.000000e+00 : f32
// CHECK: %[[ONE:.+]] = spv.Constant 1.000000e+00 : f32
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f32
%0 = arith.uitofp %arg0 : i1 to f32
return %0 : f32
}
// CHECK-LABEL: @uitofp_i1_f64
func @uitofp_i1_f64(%arg0 : i1) -> f64 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0.000000e+00 : f64
// CHECK: %[[ONE:.+]] = spv.Constant 1.000000e+00 : f64
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, f64
%0 = arith.uitofp %arg0 : i1 to f64
return %0 : f64
}
// CHECK-LABEL: @uitofp_vec_i1_f32
func @uitofp_vec_i1_f32(%arg0 : vector<4xi1>) -> vector<4xf32> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0.000000e+00> : vector<4xf32>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1.000000e+00> : vector<4xf32>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf32>
%0 = arith.uitofp %arg0 : vector<4xi1> to vector<4xf32>
return %0 : vector<4xf32>
}
// CHECK-LABEL: @uitofp_vec_i1_f64
spv.func @uitofp_vec_i1_f64(%arg0: vector<4xi1>) -> vector<4xf64> "None" {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0.000000e+00> : vector<4xf64>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1.000000e+00> : vector<4xf64>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xf64>
%0 = spv.Constant dense<0.000000e+00> : vector<4xf64>
%1 = spv.Constant dense<1.000000e+00> : vector<4xf64>
%2 = spv.Select %arg0, %1, %0 : vector<4xi1>, vector<4xf64>
spv.ReturnValue %2 : vector<4xf64>
}
// CHECK-LABEL: @sexti1
func @sexti1(%arg0: i16) -> i64 {
// CHECK: spv.SConvert %{{.*}} : i16 to i64
%0 = arith.extsi %arg0 : i16 to i64
return %0 : i64
}
// CHECK-LABEL: @sexti2
func @sexti2(%arg0 : i32) -> i64 {
// CHECK: spv.SConvert %{{.*}} : i32 to i64
%0 = arith.extsi %arg0 : i32 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti1
func @zexti1(%arg0: i16) -> i64 {
// CHECK: spv.UConvert %{{.*}} : i16 to i64
%0 = arith.extui %arg0 : i16 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti2
func @zexti2(%arg0 : i32) -> i64 {
// CHECK: spv.UConvert %{{.*}} : i32 to i64
%0 = arith.extui %arg0 : i32 to i64
return %0 : i64
}
// CHECK-LABEL: @zexti3
func @zexti3(%arg0 : i1) -> i32 {
// CHECK: %[[ZERO:.+]] = spv.Constant 0 : i32
// CHECK: %[[ONE:.+]] = spv.Constant 1 : i32
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : i1, i32
%0 = arith.extui %arg0 : i1 to i32
return %0 : i32
}
// CHECK-LABEL: @zexti4
func @zexti4(%arg0 : vector<4xi1>) -> vector<4xi32> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0> : vector<4xi32>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1> : vector<4xi32>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi32>
%0 = arith.extui %arg0 : vector<4xi1> to vector<4xi32>
return %0 : vector<4xi32>
}
// CHECK-LABEL: @zexti5
func @zexti5(%arg0 : vector<4xi1>) -> vector<4xi64> {
// CHECK: %[[ZERO:.+]] = spv.Constant dense<0> : vector<4xi64>
// CHECK: %[[ONE:.+]] = spv.Constant dense<1> : vector<4xi64>
// CHECK: spv.Select %{{.*}}, %[[ONE]], %[[ZERO]] : vector<4xi1>, vector<4xi64>
%0 = arith.extui %arg0 : vector<4xi1> to vector<4xi64>
return %0 : vector<4xi64>
}
// CHECK-LABEL: @trunci1
func @trunci1(%arg0 : i64) -> i16 {
// CHECK: spv.SConvert %{{.*}} : i64 to i16
%0 = arith.trunci %arg0 : i64 to i16
return %0 : i16
}
// CHECK-LABEL: @trunci2
func @trunci2(%arg0: i32) -> i16 {
// CHECK: spv.SConvert %{{.*}} : i32 to i16
%0 = arith.trunci %arg0 : i32 to i16
return %0 : i16
}
// CHECK-LABEL: @trunc_to_i1
func @trunc_to_i1(%arg0: i32) -> i1 {
// CHECK: %[[MASK:.*]] = spv.Constant 1 : i32
// CHECK: %[[MASKED_SRC:.*]] = spv.BitwiseAnd %{{.*}}, %[[MASK]] : i32
// CHECK: %[[IS_ONE:.*]] = spv.IEqual %[[MASKED_SRC]], %[[MASK]] : i32
// CHECK-DAG: %[[TRUE:.*]] = spv.Constant true
// CHECK-DAG: %[[FALSE:.*]] = spv.Constant false
// CHECK: spv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : i1, i1
%0 = arith.trunci %arg0 : i32 to i1
return %0 : i1
}
// CHECK-LABEL: @trunc_to_veci1
func @trunc_to_veci1(%arg0: vector<4xi32>) -> vector<4xi1> {
// CHECK: %[[MASK:.*]] = spv.Constant dense<1> : vector<4xi32>
// CHECK: %[[MASKED_SRC:.*]] = spv.BitwiseAnd %{{.*}}, %[[MASK]] : vector<4xi32>
// CHECK: %[[IS_ONE:.*]] = spv.IEqual %[[MASKED_SRC]], %[[MASK]] : vector<4xi32>
// CHECK-DAG: %[[TRUE:.*]] = spv.Constant dense<true> : vector<4xi1>
// CHECK-DAG: %[[FALSE:.*]] = spv.Constant dense<false> : vector<4xi1>
// CHECK: spv.Select %[[IS_ONE]], %[[TRUE]], %[[FALSE]] : vector<4xi1>, vector<4xi1>
%0 = arith.trunci %arg0 : vector<4xi32> to vector<4xi1>
return %0 : vector<4xi1>
}
// CHECK-LABEL: @fptosi1
func @fptosi1(%arg0 : f32) -> i32 {
// CHECK: spv.ConvertFToS %{{.*}} : f32 to i32
%0 = arith.fptosi %arg0 : f32 to i32
return %0 : i32
}
// CHECK-LABEL: @fptosi2
func @fptosi2(%arg0 : f16) -> i16 {
// CHECK: spv.ConvertFToS %{{.*}} : f16 to i16
%0 = arith.fptosi %arg0 : f16 to i16
return %0 : i16
}
} // end module
// -----
// Checks that cast types will be adjusted when missing special capabilities for
// certain non-32-bit scalar types.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Float64], []>, {}>
} {
// CHECK-LABEL: @fpext1
// CHECK-SAME: %[[ARG:.*]]: f32
func @fpext1(%arg0: f16) -> f64 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f64
%0 = arith.extf %arg0 : f16 to f64
return %0: f64
}
// CHECK-LABEL: @fpext2
// CHECK-SAME: %[[ARG:.*]]: f32
func @fpext2(%arg0 : f32) -> f64 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f64
%0 = arith.extf %arg0 : f32 to f64
return %0: f64
}
} // end module
// -----
// Checks that cast types will be adjusted when missing special capabilities for
// certain non-32-bit scalar types.
module attributes {
spv.target_env = #spv.target_env<#spv.vce<v1.0, [Float16], []>, {}>
} {
// CHECK-LABEL: @fptrunc1
// CHECK-SAME: %[[ARG:.*]]: f32
func @fptrunc1(%arg0 : f64) -> f16 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f16
%0 = arith.truncf %arg0 : f64 to f16
return %0: f16
}
// CHECK-LABEL: @fptrunc2
// CHECK-SAME: %[[ARG:.*]]: f32
func @fptrunc2(%arg0: f32) -> f16 {
// CHECK-NEXT: spv.FConvert %[[ARG]] : f32 to f16
%0 = arith.truncf %arg0 : f32 to f16
return %0: f16
}
// CHECK-LABEL: @sitofp
func @sitofp(%arg0 : i64) -> f64 {
// CHECK: spv.ConvertSToF %{{.*}} : i32 to f32
%0 = arith.sitofp %arg0 : i64 to f64
return %0: f64
}
} // end module
// -----