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 @@ -1012,4 +1012,53 @@ }]; } +// ---- + +def SPV_GLSLFrexpStructOp : SPV_GLSLOp<"FrexpStruct", 52, [NoSideEffect]> { + let summary = "Splits x into two components such that x = significand * 2^exponent"; + + let description = [{ + Same semantics as in Frexp, except that the entire result is in the + instruction’s result; there is not a pointer operand to write through. + + Result Type must be an OpTypeStruct with two members. Member 0 must + have the same type as the type of x. Member 0 holds the significand. + Member 1 must be a scalar or vector with integer component type, with + 32-bit component width. Member 1 holds exponent. These two members + must have the same number of components. This structure type must be + explicitly declared by the module. + + + ``` + float-scalar-vector-type ::= float-type | + `vector<` integer-literal `x` float-type `>` + integer-scalar-vector-type ::= integer-type | + `vector<` integer-literal `x` integer-type `>` + frexpstruct-op ::= ssa-id `=` `spv.GLSL.FrexpStruct` ssa-use `:` + `!spv.struct<` float-scalar-vector-type `,` + integer-scalar-vector-type `>` + ``` + #### Example: + + ```mlir + %2 = spv.GLSL.FrexpStruct %0 : !spv.struct + %3 = spv.GLSL.FrexpStruct %0 : !spv.struct, vector<3xi32>> + ``` + }]; + + let arguments = (ins + SPV_ScalarOrVectorOf:$operand + ); + + let results = (outs + SPV_AnyStruct:$result + ); + + let parser = [{ return ::parseGLSLFrexpStructOp(parser, result); }]; + + let printer = [{ return ::printGLSLFrexpStructOp(*this, p); }]; + + let verifier = [{ return ::verifyGLSLFrexpStructOp(*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 @@ -3534,6 +3534,87 @@ return success(); } +//===----------------------------------------------------------------------===// +// spv.GLSL.FrexpStruct +//===----------------------------------------------------------------------===// +static ParseResult parseGLSLFrexpStructOp(OpAsmParser &parser, + OperationState &state) { + OpAsmParser::OperandType operand; + Type type; + auto loc = parser.getCurrentLocation(); + if (parser.parseOperand(operand) || parser.parseColonType(type)) + return failure(); + + spirv::StructType resultType = type.dyn_cast(); + if (!resultType) + return parser.emitError( + loc, "result type must be a SPIRV structure type, but provided ") + << type; + + if (resultType.getNumElements() != 2) + return parser.emitError(loc, "result structure type with two members"); + + state.addTypes(type); + return parser.resolveOperand(operand, resultType.getElementType(0), + state.operands); +} + +static void printGLSLFrexpStructOp(spirv::GLSLFrexpStructOp frexpStructOp, + OpAsmPrinter &printer) { + printer << spirv::GLSLFrexpStructOp::getOperationName() << " " + << frexpStructOp.operand() << " : " + << frexpStructOp.result().getType(); +} + +static LogicalResult +verifyGLSLFrexpStructOp(spirv::GLSLFrexpStructOp frexpStructOp) { + spirv::StructType structTy = + frexpStructOp.result().getType().dyn_cast(); + if (!structTy) + return frexpStructOp.emitError("result type must be struct type"); + + Type memberZeroTy = structTy.getElementType(0); + Type memberOneTy = structTy.getElementType(1); + VectorType memberOneVecTy = memberOneTy.dyn_cast(); + IntegerType memberOneIntTy = memberOneTy.dyn_cast(); + + Type operandTy = frexpStructOp.operand().getType(); + VectorType operandVecTy = operandTy.dyn_cast(); + FloatType operandFTy = operandTy.dyn_cast(); + + // Check that member zero has the same type as the operand + if (memberZeroTy != operandTy) + return frexpStructOp.emitError("member zero of the resulting struct type " + "must be of the same type as the operand"); + + // Check that member one must be scalar or vector of 32bit integer type + if (memberOneVecTy) { + IntegerType componentIntTy = + memberOneVecTy.getElementType().dyn_cast(); + if (!(componentIntTy && componentIntTy.getWidth() == 32)) { + return frexpStructOp.emitError( + "member one of the resulting struct type " + "must be a scalar or vector of 32 bit integer type"); + } + } else if (!(memberOneIntTy && memberOneIntTy.getWidth() == 32)) { + return frexpStructOp.emitError( + "member one of the resulting struct type " + "must be a scalar or vector of 32 bit integer type"); + } + + // Check that the two member types have the same number of components + if (operandVecTy && memberOneVecTy && + (memberOneVecTy.getNumElements() == operandVecTy.getNumElements())) + return success(); + + if (operandFTy && memberOneIntTy) + return success(); + + return frexpStructOp.emitError( + "member one of the resulting struct type " + "must have the same number of components as the operand type"); +} + 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 @@ -365,3 +365,50 @@ %2 = spv.GLSL.Fma %a, %b, %c : vector<3xf32> return } +// ----- + +//===----------------------------------------------------------------------===// +// spv.GLSL.FrexpStruct +//===----------------------------------------------------------------------===// + +func @frexp_struct(%arg0 : f32) -> () { + // CHECK: spv.GLSL.FrexpStruct {{%.*}} : !spv.struct<(f32, i32)> + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(f32, i32)> + return +} + +func @frexp_struct_64(%arg0 : f64) -> () { + // CHECK: spv.GLSL.FrexpStruct {{%.*}} : !spv.struct<(f64, i32)> + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(f64, i32)> + return +} + +func @frexp_struct_vec(%arg0 : vector<3xf32>) -> () { + // CHECK: spv.GLSL.FrexpStruct {{%.*}} : !spv.struct<(vector<3xf32>, vector<3xi32>)> + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(vector<3xf32>, vector<3xi32>)> + return +} + +// ----- + +func @frexp_struct_wrong_type(%arg0 : i32) -> () { + // expected-error @+1 {{op operand #0 must be 16/32/64-bit float or vector of 16/32/64-bit float values}} + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(i32, vector<3xi32>)> + return +} + +// ----- + +func @frexp_struct_mismatch_num_components(%arg0 : vector<3xf32>) -> () { + // expected-error @+1 {{member one of the resulting struct type must have the same number of components as the operand type}} + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(vector<3xf32>, vector<2xi32>)> + return +} + +// ----- + +func @frexp_struct_not_i32(%arg0 : f32) -> () { + // expected-error @+1 {{member one of the resulting struct type must be a scalar or vector of 32 bit integer type}} + %2 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(f32, i64)> + return +} Index: mlir/test/Target/SPIRV/glsl-ops.mlir =================================================================== --- mlir/test/Target/SPIRV/glsl-ops.mlir +++ mlir/test/Target/SPIRV/glsl-ops.mlir @@ -28,6 +28,8 @@ %11 = spv.GLSL.Pow %arg0, %arg1 : f32 // CHECK: {{%.*}} = spv.GLSL.Round {{%.*}} : f32 %12 = spv.GLSL.Round %arg0 : f32 + // CHECK: {{%.*}} = spv.GLSL.FrexpStruct {{%.*}} : !spv.struct<(f32, i32)> + %13 = spv.GLSL.FrexpStruct %arg0 : !spv.struct<(f32, i32)> spv.Return }