From 6df3db46fa451b6b86ee1f73bd9f7a42ade64be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9on=20Frenot?= Date: Fri, 8 Nov 2024 15:47:19 +0000 Subject: [PATCH 1/2] [mlir][LLVM] Add nsw and nuw flags to trunc This implementation is based on the one already existing for the binary operations. If the nuw keyword is present, and any of the truncated bits are non-zero, the result is a poison value. If the nsw keyword is present, and any of the truncated bits are not the same as the top bit of the truncation result, the result is a poison value. --- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 19 ++++++++++++++++++- mlir/test/Dialect/LLVMIR/roundtrip.mlir | 17 +++++++++++++++++ mlir/test/Target/LLVMIR/Import/nsw_nuw.ll | 2 ++ mlir/test/Target/LLVMIR/nsw_nuw.mlir | 2 ++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index dd0251eb6a285..aa54fd167f151 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -525,6 +525,23 @@ class LLVM_CastOpWithNNegFlag traits = []> : + LLVM_Op], traits)>, + LLVM_Builder<"$res = builder.Create" # instName # "($arg, $_resultType, /*Name=*/\"\", op.hasNoUnsignedWrap(), op.hasNoSignedWrap());"> { + let arguments = (ins type:$arg, EnumProperty<"IntegerOverflowFlags", "", "IntegerOverflowFlags::none">:$overflowFlags); + let results = (outs resultType:$res); + let builders = [LLVM_OneResultOpBuilder]; + let assemblyFormat = "$arg attr-dict `` custom($overflowFlags) `:` type($arg) `to` type($res)"; + string llvmInstName = instName; + string mlirBuilder = [{ + auto op = $_builder.create<$_qualCppClassName>( + $_location, $_resultType, $arg); + moduleImport.setIntegerOverflowFlags(inst, op); + $res = op; + }]; +} + def LLVM_BitcastOp : LLVM_CastOp<"bitcast", "BitCast", LLVM_AnyNonAggregate, LLVM_AnyNonAggregate, [DeclareOpInterfaceMethods]> { let hasFolder = 1; @@ -554,7 +571,7 @@ def LLVM_ZExtOp : LLVM_CastOpWithNNegFlag<"zext", "ZExt", let hasFolder = 1; let hasVerifier = 1; } -def LLVM_TruncOp : LLVM_CastOp<"trunc", "Trunc", +def LLVM_TruncOp : LLVM_CastOpWithOverflowFlag<"trunc", "Trunc", LLVM_ScalarOrVectorOf, LLVM_ScalarOrVectorOf>; def LLVM_SIToFPOp : LLVM_CastOp<"sitofp", "SIToFP", diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir index 193ab53e6e820..aa558bad2299c 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -338,6 +338,23 @@ func.func @nneg_casts(%arg0: i32, %arg1: i64, %arg2: vector<4xi32>, llvm.return } +// CHECK-LABEL: @casts_overflow +// CHECK-SAME: (%[[I32:.*]]: i32, %[[I64:.*]]: i64, %[[V4I32:.*]]: vector<4xi32>, %[[V4I64:.*]]: vector<4xi64>, %[[PTR:.*]]: !llvm.ptr) +func.func @casts_overflow(%arg0: i32, %arg1: i64, %arg2: vector<4xi32>, + %arg3: vector<4xi64>, %arg4: !llvm.ptr) { +// CHECK: = llvm.trunc %[[I64]] overflow : i64 to i56 + %0 = llvm.trunc %arg1 overflow : i64 to i56 +// CHECK: = llvm.trunc %[[I64]] overflow : i64 to i56 + %1 = llvm.trunc %arg1 overflow : i64 to i56 +// CHECK: = llvm.trunc %[[I64]] overflow : i64 to i56 + %2 = llvm.trunc %arg1 overflow : i64 to i56 +// CHECK: = llvm.trunc %[[I64]] overflow : i64 to i56 + %3 = llvm.trunc %arg1 overflow : i64 to i56 +// CHECK: = llvm.trunc %[[V4I64]] overflow : vector<4xi64> to vector<4xi56> + %4 = llvm.trunc %arg3 overflow : vector<4xi64> to vector<4xi56> + llvm.return +} + // CHECK-LABEL: @vect func.func @vect(%arg0: vector<4xf32>, %arg1: i32, %arg2: f32, %arg3: !llvm.vec<2 x ptr>) { // CHECK: = llvm.extractelement {{.*}} : vector<4xf32> diff --git a/mlir/test/Target/LLVMIR/Import/nsw_nuw.ll b/mlir/test/Target/LLVMIR/Import/nsw_nuw.ll index d08098a5e5dfe..4af799da36dc0 100644 --- a/mlir/test/Target/LLVMIR/Import/nsw_nuw.ll +++ b/mlir/test/Target/LLVMIR/Import/nsw_nuw.ll @@ -10,5 +10,7 @@ define void @intflag_inst(i64 %arg1, i64 %arg2) { %3 = mul nsw nuw i64 %arg1, %arg2 ; CHECK: llvm.shl %{{.*}}, %{{.*}} overflow : i64 %4 = shl nuw nsw i64 %arg1, %arg2 + ; CHECK: llvm.trunc %{{.*}} overflow : i64 to i32 + %5 = trunc nsw i64 %arg1 to i32 ret void } diff --git a/mlir/test/Target/LLVMIR/nsw_nuw.mlir b/mlir/test/Target/LLVMIR/nsw_nuw.mlir index 6843c2ef0299c..584aa05a04f7c 100644 --- a/mlir/test/Target/LLVMIR/nsw_nuw.mlir +++ b/mlir/test/Target/LLVMIR/nsw_nuw.mlir @@ -10,5 +10,7 @@ llvm.func @intflags_func(%arg0: i64, %arg1: i64) { %2 = llvm.mul %arg0, %arg1 overflow : i64 // CHECK: %{{.*}} = shl nuw nsw i64 %{{.*}}, %{{.*}} %3 = llvm.shl %arg0, %arg1 overflow : i64 + // CHECK: %{{.*}} = trunc nuw i64 %{{.*}} to i32 + %4 = llvm.trunc %arg1 overflow : i64 to i32 llvm.return } From 5efc314ac30f80cca68de0b38dc55c7abd8ab907 Mon Sep 17 00:00:00 2001 From: lfrenot Date: Mon, 11 Nov 2024 11:13:28 +0000 Subject: [PATCH 2/2] nit update Co-authored-by: Tobias Gysi --- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index aa54fd167f151..81e9f69f15acf 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -532,7 +532,7 @@ class LLVM_CastOpWithOverflowFlag:$overflowFlags); let results = (outs resultType:$res); let builders = [LLVM_OneResultOpBuilder]; - let assemblyFormat = "$arg attr-dict `` custom($overflowFlags) `:` type($arg) `to` type($res)"; + let assemblyFormat = "$arg `` custom($overflowFlags) attr-dict `:` type($arg) `to` type($res)"; string llvmInstName = instName; string mlirBuilder = [{ auto op = $_builder.create<$_qualCppClassName>(