Index: mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td =================================================================== --- mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td +++ mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td @@ -168,16 +168,34 @@ let arguments = (ins LLVM_Type, LLVM_Type); } +// Saturation Arithmetic Intrinsics. + +def LLVM_SAddSat + : LLVM_IntrOp<"sadd.sat", [0], [], [], 1> { + let arguments = (ins LLVM_Type, LLVM_Type); +} +def LLVM_UAddSat + : LLVM_IntrOp<"uadd.sat", [0], [], [], 1> { + let arguments = (ins LLVM_Type, LLVM_Type); +} +def LLVM_SSubSat + : LLVM_IntrOp<"ssub.sat", [0], [], [], 1> { + let arguments = (ins LLVM_Type, LLVM_Type); +} +def LLVM_USubSat + : LLVM_IntrOp<"usub.sat", [0], [], [], 1> { + let arguments = (ins LLVM_Type, LLVM_Type); +} def LLVM_AssumeOp : LLVM_ZeroResultIntrOp<"assume", []> { let arguments = (ins LLVM_Type:$cond); } // // Coroutine intrinsics. // def LLVM_CoroIdOp : LLVM_IntrOp<"coro.id", [], [], [], 1> { let arguments = (ins I32:$align, LLVM_i8Ptr:$promise, Index: mlir/test/Target/LLVMIR/Import/intrinsic.ll =================================================================== --- mlir/test/Target/LLVMIR/Import/intrinsic.ll +++ mlir/test/Target/LLVMIR/Import/intrinsic.ll @@ -372,6 +372,42 @@ 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 @uadd_with_overflow_test define void @uadd_with_overflow_test(i32 %0, i32 %1, <8 x i32> %2, <8 x i32> %3) { ; CHECK: "llvm.intr.uadd.with.overflow"(%{{.*}}, %{{.*}}) : (i32, i32) -> !llvm.struct<(i32, i1)> @@ -732,6 +768,14 @@ 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>) #0 declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) declare i8* @llvm.coro.begin(token, i8* writeonly) declare i64 @llvm.coro.size.i64() Index: mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir =================================================================== --- mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir +++ mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir @@ -428,6 +428,42 @@ 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: @coro_id llvm.func @coro_id(%arg0: i32, %arg1: !llvm.ptr) { // CHECK: call token @llvm.coro.id @@ -770,6 +806,14 @@ // CHECK-DAG: declare { <8 x i32>, <8 x i1> } @llvm.usub.with.overflow.v8i32(<8 x i32>, <8 x i32>) #0 // 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>) #0 +// CHECK-DAG: declare i32 @llvm.sadd.sat.i32(i32, i32) #0 +// CHECK-DAG: declare <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32>, <8 x i32>) #0 +// CHECK-DAG: declare i32 @llvm.uadd.sat.i32(i32, i32) #0 +// CHECK-DAG: declare <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32>, <8 x i32>) #0 +// CHECK-DAG: declare i32 @llvm.ssub.sat.i32(i32, i32) #0 +// CHECK-DAG: declare <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32>, <8 x i32>) #0 +// CHECK-DAG: declare i32 @llvm.usub.sat.i32(i32, i32) #0 +// CHECK-DAG: declare <8 x i32> @llvm.usub.sat.v8i32(<8 x i32>, <8 x i32>) #0 // CHECK-DAG: declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) // CHECK-DAG: declare ptr @llvm.coro.begin(token, ptr writeonly) // CHECK-DAG: declare i64 @llvm.coro.size.i64()