[CIR] Add support for __builtin_assume (#144376)

This patch adds support for the `__builtin_assume` builtin function.
This commit is contained in:
Sirui Mu
2025-06-18 17:10:29 +08:00
committed by GitHub
parent 355725a25e
commit 8e157fdbb7
7 changed files with 102 additions and 0 deletions

View File

@@ -2387,4 +2387,26 @@ def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> {
let hasFolder = 1;
}
//===----------------------------------------------------------------------===//
// Assume Operations
//===----------------------------------------------------------------------===//
def AssumeOp : CIR_Op<"assume"> {
let summary = "Tell the optimizer that a boolean value is true";
let description = [{
The `cir.assume` operation takes a single boolean prediate as its only
argument and does not have any results. The operation tells the optimizer
that the predicate is always true.
This operation corresponds to the `__assume` and the `__builtin_assume`
builtin functions.
}];
let arguments = (ins CIR_BoolType:$predicate);
let assemblyFormat = [{
$predicate `:` type($predicate) attr-dict
}];
}
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD

View File

@@ -237,6 +237,9 @@ struct MissingFeatures {
static bool lowerAggregateLoadStore() { return false; }
static bool dataLayoutTypeAllocSize() { return false; }
static bool asmLabelAttr() { return false; }
static bool builtinCall() { return false; }
static bool builtinCallF128() { return false; }
static bool builtinCallMathErrno() { return false; }
// Missing types
static bool dataMemberType() { return false; }

View File

@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CIRGenCall.h"
#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenValue.h"
@@ -66,6 +67,32 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
return emitLibraryCall(*this, fd, e,
cgm.getBuiltinLibFunction(fd, builtinID));
assert(!cir::MissingFeatures::builtinCallF128());
// If the builtin has been declared explicitly with an assembler label,
// disable the specialized emitting below. Ideally we should communicate the
// rename in IR, or at least avoid generating the intrinsic calls that are
// likely to get lowered to the renamed library functions.
unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID;
assert(!cir::MissingFeatures::builtinCallMathErrno());
assert(!cir::MissingFeatures::builtinCall());
switch (builtinIDIfNoAsmLabel) {
default:
break;
case Builtin::BI__assume:
case Builtin::BI__builtin_assume: {
if (e->getArg(0)->HasSideEffects(getContext()))
return RValue::get(nullptr);
mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0));
builder.create<cir::AssumeOp>(getLoc(e->getExprLoc()), argValue);
return RValue::get(nullptr);
}
}
cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call");
return getUndefRValue(e->getType());
}
@@ -88,3 +115,14 @@ cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,
mlir::Type type = convertType(fd->getType());
return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false);
}
mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) {
mlir::Value argValue = evaluateExprAsBool(e);
if (!sanOpts.has(SanitizerKind::Builtin))
return argValue;
assert(!cir::MissingFeatures::sanitizers());
cgm.errorNYI(e->getSourceRange(),
"emitCheckedArgForAssume: sanitizers are NYI");
return {};
}

View File

@@ -772,6 +772,10 @@ public:
LValue emitCastLValue(const CastExpr *e);
/// Emits an argument for a call to a `__builtin_assume`. If the builtin
/// sanitizer is enabled, a runtime check is also emitted.
mlir::Value emitCheckedArgForAssume(const Expr *e);
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);
void emitConstructorBody(FunctionArgList &args);

View File

@@ -407,6 +407,14 @@ struct ConvertCIRToLLVMPass
StringRef getArgument() const override { return "cir-flat-to-llvm"; }
};
mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
cir::AssumeOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
auto cond = adaptor.getPredicate();
rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(op, cond);
return mlir::success();
}
mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
cir::BrCondOp brOp, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1811,6 +1819,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
dl);
patterns.add<
// clang-format off
CIRToLLVMAssumeOpLowering,
CIRToLLVMBaseClassAddrOpLowering,
CIRToLLVMBinOpLowering,
CIRToLLVMBrCondOpLowering,

View File

@@ -29,6 +29,16 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr,
mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
class CIRToLLVMAssumeOpLowering
: public mlir::OpConversionPattern<cir::AssumeOp> {
public:
using mlir::OpConversionPattern<cir::AssumeOp>::OpConversionPattern;
mlir::LogicalResult
matchAndRewrite(cir::AssumeOp op, OpAdaptor,
mlir::ConversionPatternRewriter &) const override;
};
class CIRToLLVMBrCondOpLowering
: public mlir::OpConversionPattern<cir::BrCondOp> {
public:

View File

@@ -94,3 +94,19 @@ void library_builtins() {
// OGCG: define dso_local void @_Z16library_builtinsv()
// OGCG: call i32 (ptr, ...) @printf(ptr noundef null)
// OGCG: call void @abort()
void assume(bool arg) {
__builtin_assume(arg);
}
// CIR: cir.func @_Z6assumeb
// CIR: cir.assume %{{.+}} : !cir.bool
// CIR: }
// LLVM: define void @_Z6assumeb
// LLVM: call void @llvm.assume(i1 %{{.+}})
// LLVM: }
// OGCG: define {{.*}}void @_Z6assumeb
// OGCG: call void @llvm.assume(i1 %{{.+}})
// OGCG: }