diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td index e12b8ac84ba23..398388bd720be 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -184,6 +184,15 @@ def LLVM_UMinOp : LLVM_BinarySameArgsIntrOpI<"umin">; def LLVM_SinOp : LLVM_UnaryIntrOpF<"sin">; def LLVM_CosOp : LLVM_UnaryIntrOpF<"cos">; def LLVM_TanOp : LLVM_UnaryIntrOpF<"tan">; +def LLVM_SincosOp : LLVM_TwoResultIntrOp<"sincos", [], [0], + [Pure], /*requiresFastmath=*/1> { + let arguments = + (ins LLVM_ScalarOrVectorOf:$val, + DefaultValuedAttr:$fastmathFlags); + let assemblyFormat = "`(` operands `)` attr-dict `:` " + "functional-type(operands, results)"; + let hasVerifier = 1; +} def LLVM_ASinOp : LLVM_UnaryIntrOpF<"asin">; def LLVM_ACosOp : LLVM_UnaryIntrOpF<"acos">; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index a3d5d25b96ec2..5d08cccb4faab 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -4085,6 +4085,25 @@ printIndirectBrOpSucessors(OpAsmPrinter &p, IndirectBrOp op, Type flagType, p << "]"; } +//===----------------------------------------------------------------------===// +// SincosOp (intrinsic) +//===----------------------------------------------------------------------===// + +LogicalResult LLVM::SincosOp::verify() { + auto operandType = getOperand().getType(); + auto resultType = getResult().getType(); + auto resultStructType = + mlir::dyn_cast(resultType); + if (!resultStructType || resultStructType.getBody().size() != 2 || + resultStructType.getBody()[0] != operandType || + resultStructType.getBody()[1] != operandType) { + return emitOpError("expected result type to be an homogeneous struct with " + "two elements matching the operand type, but got ") + << resultType; + } + return success(); +} + //===----------------------------------------------------------------------===// // AssumeOp (intrinsic) //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir index 1adecf264e8f6..627abd0665d8c 100644 --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -2014,3 +2014,24 @@ llvm.mlir.alias external @alias_resolver : !llvm.ptr { } // expected-error@+1 {{'llvm.mlir.ifunc' op must have a function resolver}} llvm.mlir.ifunc external @foo : !llvm.func, !llvm.ptr @alias_resolver {dso_local} + +// ----- + +llvm.func @invalid_sincos_nonhomogeneous_return_type(%f: f32) -> () { + // expected-error@+1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}} + llvm.intr.sincos(%f) : (f32) -> !llvm.struct<(f32, f64)> +} + +// ----- + +llvm.func @invalid_sincos_non_struct_return_type(%f: f32) -> () { + // expected-error@+1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}} + llvm.intr.sincos(%f) : (f32) -> f32 +} + +// ----- + +llvm.func @invalid_sincos_gt_2_element_struct_return_type(%f: f32) -> () { + // expected-error@+1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}} + llvm.intr.sincos(%f) : (f32) -> !llvm.struct<(f32, f32, f32)> +} diff --git a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir index cf3e129879d09..d63584e5e03ab 100644 --- a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir @@ -146,6 +146,11 @@ llvm.func @trig_test(%arg0: f32, %arg1: vector<8xf32>) { llvm.intr.tan(%arg0) : (f32) -> f32 // CHECK: call <8 x float> @llvm.tan.v8f32 llvm.intr.tan(%arg1) : (vector<8xf32>) -> vector<8xf32> + + // CHECK: call { float, float } @llvm.sincos.f32 + llvm.intr.sincos(%arg0) : (f32) -> !llvm.struct<(f32, f32)> + // CHECK: call { <8 x float>, <8 x float> } @llvm.sincos.v8f32 + llvm.intr.sincos(%arg1) : (vector<8xf32>) -> !llvm.struct<(vector<8xf32>, vector<8xf32>)> llvm.return } @@ -1302,6 +1307,8 @@ llvm.func @experimental_constrained_fpext(%s: f32, %v: vector<4xf32>) { // CHECK-DAG: declare <8 x float> @llvm.ceil.v8f32(<8 x float>) #0 // CHECK-DAG: declare float @llvm.cos.f32(float) // CHECK-DAG: declare <8 x float> @llvm.cos.v8f32(<8 x float>) #0 +// CHECK-DAG: declare { float, float } @llvm.sincos.f32(float) +// CHECK-DAG: declare { <8 x float>, <8 x float> } @llvm.sincos.v8f32(<8 x float>) #0 // CHECK-DAG: declare float @llvm.copysign.f32(float, float) // CHECK-DAG: declare float @llvm.rint.f32(float) // CHECK-DAG: declare double @llvm.rint.f64(double)