[CIR] Add CIRGen for cir.unreachable and cir.trap (#151363)

This commit is contained in:
Sirui Mu 2025-08-05 18:52:02 +08:00 committed by GitHub
parent 94d374ab6c
commit 13600c72ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 123 additions and 1 deletions

View File

@ -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,14 @@ 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

View File

@ -1939,6 +1939,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);

View File

@ -383,6 +383,7 @@ void CIRGenFunction::LexicalScope::emitImplicitReturn() {
!mayDropFunctionReturn(fd->getASTContext(), fd->getReturnType());
if (shouldEmitUnreachable) {
assert(!cir::MissingFeatures::sanitizers());
if (cgf.cgm.getCodeGenOpts().OptimizationLevel == 0)
builder.create<cir::TrapOp>(localScope->endLoc);
else

View File

@ -1223,8 +1223,28 @@ public:
/// 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);

View File

@ -2212,7 +2212,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
CIRToLLVMVecShuffleDynamicOpLowering,
CIRToLLVMVecShuffleOpLowering,
CIRToLLVMVecSplatOpLowering,
CIRToLLVMVecTernaryOpLowering
CIRToLLVMVecTernaryOpLowering,
CIRToLLVMUnreachableOpLowering
// clang-format on
>(converter, patterns.getContext());
@ -2268,6 +2269,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 {

View File

@ -402,6 +402,16 @@ public:
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;

View File

@ -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: }