[mlir][spirv] Define spv.GLSL.Ldexp

co-authored-by: Alan Liu <alanliu.yf@gmail.com>

Reviewed By: antiagainst

Differential Revision: https://reviews.llvm.org/D97228
This commit is contained in:
Weiwei Li 2021-02-24 13:07:05 -05:00 committed by Lei Zhang
parent fe50be12c8
commit ce2ad938ff
4 changed files with 125 additions and 1 deletions

View File

@ -1069,4 +1069,59 @@ def SPV_GLSLFrexpStructOp : SPV_GLSLOp<"FrexpStruct", 52, [NoSideEffect]> {
let verifier = [{ return ::verifyGLSLFrexpStructOp(*this); }];
}
def SPV_GLSLLdexpOp :
SPV_GLSLOp<"Ldexp", 53, [
NoSideEffect, AllTypesMatch<["x", "y"]>]> {
let summary = "Builds y such that y = significand * 2^exponent";
let description = [{
Builds a floating-point number from x and the corresponding
integral exponent of two in exp:
significand * 2^exponent
If this product is too large to be represented in the floating-point
type, the resulting value is undefined. If exp is greater than +128
(single precision) or +1024 (double precision), the resulting value is
undefined. If exp is less than -126 (single precision) or -1022 (double precision),
the result may be flushed to zero. Additionally, splitting the value
into a significand and exponent using frexp and then reconstructing a
floating-point value using ldexp should yield the original input for
zero and all finite non-denormalized values.
The operand x must be a scalar or vector whose component type is floating-point.
The exp operand must be a scalar or vector with integer component type.
The number of components in x and exp must be the same.
Result Type must be the same type as the type of x. Results are computed per
component.
<!-- End of AutoGen section -->
#### Example:
```mlir
%y = spv.GLSL.Ldexp %x : f32, %exp : i32 -> f32
%y = spv.GLSL.Ldexp %x : vector<3xf32>, %exp : vector<3xi32> -> vector<3xf32>
```
}];
let arguments = (ins
SPV_ScalarOrVectorOf<SPV_Float>:$x,
SPV_ScalarOrVectorOf<SPV_Integer>:$exp
);
let results = (outs
SPV_ScalarOrVectorOf<SPV_Float>:$y
);
let assemblyFormat = [{
attr-dict $x `:` type($x) `,` $exp `:` type($exp) `->` type($y)
}];
let verifier = [{ return ::verify(*this); }];
}
#endif // MLIR_DIALECT_SPIRV_IR_GLSL_OPS

View File

@ -3585,6 +3585,30 @@ verifyGLSLFrexpStructOp(spirv::GLSLFrexpStructOp frexpStructOp) {
"must have the same number of components as the operand type");
}
//===----------------------------------------------------------------------===//
// spv.GLSL.Ldexp
//===----------------------------------------------------------------------===//
static LogicalResult verify(spirv::GLSLLdexpOp ldexpOp) {
Type significandType = ldexpOp.x().getType();
Type exponentType = ldexpOp.exp().getType();
if (significandType.isa<FloatType>() != exponentType.isa<IntegerType>())
return ldexpOp.emitOpError("operands must both be scalars or vectors");
auto getNumElements = [](Type type) -> unsigned {
if (auto vectorType = type.dyn_cast<VectorType>())
return vectorType.getNumElements();
return 1;
};
if (getNumElements(significandType) != getNumElements(exponentType))
return ldexpOp.emitOpError(
"operands must have the same number of elements");
return success();
}
namespace mlir {
namespace spirv {

View File

@ -420,3 +420,46 @@ func @frexp_struct_not_i32(%arg0 : f32) -> () {
%2 = spv.GLSL.FrexpStruct %arg0 : f32 -> !spv.struct<(f32, i64)>
return
}
// -----
//===----------------------------------------------------------------------===//
// spv.GLSL.Ldexp
//===----------------------------------------------------------------------===//
func @ldexp(%arg0 : f32, %arg1 : i32) -> () {
// CHECK: {{%.*}} = spv.GLSL.Ldexp {{%.*}} : f32, {{%.*}} : i32 -> f32
%0 = spv.GLSL.Ldexp %arg0 : f32, %arg1 : i32 -> f32
return
}
// -----
func @ldexp_vec(%arg0 : vector<3xf32>, %arg1 : vector<3xi32>) -> () {
// CHECK: {{%.*}} = spv.GLSL.Ldexp {{%.*}} : vector<3xf32>, {{%.*}} : vector<3xi32> -> vector<3xf32>
%0 = spv.GLSL.Ldexp %arg0 : vector<3xf32>, %arg1 : vector<3xi32> -> vector<3xf32>
return
}
// -----
func @ldexp_wrong_type_scalar(%arg0 : f32, %arg1 : vector<2xi32>) -> () {
// expected-error @+1 {{operands must both be scalars or vectors}}
%0 = spv.GLSL.Ldexp %arg0 : f32, %arg1 : vector<2xi32> -> f32
return
}
// -----
func @ldexp_wrong_type_vec_1(%arg0 : vector<3xf32>, %arg1 : i32) -> () {
// expected-error @+1 {{operands must both be scalars or vectors}}
%0 = spv.GLSL.Ldexp %arg0 : vector<3xf32>, %arg1 : i32 -> vector<3xf32>
return
}
// -----
func @ldexp_wrong_type_vec_2(%arg0 : vector<3xf32>, %arg1 : vector<2xi32>) -> () {
// expected-error @+1 {{operands must have the same number of elements}}
%0 = spv.GLSL.Ldexp %arg0 : vector<3xf32>, %arg1 : vector<2xi32> -> vector<3xf32>
return
}

View File

@ -1,7 +1,7 @@
// RUN: mlir-translate -test-spirv-roundtrip %s | FileCheck %s
spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
spv.func @fmul(%arg0 : f32, %arg1 : f32) "None" {
spv.func @fmul(%arg0 : f32, %arg1 : f32, %arg2 : i32) "None" {
// CHECK: {{%.*}} = spv.GLSL.Exp {{%.*}} : f32
%0 = spv.GLSL.Exp %arg0 : f32
// CHECK: {{%.*}} = spv.GLSL.FMax {{%.*}}, {{%.*}} : f32
@ -30,6 +30,8 @@ spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
%12 = spv.GLSL.Round %arg0 : f32
// CHECK: {{%.*}} = spv.GLSL.FrexpStruct {{%.*}} : f32 -> !spv.struct<(f32, i32)>
%13 = spv.GLSL.FrexpStruct %arg0 : f32 -> !spv.struct<(f32, i32)>
// CHECK: {{%.*}} = spv.GLSL.Ldexp {{%.*}} : f32, {{%.*}} : i32 -> f32
%14 = spv.GLSL.Ldexp %arg0 : f32, %arg2 : i32 -> f32
spv.Return
}