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
1757 lines
54 KiB
MLIR
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
|
|
|
|
// -----
|