[clang] [CIR] Add support for __builtin_assume (PR #144376)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 17 08:39:59 PDT 2025
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/144376
>From 74b80387abe26da76d73b81682105228ef3dfc73 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Tue, 17 Jun 2025 23:39:34 +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 | 3 ++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 38 +++++++++++++++++++
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, 102 insertions(+)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 8dd1f0ce361d7..4655cebc82ee7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -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
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 3dc28e6f2e5bf..3d120903dea19 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -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; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 19fac00ab8736..83825f0835a1e 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"
@@ -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 {};
+}
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 322c13c8f081a..0a2226a2cc592 100644
--- a/clang/test/CIR/CodeGen/builtin_call.cpp
+++ b/clang/test/CIR/CodeGen/builtin_call.cpp
@@ -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: }
More information about the cfe-commits
mailing list