[clang] [CIR] Add CIRGen for cir.unreachable and cir.trap (PR #151363)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 31 09:19:21 PDT 2025
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/151363
>From 8f1deb8f71b2fec45c706ae4a6b21a87cab43bc9 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Thu, 31 Jul 2025 01:08:22 +0800
Subject: [PATCH] [CIR] Add CIRGen for cir.unreachable and cir.trap
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 11 ++++
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 14 +++++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 20 +++++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 10 +++-
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 ++++
clang/test/CIR/CodeGen/builtin_call.cpp | 60 +++++++++++++++++++
6 files changed, 124 insertions(+), 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 9049a016b2b9b..fd652981cc51a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -21,6 +21,7 @@
#include "mlir/Support/LLVM.h"
#include "clang/AST/Expr.h"
#include "clang/AST/GlobalDecl.h"
+#include "clang/Basic/Builtins.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/Support/ErrorHandling.h"
@@ -269,6 +270,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__builtin_rotateright32:
case Builtin::BI__builtin_rotateright64:
return emitRotate(e, /*isRotateLeft=*/false);
+
+ case Builtin::BI__builtin_trap: {
+ emitTrap(loc, /*createNewBlock=*/true);
+ return RValue::get(nullptr);
+ }
+
+ case Builtin::BI__builtin_unreachable: {
+ emitUnreachable(e->getExprLoc(), /*createNewBlock=*/true);
+ return RValue::get(nullptr);
+ }
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index c18498f80e99f..43e1a8efbd25a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1780,6 +1780,20 @@ LValue CIRGenFunction::emitLoadOfReferenceLValue(Address refAddr,
pointeeBaseInfo);
}
+void CIRGenFunction::emitTrap(mlir::Location loc, bool createNewBlock) {
+ cir::TrapOp::create(builder, loc);
+ if (createNewBlock)
+ builder.createBlock(builder.getBlock()->getParent());
+}
+
+void CIRGenFunction::emitUnreachable(clang::SourceLocation loc,
+ bool createNewBlock) {
+ assert(!cir::MissingFeatures::sanitizers());
+ cir::UnreachableOp::create(builder, getLoc(loc));
+ if (createNewBlock)
+ builder.createBlock(builder.getBlock()->getParent());
+}
+
mlir::Value CIRGenFunction::createDummyValue(mlir::Location loc,
clang::QualType qt) {
mlir::Type t = convertType(qt);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 603f75078c519..0c1cb26d4f84a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1199,8 +1199,28 @@ class CIRGenFunction : public CIRGenTypeCache {
/// to conserve the high level information.
mlir::Value emitToMemory(mlir::Value value, clang::QualType ty);
+ /// Emit a trap instruction, which is used to abort the program in an abnormal
+ /// way, usually for debugging purposes.
+ /// \p createNewBlock indicates whether to create a new block for the IR
+ /// builder. Since the `cir.trap` operation is a terminator, operations that
+ /// follow a trap cannot be emitted after `cir.trap` in the same block. To
+ /// ensure these operations get emitted successfully, you need to create a new
+ /// dummy block and set the insertion point there before continuing from the
+ /// trap operation.
+ void emitTrap(mlir::Location loc, bool createNewBlock);
+
LValue emitUnaryOpLValue(const clang::UnaryOperator *e);
+ /// Emit a reached-unreachable diagnostic if \p loc is valid and runtime
+ /// checking is enabled. Otherwise, just emit an unreachable instruction.
+ /// \p createNewBlock indicates whether to create a new block for the IR
+ /// builder. Since the `cir.unreachable` operation is a terminator, operations
+ /// that follow an unreachable point cannot be emitted after `cir.unreachable`
+ /// in the same block. To ensure these operations get emitted successfully,
+ /// you need to create a dummy block and set the insertion point there before
+ /// continuing from the unreachable point.
+ void emitUnreachable(clang::SourceLocation loc, bool createNewBlock);
+
/// This method handles emission of any variable declaration
/// inside a function, including static vars etc.
void emitVarDecl(const clang::VarDecl &d);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 957a51ab334aa..ce245681e4443 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -2214,7 +2214,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecShuffleDynamicOpLowering,
CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecSplatOpLowering,
- CIRToLLVMVecTernaryOpLowering
+ CIRToLLVMVecTernaryOpLowering,
+ CIRToLLVMUnreachableOpLowering
// clang-format on
>(converter, patterns.getContext());
@@ -2270,6 +2271,13 @@ mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(
}
}
+mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
+ cir::UnreachableOp op, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(op);
+ return mlir::success();
+}
+
mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
cir::TrapOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index f339d4310ae0c..c5106cb33f452 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -402,6 +402,16 @@ class CIRToLLVMGetMemberOpLowering
mlir::ConversionPatternRewriter &) const override;
};
+class CIRToLLVMUnreachableOpLowering
+ : public mlir::OpConversionPattern<cir::UnreachableOp> {
+public:
+ using mlir::OpConversionPattern<cir::UnreachableOp>::OpConversionPattern;
+
+ mlir::LogicalResult
+ matchAndRewrite(cir::UnreachableOp op, OpAdaptor,
+ mlir::ConversionPatternRewriter &) const override;
+};
+
class CIRToLLVMTrapOpLowering : public mlir::OpConversionPattern<cir::TrapOp> {
public:
using mlir::OpConversionPattern<cir::TrapOp>::OpConversionPattern;
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp
index d9a70683a4dbc..c266f1a6d1637 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -166,3 +166,63 @@ void expect_prob(int x, int y) {
// LLVM-NEXT: %[[Y_LONG:.+]] = sext i32 %[[Y]] to i64
// LLVM-NEXT: %{{.+}} = call i64 @llvm.expect.with.probability.i64(i64 %[[X_LONG]], i64 %[[Y_LONG]], double 2.500000e-01)
// LLVM: }
+
+void unreachable() {
+ __builtin_unreachable();
+}
+
+// CIR-LABEL: @_Z11unreachablev
+// CIR: cir.unreachable
+// CIR: }
+
+// LLVM-LABEL: @_Z11unreachablev
+// LLVM: unreachable
+// LLVM: }
+
+void f1();
+void unreachable2() {
+ __builtin_unreachable();
+ f1();
+}
+
+// CIR-LABEL: @_Z12unreachable2v
+// CIR: cir.unreachable
+// CIR-NEXT: ^{{.+}}:
+// CIR-NEXT: cir.call @_Z2f1v() : () -> ()
+// CIR: }
+
+// LLVM-LABEL: @_Z12unreachable2v
+// LLVM: unreachable
+// LLVM: {{.+}}:
+// LLVM-NEXT: call void @_Z2f1v()
+// LLVM: }
+
+void trap() {
+ __builtin_trap();
+}
+
+// CIR-LABEL: @_Z4trapv
+// CIR: cir.trap
+// CIR: }
+
+// LLVM-LABEL: @_Z4trapv
+// LLVM: call void @llvm.trap()
+// LLVM: }
+
+void trap2() {
+ __builtin_trap();
+ f1();
+}
+
+// CIR-LABEL: @_Z5trap2v
+// CIR: cir.trap
+// CIR-NEXT: ^{{.+}}:
+// CIR-NEXT: cir.call @_Z2f1v() : () -> ()
+// CIR: }
+
+// LLVM-LABEL: @_Z5trap2v
+// LLVM: call void @llvm.trap()
+// LLVM-NEXT: unreachable
+// LLVM: {{.+}}:
+// LLVM-NEXT: call void @_Z2f1v()
+// LLVM: }
More information about the cfe-commits
mailing list