From a47b28cf95f5fca857184f05f0c3840b24e470d5 Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Fri, 28 Nov 2025 04:25:38 +0000 Subject: [PATCH 1/3] [mlir][UB] Add `ub.unreachable` operation --- mlir/include/mlir/Dialect/UB/IR/UBOps.td | 20 +++++++++++ mlir/lib/Conversion/UBToLLVM/UBToLLVM.cpp | 35 +++++++++++++++---- mlir/lib/Conversion/UBToSPIRV/UBToSPIRV.cpp | 14 +++++++- mlir/test/Conversion/UBToLLVM/ub-to-llvm.mlir | 6 ++++ .../Conversion/UBToSPIRV/ub-to-spirv.mlir | 15 ++++++++ mlir/test/Dialect/UB/ops.mlir | 6 ++++ 6 files changed, 88 insertions(+), 8 deletions(-) diff --git a/mlir/include/mlir/Dialect/UB/IR/UBOps.td b/mlir/include/mlir/Dialect/UB/IR/UBOps.td index c400a2ef2cc7a..8a354da2db10c 100644 --- a/mlir/include/mlir/Dialect/UB/IR/UBOps.td +++ b/mlir/include/mlir/Dialect/UB/IR/UBOps.td @@ -66,4 +66,24 @@ def PoisonOp : UB_Op<"poison", [ConstantLike, Pure]> { let hasFolder = 1; } +//===----------------------------------------------------------------------===// +// UnreachableOp +//===----------------------------------------------------------------------===// + +def UnreachableOp : UB_Op<"unreachable", [Terminator]> { + let summary = "Unreachable operation."; + let description = [{ + The `unreachable` operation has no defined semantics. This operation + indicates that its enclosing basic block is not reachable. + + Example: + + ``` + ub.unreachable + ``` + }]; + + let assemblyFormat = "attr-dict"; +} + #endif // MLIR_DIALECT_UB_IR_UBOPS_TD diff --git a/mlir/lib/Conversion/UBToLLVM/UBToLLVM.cpp b/mlir/lib/Conversion/UBToLLVM/UBToLLVM.cpp index 9921a06778dd7..feb04899cb33d 100644 --- a/mlir/lib/Conversion/UBToLLVM/UBToLLVM.cpp +++ b/mlir/lib/Conversion/UBToLLVM/UBToLLVM.cpp @@ -23,8 +23,11 @@ namespace mlir { using namespace mlir; -namespace { +//===----------------------------------------------------------------------===// +// PoisonOpLowering +//===----------------------------------------------------------------------===// +namespace { struct PoisonOpLowering : public ConvertOpToLLVMPattern { using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; @@ -32,13 +35,8 @@ struct PoisonOpLowering : public ConvertOpToLLVMPattern { matchAndRewrite(ub::PoisonOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override; }; - } // namespace -//===----------------------------------------------------------------------===// -// PoisonOpLowering -//===----------------------------------------------------------------------===// - LogicalResult PoisonOpLowering::matchAndRewrite(ub::PoisonOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const { @@ -60,6 +58,29 @@ PoisonOpLowering::matchAndRewrite(ub::PoisonOp op, OpAdaptor adaptor, return success(); } +//===----------------------------------------------------------------------===// +// UnreachableOpLowering +//===----------------------------------------------------------------------===// + +namespace { +struct UnreachableOpLowering + : public ConvertOpToLLVMPattern { + using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; + + LogicalResult + matchAndRewrite(ub::UnreachableOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override; +}; +} // namespace +LogicalResult + +UnreachableOpLowering::matchAndRewrite( + ub::UnreachableOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const { + rewriter.replaceOpWithNewOp(op); + return success(); +} + //===----------------------------------------------------------------------===// // Pass Definition //===----------------------------------------------------------------------===// @@ -93,7 +114,7 @@ struct UBToLLVMConversionPass void mlir::ub::populateUBToLLVMConversionPatterns( const LLVMTypeConverter &converter, RewritePatternSet &patterns) { - patterns.add(converter); + patterns.add(converter); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/UBToSPIRV/UBToSPIRV.cpp b/mlir/lib/Conversion/UBToSPIRV/UBToSPIRV.cpp index 244d214cba196..3831387816eaf 100644 --- a/mlir/lib/Conversion/UBToSPIRV/UBToSPIRV.cpp +++ b/mlir/lib/Conversion/UBToSPIRV/UBToSPIRV.cpp @@ -40,6 +40,17 @@ struct PoisonOpLowering final : OpConversionPattern { } }; +struct UnreachableOpLowering final : OpConversionPattern { + using Base::Base; + + LogicalResult + matchAndRewrite(ub::UnreachableOp op, OpAdaptor, + ConversionPatternRewriter &rewriter) const override { + rewriter.replaceOpWithNewOp(op); + return success(); + } +}; + } // namespace //===----------------------------------------------------------------------===// @@ -75,5 +86,6 @@ struct UBToSPIRVConversionPass final void mlir::ub::populateUBToSPIRVConversionPatterns( const SPIRVTypeConverter &converter, RewritePatternSet &patterns) { - patterns.add(converter, patterns.getContext()); + patterns.add(converter, + patterns.getContext()); } diff --git a/mlir/test/Conversion/UBToLLVM/ub-to-llvm.mlir b/mlir/test/Conversion/UBToLLVM/ub-to-llvm.mlir index 6c0b111d4c2c5..0fe63f5a3a89f 100644 --- a/mlir/test/Conversion/UBToLLVM/ub-to-llvm.mlir +++ b/mlir/test/Conversion/UBToLLVM/ub-to-llvm.mlir @@ -17,3 +17,9 @@ func.func @check_poison() { %3 = ub.poison : !llvm.ptr return } + +// CHECK-LABEL: @check_unrechable +func.func @check_unrechable() { +// CHECK: llvm.unreachable + ub.unreachable +} diff --git a/mlir/test/Conversion/UBToSPIRV/ub-to-spirv.mlir b/mlir/test/Conversion/UBToSPIRV/ub-to-spirv.mlir index f497eb3bc552c..edbe8b8001bba 100644 --- a/mlir/test/Conversion/UBToSPIRV/ub-to-spirv.mlir +++ b/mlir/test/Conversion/UBToSPIRV/ub-to-spirv.mlir @@ -19,3 +19,18 @@ func.func @check_poison() { } } + +// ----- + +// No successful test because the dialect conversion framework does not convert +// unreachable blocks. + +module attributes { + spirv.target_env = #spirv.target_env< + #spirv.vce, #spirv.resource_limits<>> +} { +func.func @check_unrechable() { +// expected-error@+1{{cannot be used in reachable block}} + spirv.Unreachable +} +} diff --git a/mlir/test/Dialect/UB/ops.mlir b/mlir/test/Dialect/UB/ops.mlir index 724b6b4caac5d..730c1bd1380b8 100644 --- a/mlir/test/Dialect/UB/ops.mlir +++ b/mlir/test/Dialect/UB/ops.mlir @@ -38,3 +38,9 @@ func.func @poison_tensor() -> tensor<8x?xf64> { %0 = ub.poison : tensor<8x?xf64> return %0 : tensor<8x?xf64> } + +// CHECK-LABEL: func @unreachable() +// CHECK: ub.unreachable +func.func @unreachable() { + ub.unreachable +} From e0ec74421b1f0c07ce3d06f57b7ed90f631a0090 Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Fri, 28 Nov 2025 19:13:45 +0900 Subject: [PATCH 2/3] Update mlir/include/mlir/Dialect/UB/IR/UBOps.td Co-authored-by: Mehdi Amini --- mlir/include/mlir/Dialect/UB/IR/UBOps.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Dialect/UB/IR/UBOps.td b/mlir/include/mlir/Dialect/UB/IR/UBOps.td index 8a354da2db10c..891591e4f9331 100644 --- a/mlir/include/mlir/Dialect/UB/IR/UBOps.td +++ b/mlir/include/mlir/Dialect/UB/IR/UBOps.td @@ -73,7 +73,7 @@ def PoisonOp : UB_Op<"poison", [ConstantLike, Pure]> { def UnreachableOp : UB_Op<"unreachable", [Terminator]> { let summary = "Unreachable operation."; let description = [{ - The `unreachable` operation has no defined semantics. This operation + The `unreachable` operation triggers immediate undefined behavior if executed. This operation indicates that its enclosing basic block is not reachable. Example: From e8d698d0b14097f48fa8c309794f0434e108ebf5 Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Fri, 28 Nov 2025 10:15:21 +0000 Subject: [PATCH 3/3] line break and remove last sentence from docs --- mlir/include/mlir/Dialect/UB/IR/UBOps.td | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/include/mlir/Dialect/UB/IR/UBOps.td b/mlir/include/mlir/Dialect/UB/IR/UBOps.td index 891591e4f9331..1bff39add691e 100644 --- a/mlir/include/mlir/Dialect/UB/IR/UBOps.td +++ b/mlir/include/mlir/Dialect/UB/IR/UBOps.td @@ -73,8 +73,8 @@ def PoisonOp : UB_Op<"poison", [ConstantLike, Pure]> { def UnreachableOp : UB_Op<"unreachable", [Terminator]> { let summary = "Unreachable operation."; let description = [{ - The `unreachable` operation triggers immediate undefined behavior if executed. This operation - indicates that its enclosing basic block is not reachable. + The `unreachable` operation triggers immediate undefined behavior if + executed. Example: