[clang] [CIR] Add support for __builtin_assume (PR #144376)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 16 08:42:21 PDT 2025
https://github.com/Lancern created https://github.com/llvm/llvm-project/pull/144376
This patch adds support for the `__builtin_assume` builtin function.
>From 886097329c486b48ceb32ea7ea807e561ad8abdd Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Mon, 16 Jun 2025 23:38:47 +0800
Subject: [PATCH] [CIR] Add support for __builtin_assume
This patch adds support for the __builtin_assume builtin function.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 22 +++++++++++
clang/include/clang/CIR/MissingFeatures.h | 1 +
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 +++++++++++++++++++
clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 9 +++++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 +++++
clang/test/CIR/CodeGen/builtin_call.cpp | 16 ++++++++
7 files changed, 101 insertions(+)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index bd36d228578b7..60fbce646da9b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2385,4 +2385,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 function.
+ }];
+
+ let arguments = (ins CIR_BoolType:$predicate);
+
+ let assemblyFormat = [{
+ $predicate `:` type($predicate) attr-dict
+ }];
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 13ddc77835fbc..ca9eef36e0d78 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -90,6 +90,7 @@ struct MissingFeatures {
static bool opCallABIExtendArg() { return false; }
static bool opCallABIIndirectArg() { return false; }
static bool opCallWidenArg() { return false; }
+ static bool opCallBuiltin() { return false; }
static bool opCallBitcastArg() { return false; }
static bool opCallImplicitObjectSizeArgs() { return false; }
static bool opCallReturn() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index c59ac78210f81..6e4d38bd6f051 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CIRGenCall.h"
+#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenValue.h"
@@ -28,6 +29,8 @@ using namespace clang::CIRGen;
RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
const CallExpr *e,
ReturnValueSlot returnValue) {
+ const FunctionDecl *fd = gd.getDecl()->getAsFunction();
+
// See if we can constant fold this builtin. If so, don't emit it at all.
// TODO: Extend this handling to all builtin calls that we can constant-fold.
Expr::EvalResult result;
@@ -49,7 +52,43 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
}
}
+ assert(!cir::MissingFeatures::opCallBuiltin());
+
+ // 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::opCallBuiltin());
+
+ 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);
+ }
+ }
+
mlir::Location loc = getLoc(e->getExprLoc());
cgm.errorNYI(loc, "non constant foldable builtin calls");
return getUndefRValue(e->getType());
}
+
+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 {};
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index de6ef2a69faf1..6c490a72b2e93 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -772,6 +772,10 @@ class CIRGenFunction : public CIRGenTypeCache {
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);
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6a4e4e4a7df3b..a96501ab2c384 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -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,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index a809818063547..a80c66ac1abf2 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -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:
diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp
index 2706ea7f8f857..c5ad08740ea3c 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -76,3 +76,19 @@ float constant_fp_builtin_single() {
// OGCG: define {{.*}}float @_Z26constant_fp_builtin_singlev()
// OGCG: ret float 0x3FB99999A0000000
// OGCG: }
+
+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: }
More information about the cfe-commits
mailing list