Index: mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLSLOps.td =================================================================== --- mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLSLOps.td +++ mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLSLOps.td @@ -1069,4 +1069,62 @@ let verifier = [{ return ::verifyGLSLFrexpStructOp(*this); }]; } +def SPV_GLSLLdexpOp : SPV_GLSLOp<"Ldexp", 53, [NoSideEffect]> { + 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. + + + ``` + float-scalar-vector-type ::= float-type | + `vector<` integer-literal `x` float-type `>` + ldexp-op ::= ssa-id `=` `spv.GLSL.Ldexp` ssa-use `:` + float-scalar-vector-type `,` integer-type + ``` + #### Example: + + ```mlir + %2 = spv.GLSL.Ldexp %0, %1 : f32, i32 -> f32 + %3 = spv.GLSL.Ldexp %0, %1 : vector<3xf32>, vector<3xi32> -> vector<3xf32> + ``` + }]; + + let arguments = (ins + SPV_ScalarOrVectorOf:$x, + SPV_ScalarOrVectorOf:$exp + ); + + let results = (outs + SPV_ScalarOrVectorOf:$result + ); + + let assemblyFormat = [{ + attr-dict $x `,` $exp `:` type($x) `,` type($exp) `->` type($result) + }]; + + let verifier = [{ return ::verify(*this); }]; +} + + #endif // MLIR_DIALECT_SPIRV_IR_GLSL_OPS Index: mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp =================================================================== --- mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp +++ mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp @@ -3585,6 +3585,37 @@ "must have the same number of components as the operand type"); } +//===----------------------------------------------------------------------===// +// spv.GLSL.Ldexp +//===----------------------------------------------------------------------===// + +static LogicalResult verify(spirv::GLSLLdexpOp ldexpOp) { + Type resultTy = ldexpOp.result().getType(); + Type significandTy = ldexpOp.x().getType(); + Type exponentTy = ldexpOp.exp().getType(); + + if (resultTy != significandTy) + return ldexpOp.emitError( + "result type must be the same type as the type of the x operand"); + + if (significandTy.isa()) { + if (!exponentTy.isa()) + return ldexpOp.emitError("the number of components in x and exp " + "must be the same"); + } else if (VectorType significandVecTy = + significandTy.dyn_cast()) { + if (!exponentTy.isa()) + return ldexpOp.emitError("the number of components in x and exp " + "must be the same"); + + VectorType exponentVecTy = exponentTy.cast(); + if (exponentVecTy.getNumElements() != significandVecTy.getNumElements()) + return ldexpOp.emitError("the number of components in x and exp " + "must be the same"); + } + return success(); +} + namespace mlir { namespace spirv { Index: mlir/test/Dialect/SPIRV/IR/glsl-ops.mlir =================================================================== --- mlir/test/Dialect/SPIRV/IR/glsl-ops.mlir +++ mlir/test/Dialect/SPIRV/IR/glsl-ops.mlir @@ -420,3 +420,54 @@ %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, %arg1 : f32, 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, %arg1 : vector<3xf32>, vector<3xi32> -> vector<3xf32> + return +} + +// ----- + +func @ldexp_wrong_result_type(%arg0 : vector<3xf32>, %arg1 : vector<3xi32>) -> () { + // expected-error @+1 {{result type must be the same type as the type of the x operand}} + %0 = spv.GLSL.Ldexp %arg0, %arg1 : vector<3xf32>, vector<3xi32> -> vector<2xf32> + return +} + +// ----- + +func @ldexp_wrong_type_scalar(%arg0 : f32, %arg1 : vector<2xi32>) -> () { + // expected-error @+1 {{the number of components in x and exp must be the same}} + %0 = spv.GLSL.Ldexp %arg0, %arg1 : f32, vector<2xi32> -> f32 + return +} + +// ----- + +func @ldexp_wrong_type_vec_1(%arg0 : vector<3xf32>, %arg1 : i32) -> () { + // expected-error @+1 {{the number of components in x and exp must be the same}} + %0 = spv.GLSL.Ldexp %arg0, %arg1 : vector<3xf32>, i32 -> vector<3xf32> + return +} + +// ----- + +func @ldexp_wrong_type_vec_2(%arg0 : vector<3xf32>, %arg1 : vector<2xi32>) -> () { + // expected-error @+1 {{the number of components in x and exp must be the same}} + %0 = spv.GLSL.Ldexp %arg0, %arg1 : vector<3xf32>, vector<2xi32> -> vector<3xf32> + return +} \ No newline at end of file Index: mlir/test/Target/SPIRV/glsl-ops.mlir =================================================================== --- mlir/test/Target/SPIRV/glsl-ops.mlir +++ mlir/test/Target/SPIRV/glsl-ops.mlir @@ -1,7 +1,7 @@ // RUN: mlir-translate -test-spirv-roundtrip %s | FileCheck %s spv.module Logical GLSL450 requires #spv.vce { - 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 @@ %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, %arg2 : f32, i32 -> f32 spv.Return }