From c04cf58dfc5430f0c82c8ef42c3a8cb43f84020b Mon Sep 17 00:00:00 2001 From: Tobias Gysi Date: Wed, 17 May 2023 06:28:03 +0000 Subject: [PATCH] [mlir][llvm] Saturation arithmetic intrinsics. Add the saturation arithmetic intrinsics to the LLVM dialect. Reviewed By: Dinistro Differential Revision: https://reviews.llvm.org/D150676 --- .../mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td | 11 ++++ mlir/test/Target/LLVMIR/Import/intrinsic.ll | 66 ++++++++++++++++++++++ mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir | 66 ++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td index df6947d..03c3979 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -263,6 +263,17 @@ def LLVM_SMulWithOverflowOp : LLVM_ArithWithOverflowOp<"smul.with.overflow">; def LLVM_UMulWithOverflowOp : LLVM_ArithWithOverflowOp<"umul.with.overflow">; // +// Saturation Arithmetic Intrinsics. +// + +def LLVM_SAddSat : LLVM_BinarySameArgsIntrOpI<"sadd.sat">; +def LLVM_UAddSat : LLVM_BinarySameArgsIntrOpI<"uadd.sat">; +def LLVM_SSubSat : LLVM_BinarySameArgsIntrOpI<"ssub.sat">; +def LLVM_USubSat : LLVM_BinarySameArgsIntrOpI<"usub.sat">; +def LLVM_SSHLSat : LLVM_BinarySameArgsIntrOpI<"sshl.sat">; +def LLVM_USHLSat : LLVM_BinarySameArgsIntrOpI<"ushl.sat">; + +// // Optimization hint intrinsics. // diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic.ll b/mlir/test/Target/LLVMIR/Import/intrinsic.ll index 1903624..811dc44 100644 --- a/mlir/test/Target/LLVMIR/Import/intrinsic.ll +++ b/mlir/test/Target/LLVMIR/Import/intrinsic.ll @@ -448,6 +448,60 @@ define void @umul_with_overflow_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) ret void } +; CHECK-LABEL: llvm.func @sadd_sat_test +define void @sadd_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.sadd.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.sadd.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.sadd.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + +; CHECK-LABEL: llvm.func @uadd_sat_test +define void @uadd_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.uadd.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.uadd.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.uadd.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + +; CHECK-LABEL: llvm.func @ssub_sat_test +define void @ssub_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.ssub.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.ssub.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.ssub.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + +; CHECK-LABEL: llvm.func @usub_sat_test +define void @usub_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.usub.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.usub.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.usub.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + +; CHECK-LABEL: llvm.func @sshl_sat_test +define void @sshl_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.sshl.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.sshl.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.sshl.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.sshl.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + +; CHECK-LABEL: llvm.func @ushl_sat_test +define void @ushl_sat_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { + ; CHECK: llvm.intr.ushl.sat(%{{.*}}, %{{.*}}) : (i32, i32) -> i32 + %5 = call i32 @llvm.ushl.sat.i32(i32 %0, i32 %1) + ; CHECK: llvm.intr.ushl.sat(%{{.*}}, %{{.*}}) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + %6 = call <8 x i32> @llvm.ushl.sat.v8i32(<8 x i32> %2, <8 x i32> %3) + ret void +} + ; CHECK-LABEL: llvm.func @va_intrinsics_test define void @va_intrinsics_test(ptr %0, ptr %1) { ; CHECK: llvm.intr.vastart %{{.*}} @@ -800,6 +854,18 @@ declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32) declare { <8 x i32>, <8 x i1> } @llvm.smul.with.overflow.v8i32(<8 x i32>, <8 x i32>) declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) declare { <8 x i32>, <8 x i1> } @llvm.umul.with.overflow.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.sadd.sat.i32(i32, i32) +declare <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.uadd.sat.i32(i32, i32) +declare <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.ssub.sat.i32(i32, i32) +declare <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.usub.sat.i32(i32, i32) +declare <8 x i32> @llvm.usub.sat.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.sshl.sat.i32(i32, i32) +declare <8 x i32> @llvm.sshl.sat.v8i32(<8 x i32>, <8 x i32>) +declare i32 @llvm.ushl.sat.i32(i32, i32) +declare <8 x i32> @llvm.ushl.sat.v8i32(<8 x i32>, <8 x i32>) declare i1 @llvm.is.constant.i32(i32) declare i32 @llvm.expect.i32(i32, i32) declare i16 @llvm.expect.with.probability.i16(i16, i16, double immarg) diff --git a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir index eb72a43..c6a3c7f 100644 --- a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir @@ -489,6 +489,60 @@ llvm.func @expect_with_probability(%arg0: i16) { llvm.return } +// CHECK-LABEL: @sadd_sat_test +llvm.func @sadd_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.sadd.sat.i32 + "llvm.intr.sadd.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.sadd.sat.v8i32 + "llvm.intr.sadd.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @uadd_sat_test +llvm.func @uadd_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.uadd.sat.i32 + "llvm.intr.uadd.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.uadd.sat.v8i32 + "llvm.intr.uadd.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @ssub_sat_test +llvm.func @ssub_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.ssub.sat.i32 + "llvm.intr.ssub.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.ssub.sat.v8i32 + "llvm.intr.ssub.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @usub_sat_test +llvm.func @usub_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.usub.sat.i32 + "llvm.intr.usub.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.usub.sat.v8i32 + "llvm.intr.usub.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @sshl_sat_test +llvm.func @sshl_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.sshl.sat.i32 + "llvm.intr.sshl.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.sshl.sat.v8i32 + "llvm.intr.sshl.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + +// CHECK-LABEL: @ushl_sat_test +llvm.func @ushl_sat_test(%arg0: i32, %arg1: i32, %arg2: vector<8xi32>, %arg3: vector<8xi32>) { + // CHECK: call i32 @llvm.ushl.sat.i32 + "llvm.intr.ushl.sat"(%arg0, %arg1) : (i32, i32) -> i32 + // CHECK: call <8 x i32> @llvm.ushl.sat.v8i32 + "llvm.intr.ushl.sat"(%arg2, %arg3) : (vector<8xi32>, vector<8xi32>) -> vector<8xi32> + llvm.return +} + // CHECK-LABEL: @coro_id llvm.func @coro_id(%arg0: i32, %arg1: !llvm.ptr) { // CHECK: call token @llvm.coro.id @@ -837,6 +891,18 @@ llvm.func @lifetime(%p: !llvm.ptr) { // CHECK-DAG: declare { <8 x i32>, <8 x i1> } @llvm.usub.with.overflow.v8i32(<8 x i32>, <8 x i32>) // CHECK-DAG: declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32) // CHECK-DAG: declare { <8 x i32>, <8 x i1> } @llvm.umul.with.overflow.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.sadd.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.uadd.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.ssub.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.usub.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.usub.sat.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.sshl.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.sshl.sat.v8i32(<8 x i32>, <8 x i32>) +// CHECK-DAG: declare i32 @llvm.ushl.sat.i32(i32, i32) +// CHECK-DAG: declare <8 x i32> @llvm.ushl.sat.v8i32(<8 x i32>, <8 x i32>) // CHECK-DAG: declare i1 @llvm.is.constant.i32(i32) // CHECK-DAG: declare i32 @llvm.expect.i32(i32, i32) // CHECK-DAG: declare i16 @llvm.expect.with.probability.i16(i16, i16, double immarg) -- 2.7.4