[mlir][spirv] Define spv.GLSL.Ldexp
authorWeiwei Li <weiwei.li1@huawei.com>
Wed, 24 Feb 2021 18:07:05 +0000 (13:07 -0500)
committerLei Zhang <antiagainst@google.com>
Wed, 24 Feb 2021 18:07:46 +0000 (13:07 -0500)
co-authored-by: Alan Liu <alanliu.yf@gmail.com>

Reviewed By: antiagainst

Differential Revision: https://reviews.llvm.org/D97228

mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLSLOps.td
mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
mlir/test/Dialect/SPIRV/IR/glsl-ops.mlir
mlir/test/Target/SPIRV/glsl-ops.mlir

index 51ed82d..2097498 100644 (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
index 05ca48d..242c86b 100644 (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 {
 
index 49fa6c3..5b6d382 100644 (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
+}
index 00422c2..8fb5832 100644 (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
   }