diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -57,19 +57,31 @@ let arguments = !con(commonArgs, fmfArg); } -class LLVM_TernarySameArgsIntrOpF traits = []> : +class LLVM_TernarySameArgsIntrOpBase traits = [], bit requiresFastmath = 0> : LLVM_OneResultIntrOp { - let arguments = (ins LLVM_ScalarOrVectorOf:$a, - LLVM_ScalarOrVectorOf:$b, - LLVM_ScalarOrVectorOf:$c, - DefaultValuedAttr:$fastmathFlags); + requiresFastmath> { + dag commonArgs = (ins LLVM_ScalarOrVectorOf:$a, + LLVM_ScalarOrVectorOf:$b, + LLVM_ScalarOrVectorOf:$c); let assemblyFormat = "`(` operands `)` custom(attr-dict) `:` " "functional-type(operands, results)"; } +class LLVM_TernarySameArgsIntrOpI traits = []> : + LLVM_TernarySameArgsIntrOpBase { + let arguments = commonArgs; +} + +class LLVM_TernarySameArgsIntrOpF traits = []> : + LLVM_TernarySameArgsIntrOpBase { + dag fmfArg = ( + ins DefaultValuedAttr:$fastmathFlags); + let arguments = !con(commonArgs, fmfArg); +} + class LLVM_CountZerosIntrOp traits = []> : LLVM_OneResultIntrOp { @@ -117,9 +129,12 @@ "functional-type(operands, results)"; } def LLVM_BitReverseOp : LLVM_UnaryIntrOpI<"bitreverse">; +def LLVM_BitSwapOp : LLVM_UnaryIntrOpI<"bswap">; def LLVM_CountLeadingZerosOp : LLVM_CountZerosIntrOp<"ctlz">; def LLVM_CountTrailingZerosOp : LLVM_CountZerosIntrOp<"cttz">; def LLVM_CtPopOp : LLVM_UnaryIntrOpI<"ctpop">; +def LLVM_FshlOp : LLVM_TernarySameArgsIntrOpI<"fshl">; +def LLVM_FshrOp : LLVM_TernarySameArgsIntrOpI<"fshr">; def LLVM_MaxNumOp : LLVM_BinarySameArgsIntrOpF<"maxnum">; def LLVM_MinNumOp : LLVM_BinarySameArgsIntrOpF<"minnum">; def LLVM_MaximumOp : LLVM_BinarySameArgsIntrOpF<"maximum">; diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic.ll b/mlir/test/Target/LLVMIR/Import/intrinsic.ll --- a/mlir/test/Target/LLVMIR/Import/intrinsic.ll +++ b/mlir/test/Target/LLVMIR/Import/intrinsic.ll @@ -125,6 +125,14 @@ %4 = call <8 x i32> @llvm.bitreverse.v8i32(<8 x i32> %1) ret void } +; CHECK-LABEL: llvm.func @bitswap_test +define void @bitswap_test(i32 %0, <8 x i32> %1) { + ; CHECK: llvm.intr.bswap(%{{.*}}) : (i32) -> i32 + %3 = call i32 @llvm.bswap.i32(i32 %0) + ; CHECK: llvm.intr.bswap(%{{.*}}) : (vector<8xi32>) -> vector<8xi32> + %4 = call <8 x i32> @llvm.bswap.v8i32(<8 x i32> %1) + ret void +} ; CHECK-LABEL: llvm.func @ctlz_test define void @ctlz_test(i32 %0, <8 x i32> %1) { ; CHECK: %[[FALSE:.+]] = llvm.mlir.constant(false) : i1 @@ -153,6 +161,24 @@ ret void } +; CHECK-LABEL: llvm.func @fshl_test +define void @fshl_test(i32 %0, i32 %1, i32 %2, <8 x i32> %3, <8 x i32> %4, <8 x i32> %5) { + ; CHECK: llvm.intr.fshl(%{{.*}}, %{{.*}}, %{{.*}}) : (i32, i32, i32) -> i32 + %7 = call i32 @llvm.fshl.i32(i32 %0, i32 %1, i32 %2) + ; CHECK: llvm.intr.fshl(%{{.*}}, %{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %8 = call <8 x i32> @llvm.fshl.v8i32(<8 x i32> %3, <8 x i32> %4, <8 x i32> %5) + ret void +} + +; CHECK-LABEL: llvm.func @fshr_test +define void @fshr_test(i32 %0, i32 %1, i32 %2, <8 x i32> %3, <8 x i32> %4, <8 x i32> %5) { + ; CHECK: llvm.intr.fshr(%{{.*}}, %{{.*}}, %{{.*}}) : (i32, i32, i32) -> i32 + %7 = call i32 @llvm.fshr.i32(i32 %0, i32 %1, i32 %2) + ; CHECK: llvm.intr.fshr(%{{.*}}, %{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %8 = call <8 x i32> @llvm.fshr.v8i32(<8 x i32> %3, <8 x i32> %4, <8 x i32> %5) + ret void +} + ; CHECK-LABEL: llvm.func @maximum_test define void @maximum_test(float %0, float %1, <8 x float> %2, <8 x float> %3) { ; CHECK: llvm.intr.maximum(%{{.*}}, %{{.*}}) : (f32, f32) -> f32 @@ -665,12 +691,18 @@ declare <8 x float> @llvm.pow.v8f32(<8 x float>, <8 x float>) declare i32 @llvm.bitreverse.i32(i32) declare <8 x i32> @llvm.bitreverse.v8i32(<8 x i32>) +declare i32 @llvm.bswap.i32(i32) +declare <8 x i32> @llvm.bswap.v8i32(<8 x i32>) declare i32 @llvm.ctlz.i32(i32, i1 immarg) declare <8 x i32> @llvm.ctlz.v8i32(<8 x i32>, i1 immarg) declare i32 @llvm.cttz.i32(i32, i1 immarg) declare <8 x i32> @llvm.cttz.v8i32(<8 x i32>, i1 immarg) declare i32 @llvm.ctpop.i32(i32) declare <8 x i32> @llvm.ctpop.v8i32(<8 x i32>) +declare i32 @llvm.fshl.i32(i32, i32, i32) +declare <8 x i32> @llvm.fshl.v8i32(<8 x i32>, <8 x i32>, <8 x i32>) +declare i32 @llvm.fshr.i32(i32, i32, i32) +declare <8 x i32> @llvm.fshr.v8i32(<8 x i32>, <8 x i32>, <8 x i32>) declare float @llvm.maximum.f32(float, float) declare <8 x float> @llvm.maximum.v8f32(<8 x float>, <8 x float>) declare float @llvm.minimum.f32(float, float) diff --git a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir --- a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir @@ -143,6 +143,15 @@ llvm.return } +// CHECK-LABEL: @bitswap_test +llvm.func @bitswap_test(%arg0: i32, %arg1: vector<8xi32>) { + // CHECK: call i32 @llvm.bswap.i32 + "llvm.intr.bswap"(%arg0) : (i32) -> i32 + // CHECK: call <8 x i32> @llvm.bswap.v8i32 + "llvm.intr.bswap"(%arg1) : (vector<8xi32>) -> vector<8xi32> + llvm.return +} + // CHECK-LABEL: @ctlz_test llvm.func @ctlz_test(%arg0: i32, %arg1: vector<8xi32>) { %i1 = llvm.mlir.constant(false) : i1 @@ -172,6 +181,24 @@ llvm.return } +// CHECK-LABEL: @fshl_test +llvm.func @fshl_test(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: vector<8xi32>, %arg4: vector<8xi32>, %arg5: vector<8xi32>) { + // CHECK: call i32 @llvm.fshl.i32 + "llvm.intr.fshl"(%arg0, %arg1, %arg2) : (i32, i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.fshl.v8i32 + "llvm.intr.fshl"(%arg3, %arg4, %arg5) : (vector<8xi32>, vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @fshr_test +llvm.func @fshr_test(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: vector<8xi32>, %arg4: vector<8xi32>, %arg5: vector<8xi32>) { + // CHECK: call i32 @llvm.fshr.i32 + "llvm.intr.fshr"(%arg0, %arg1, %arg2) : (i32, i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.fshr.v8i32 + "llvm.intr.fshr"(%arg3, %arg4, %arg5) : (vector<8xi32>, vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + // CHECK-LABEL: @maximum_test llvm.func @maximum_test(%arg0: f32, %arg1: f32, %arg2: vector<8xf32>, %arg3: vector<8xf32>) { // CHECK: call float @llvm.maximum.f32 diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir --- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir @@ -91,7 +91,7 @@ // ----- llvm.func @ternary_float_intr_wrong_type(%arg0 : f32, %arg1 : f32, %arg2 : i32) -> f32 { - // expected-error @below{{op operand #2 must be floating-point or LLVM dialect-compatible vector of floating-point}} + // expected-error @below{{op operand #2 must be floating point LLVM type or LLVM dialect-compatible vector of floating point LLVM type}} %0 = "llvm.intr.fma"(%arg0, %arg1, %arg2) : (f32, f32, i32) -> f32 llvm.return %0 : f32 }