Skip to content

Commit 8e157fd

Browse files
authored
[CIR] Add support for __builtin_assume (#144376)
This patch adds support for the `__builtin_assume` builtin function.
1 parent 355725a commit 8e157fd

File tree

7 files changed

+102
-0
lines changed

7 files changed

+102
-0
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,4 +2387,26 @@ def ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> {
23872387
let hasFolder = 1;
23882388
}
23892389

2390+
//===----------------------------------------------------------------------===//
2391+
// Assume Operations
2392+
//===----------------------------------------------------------------------===//
2393+
2394+
def AssumeOp : CIR_Op<"assume"> {
2395+
let summary = "Tell the optimizer that a boolean value is true";
2396+
let description = [{
2397+
The `cir.assume` operation takes a single boolean prediate as its only
2398+
argument and does not have any results. The operation tells the optimizer
2399+
that the predicate is always true.
2400+
2401+
This operation corresponds to the `__assume` and the `__builtin_assume`
2402+
builtin functions.
2403+
}];
2404+
2405+
let arguments = (ins CIR_BoolType:$predicate);
2406+
2407+
let assemblyFormat = [{
2408+
$predicate `:` type($predicate) attr-dict
2409+
}];
2410+
}
2411+
23902412
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ struct MissingFeatures {
237237
static bool lowerAggregateLoadStore() { return false; }
238238
static bool dataLayoutTypeAllocSize() { return false; }
239239
static bool asmLabelAttr() { return false; }
240+
static bool builtinCall() { return false; }
241+
static bool builtinCallF128() { return false; }
242+
static bool builtinCallMathErrno() { return false; }
240243

241244
// Missing types
242245
static bool dataMemberType() { return false; }

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "CIRGenCall.h"
15+
#include "CIRGenConstantEmitter.h"
1516
#include "CIRGenFunction.h"
1617
#include "CIRGenModule.h"
1718
#include "CIRGenValue.h"
@@ -66,6 +67,32 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
6667
return emitLibraryCall(*this, fd, e,
6768
cgm.getBuiltinLibFunction(fd, builtinID));
6869

70+
assert(!cir::MissingFeatures::builtinCallF128());
71+
72+
// If the builtin has been declared explicitly with an assembler label,
73+
// disable the specialized emitting below. Ideally we should communicate the
74+
// rename in IR, or at least avoid generating the intrinsic calls that are
75+
// likely to get lowered to the renamed library functions.
76+
unsigned builtinIDIfNoAsmLabel = fd->hasAttr<AsmLabelAttr>() ? 0 : builtinID;
77+
78+
assert(!cir::MissingFeatures::builtinCallMathErrno());
79+
assert(!cir::MissingFeatures::builtinCall());
80+
81+
switch (builtinIDIfNoAsmLabel) {
82+
default:
83+
break;
84+
85+
case Builtin::BI__assume:
86+
case Builtin::BI__builtin_assume: {
87+
if (e->getArg(0)->HasSideEffects(getContext()))
88+
return RValue::get(nullptr);
89+
90+
mlir::Value argValue = emitCheckedArgForAssume(e->getArg(0));
91+
builder.create<cir::AssumeOp>(getLoc(e->getExprLoc()), argValue);
92+
return RValue::get(nullptr);
93+
}
94+
}
95+
6996
cgm.errorNYI(e->getSourceRange(), "unimplemented builtin call");
7097
return getUndefRValue(e->getType());
7198
}
@@ -88,3 +115,14 @@ cir::FuncOp CIRGenModule::getBuiltinLibFunction(const FunctionDecl *fd,
88115
mlir::Type type = convertType(fd->getType());
89116
return getOrCreateCIRFunction(name, type, d, /*forVTable=*/false);
90117
}
118+
119+
mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) {
120+
mlir::Value argValue = evaluateExprAsBool(e);
121+
if (!sanOpts.has(SanitizerKind::Builtin))
122+
return argValue;
123+
124+
assert(!cir::MissingFeatures::sanitizers());
125+
cgm.errorNYI(e->getSourceRange(),
126+
"emitCheckedArgForAssume: sanitizers are NYI");
127+
return {};
128+
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,10 @@ class CIRGenFunction : public CIRGenTypeCache {
772772

773773
LValue emitCastLValue(const CastExpr *e);
774774

775+
/// Emits an argument for a call to a `__builtin_assume`. If the builtin
776+
/// sanitizer is enabled, a runtime check is also emitted.
777+
mlir::Value emitCheckedArgForAssume(const Expr *e);
778+
775779
LValue emitCompoundAssignmentLValue(const clang::CompoundAssignOperator *e);
776780

777781
void emitConstructorBody(FunctionArgList &args);

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,14 @@ struct ConvertCIRToLLVMPass
407407
StringRef getArgument() const override { return "cir-flat-to-llvm"; }
408408
};
409409

410+
mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
411+
cir::AssumeOp op, OpAdaptor adaptor,
412+
mlir::ConversionPatternRewriter &rewriter) const {
413+
auto cond = adaptor.getPredicate();
414+
rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(op, cond);
415+
return mlir::success();
416+
}
417+
410418
mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
411419
cir::BrCondOp brOp, OpAdaptor adaptor,
412420
mlir::ConversionPatternRewriter &rewriter) const {
@@ -1811,6 +1819,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
18111819
dl);
18121820
patterns.add<
18131821
// clang-format off
1822+
CIRToLLVMAssumeOpLowering,
18141823
CIRToLLVMBaseClassAddrOpLowering,
18151824
CIRToLLVMBinOpLowering,
18161825
CIRToLLVMBrCondOpLowering,

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr,
2929

3030
mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage);
3131

32+
class CIRToLLVMAssumeOpLowering
33+
: public mlir::OpConversionPattern<cir::AssumeOp> {
34+
public:
35+
using mlir::OpConversionPattern<cir::AssumeOp>::OpConversionPattern;
36+
37+
mlir::LogicalResult
38+
matchAndRewrite(cir::AssumeOp op, OpAdaptor,
39+
mlir::ConversionPatternRewriter &) const override;
40+
};
41+
3242
class CIRToLLVMBrCondOpLowering
3343
: public mlir::OpConversionPattern<cir::BrCondOp> {
3444
public:

clang/test/CIR/CodeGen/builtin_call.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,19 @@ void library_builtins() {
9494
// OGCG: define dso_local void @_Z16library_builtinsv()
9595
// OGCG: call i32 (ptr, ...) @printf(ptr noundef null)
9696
// OGCG: call void @abort()
97+
98+
void assume(bool arg) {
99+
__builtin_assume(arg);
100+
}
101+
102+
// CIR: cir.func @_Z6assumeb
103+
// CIR: cir.assume %{{.+}} : !cir.bool
104+
// CIR: }
105+
106+
// LLVM: define void @_Z6assumeb
107+
// LLVM: call void @llvm.assume(i1 %{{.+}})
108+
// LLVM: }
109+
110+
// OGCG: define {{.*}}void @_Z6assumeb
111+
// OGCG: call void @llvm.assume(i1 %{{.+}})
112+
// OGCG: }

0 commit comments

Comments
 (0)