Skip to content

Commit 46e1300

Browse files
committed
[CIR] Add support for __builtin_assume_aligned
1 parent 9f50224 commit 46e1300

File tree

9 files changed

+185
-0
lines changed

9 files changed

+185
-0
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,45 @@ def CIR_AssumeOp : CIR_Op<"assume"> {
31433143
}];
31443144
}
31453145

3146+
def CIR_AssumeAlignedOp : CIR_Op<"assume_aligned", [
3147+
Pure, AllTypesMatch<["pointer", "result"]>
3148+
]> {
3149+
let summary = "Tell the optimizer that a pointer is aligned";
3150+
let description = [{
3151+
The `cir.assume_aligned` operation takes two or three arguments. The first
3152+
argument `pointer` gives the pointer value whose alignment is to be assumed,
3153+
and the second argument `align` is an integer attribute that gives the
3154+
assumed alignment.
3155+
3156+
The `offset` argument is optional. If given, it represents misalignment
3157+
offset. When it's present, this operation tells the optimizer that the
3158+
pointer is always misaligned to the alignment by `offset` bytes, a.k.a. the
3159+
pointer yielded by `(char *)pointer - offset` is aligned to the specified
3160+
alignment. Note that the `offset` argument is an SSA value rather than an
3161+
attribute, which means that you could pass a dynamically determined value
3162+
as the mialignment offset.
3163+
3164+
The result of this operation has the same value as the `pointer` argument,
3165+
but it additionally carries any alignment information indicated by this
3166+
operation.
3167+
3168+
This operation corresponds to the `__builtin_assume_aligned` builtin
3169+
function.
3170+
}];
3171+
3172+
let arguments = (ins CIR_PointerType:$pointer,
3173+
I64Attr:$alignment,
3174+
Optional<CIR_IntType>:$offset);
3175+
let results = (outs CIR_PointerType:$result);
3176+
3177+
let assemblyFormat = [{
3178+
$pointer
3179+
`alignment` $alignment
3180+
(`[` `offset` $offset^ `:` type($offset) `]`)?
3181+
`:` qualified(type($pointer)) attr-dict
3182+
}];
3183+
}
3184+
31463185
def CIR_AssumeSepStorageOp : CIR_Op<"assume_separate_storage", [
31473186
SameTypeOperands
31483187
]> {

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
129129
return RValue::get(nullptr);
130130
}
131131

132+
case Builtin::BI__builtin_assume_aligned: {
133+
const Expr *ptrExpr = e->getArg(0);
134+
mlir::Value ptrValue = emitScalarExpr(ptrExpr);
135+
mlir::Value offsetValue =
136+
(e->getNumArgs() > 2) ? emitScalarExpr(e->getArg(2)) : nullptr;
137+
138+
const Expr *alignmentExpr = e->getArg(1);
139+
mlir::Attribute alignmentAttr = ConstantEmitter(*this).emitAbstract(
140+
alignmentExpr, alignmentExpr->getType());
141+
int64_t alignment = mlir::cast<cir::IntAttr>(alignmentAttr).getSInt();
142+
143+
mlir::Value result = emitAlignmentAssumption(
144+
ptrValue, ptrExpr, ptrExpr->getExprLoc(),
145+
builder.getI64IntegerAttr(alignment), offsetValue);
146+
return RValue::get(result);
147+
}
148+
132149
case Builtin::BI__builtin_complex: {
133150
mlir::Value real = emitScalarExpr(e->getArg(0));
134151
mlir::Value imag = emitScalarExpr(e->getArg(1));

clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class ConstantEmitter {
9090
/// asserting that it succeeded. This is only safe to do when the
9191
/// expression is known to be a constant expression with either a fairly
9292
/// simple type or a known simple form.
93+
mlir::Attribute emitAbstract(const Expr *e, QualType ty);
9394
mlir::Attribute emitAbstract(SourceLocation loc, const APValue &value,
9495
QualType t);
9596

@@ -100,6 +101,7 @@ class ConstantEmitter {
100101
// functions and classes.
101102

102103
mlir::Attribute tryEmitPrivateForVarInit(const VarDecl &d);
104+
mlir::TypedAttr tryEmitPrivate(const Expr *e, QualType ty);
103105

104106
mlir::Attribute tryEmitPrivate(const APValue &value, QualType destType);
105107
mlir::Attribute tryEmitPrivateForMemory(const APValue &value, QualType t);

clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,38 @@ mlir::Attribute ConstantEmitter::tryEmitPrivateForMemory(const APValue &value,
650650
return (c ? emitForMemory(c, destType) : nullptr);
651651
}
652652

653+
mlir::TypedAttr ConstantEmitter::tryEmitPrivate(const Expr *e, QualType ty) {
654+
assert(!ty->isVoidType() && "can't emit a void constant");
655+
656+
if (mlir::Attribute attr =
657+
ConstExprEmitter(*this).Visit(const_cast<Expr *>(e), ty))
658+
return mlir::cast<mlir::TypedAttr>(attr);
659+
660+
Expr::EvalResult result;
661+
662+
bool success = false;
663+
if (ty->isReferenceType())
664+
success = e->EvaluateAsLValue(result, cgm.getASTContext());
665+
else
666+
success =
667+
e->EvaluateAsRValue(result, cgm.getASTContext(), inConstantContext);
668+
669+
if (success && !result.hasSideEffects()) {
670+
mlir::Attribute attr = tryEmitPrivate(result.Val, ty);
671+
return mlir::cast<mlir::TypedAttr>(attr);
672+
}
673+
674+
return nullptr;
675+
}
676+
677+
mlir::Attribute ConstantEmitter::emitAbstract(const Expr *e, QualType ty) {
678+
AbstractStateRAII state(*this, true);
679+
auto attr = mlir::cast<mlir::Attribute>(tryEmitPrivate(e, ty));
680+
if (!attr)
681+
cgm.errorNYI(e->getExprLoc(), "emitAbstract failed, emit null constant");
682+
return attr;
683+
}
684+
653685
mlir::Attribute ConstantEmitter::emitAbstract(SourceLocation loc,
654686
const APValue &value,
655687
QualType destType) {

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,24 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType,
931931
return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs);
932932
}
933933

934+
mlir::Value CIRGenFunction::emitAlignmentAssumption(
935+
mlir::Value ptrValue, QualType ty, SourceLocation loc,
936+
SourceLocation assumptionLoc, mlir::IntegerAttr alignment,
937+
mlir::Value offsetValue) {
938+
assert(!cir::MissingFeatures::sanitizers());
939+
return cir::AssumeAlignedOp::create(builder, getLoc(assumptionLoc), ptrValue,
940+
alignment, offsetValue);
941+
}
942+
943+
mlir::Value CIRGenFunction::emitAlignmentAssumption(
944+
mlir::Value ptrValue, const Expr *expr, SourceLocation assumptionLoc,
945+
mlir::IntegerAttr alignment, mlir::Value offsetValue) {
946+
QualType ty = expr->getType();
947+
SourceLocation loc = expr->getExprLoc();
948+
return emitAlignmentAssumption(ptrValue, ty, loc, assumptionLoc, alignment,
949+
offsetValue);
950+
}
951+
934952
// TODO(cir): Most of this function can be shared between CIRGen
935953
// and traditional LLVM codegen
936954
void CIRGenFunction::emitVariablyModifiedType(QualType type) {

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,18 @@ class CIRGenFunction : public CIRGenTypeCache {
825825
/// ----------------------
826826
/// CIR emit functions
827827
/// ----------------------
828+
public:
829+
mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, QualType ty,
830+
SourceLocation loc,
831+
SourceLocation assumptionLoc,
832+
mlir::IntegerAttr alignment,
833+
mlir::Value offsetValue = nullptr);
834+
835+
mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, const Expr *expr,
836+
SourceLocation assumptionLoc,
837+
mlir::IntegerAttr alignment,
838+
mlir::Value offsetValue = nullptr);
839+
828840
private:
829841
void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc,
830842
clang::CharUnits alignment);

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,28 @@ mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
460460
return mlir::success();
461461
}
462462

463+
mlir::LogicalResult CIRToLLVMAssumeAlignedOpLowering::matchAndRewrite(
464+
cir::AssumeAlignedOp op, OpAdaptor adaptor,
465+
mlir::ConversionPatternRewriter &rewriter) const {
466+
SmallVector<mlir::Value, 3> opBundleArgs{adaptor.getPointer()};
467+
468+
auto alignment = rewriter.create<mlir::LLVM::ConstantOp>(
469+
op.getLoc(), rewriter.getI64Type(), op.getAlignment());
470+
opBundleArgs.push_back(alignment);
471+
472+
if (mlir::Value offset = adaptor.getOffset())
473+
opBundleArgs.push_back(offset);
474+
475+
auto cond = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(),
476+
rewriter.getI1Type(), 1);
477+
rewriter.create<mlir::LLVM::AssumeOp>(op.getLoc(), cond, "align",
478+
opBundleArgs);
479+
rewriter.replaceAllUsesWith(op, op.getPointer());
480+
rewriter.eraseOp(op);
481+
482+
return mlir::success();
483+
}
484+
463485
mlir::LogicalResult CIRToLLVMAssumeSepStorageOpLowering::matchAndRewrite(
464486
cir::AssumeSepStorageOp op, OpAdaptor adaptor,
465487
mlir::ConversionPatternRewriter &rewriter) const {
@@ -2168,6 +2190,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
21682190
patterns.add<
21692191
// clang-format off
21702192
CIRToLLVMAssumeOpLowering,
2193+
CIRToLLVMAssumeAlignedOpLowering,
21712194
CIRToLLVMAssumeSepStorageOpLowering,
21722195
CIRToLLVMBaseClassAddrOpLowering,
21732196
CIRToLLVMBinOpLowering,

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ class CIRToLLVMAssumeOpLowering
4444
mlir::ConversionPatternRewriter &) const override;
4545
};
4646

47+
class CIRToLLVMAssumeAlignedOpLowering
48+
: public mlir::OpConversionPattern<cir::AssumeAlignedOp> {
49+
public:
50+
using mlir::OpConversionPattern<cir::AssumeAlignedOp>::OpConversionPattern;
51+
52+
mlir::LogicalResult
53+
matchAndRewrite(cir::AssumeAlignedOp op, OpAdaptor,
54+
mlir::ConversionPatternRewriter &) const override;
55+
};
56+
4757
class CIRToLLVMAssumeSepStorageOpLowering
4858
: public mlir::OpConversionPattern<cir::AssumeSepStorageOp> {
4959
public:

clang/test/CIR/CodeGen/builtin_call.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,38 @@ void assume(bool arg) {
111111
// OGCG: call void @llvm.assume(i1 %{{.+}})
112112
// OGCG: }
113113

114+
void *assume_aligned(void *ptr) {
115+
return __builtin_assume_aligned(ptr, 16);
116+
}
117+
118+
// CIR: @_Z14assume_alignedPv
119+
// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16 : !cir.ptr<!void>
120+
// CIR: }
121+
122+
// LLVM: @_Z14assume_alignedPv
123+
// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ]
124+
// LLVM: }
125+
126+
// OGCG: @_Z14assume_alignedPv
127+
// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ]
128+
// OGCG: }
129+
130+
void *assume_aligned_misalignment(void *ptr, unsigned misalignment) {
131+
return __builtin_assume_aligned(ptr, 16, misalignment);
132+
}
133+
134+
// CIR: @_Z27assume_aligned_misalignmentPvj
135+
// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16[offset %{{.+}} : !u64i] : !cir.ptr<!void>
136+
// CIR: }
137+
138+
// LLVM: @_Z27assume_aligned_misalignmentPvj
139+
// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ]
140+
// LLVM: }
141+
142+
// OGCG: @_Z27assume_aligned_misalignmentPvj
143+
// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ]
144+
// OGCG: }
145+
114146
void assume_separate_storage(void *p1, void *p2) {
115147
__builtin_assume_separate_storage(p1, p2);
116148
}

0 commit comments

Comments
 (0)