Skip to content

Commit d517c14

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

File tree

7 files changed

+151
-0
lines changed

7 files changed

+151
-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: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,24 @@ 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+
std::optional<llvm::APSInt> alignment =
139+
e->getArg(1)->getIntegerConstantExpr(getContext());
140+
assert(alignment.has_value() &&
141+
"the second argument to __builtin_assume_aligned must be an "
142+
"integral constant expression");
143+
144+
mlir::Value result =
145+
emitAlignmentAssumption(ptrValue, ptrExpr, ptrExpr->getExprLoc(),
146+
alignment->getSExtValue(), offsetValue);
147+
return RValue::get(result);
148+
}
149+
132150
case Builtin::BI__builtin_complex: {
133151
mlir::Value real = emitScalarExpr(e->getArg(0));
134152
mlir::Value imag = emitScalarExpr(e->getArg(1));

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,23 @@ 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, int64_t alignment, mlir::Value offsetValue) {
937+
assert(!cir::MissingFeatures::sanitizers());
938+
return cir::AssumeAlignedOp::create(builder, getLoc(assumptionLoc), ptrValue,
939+
alignment, offsetValue);
940+
}
941+
942+
mlir::Value CIRGenFunction::emitAlignmentAssumption(
943+
mlir::Value ptrValue, const Expr *expr, SourceLocation assumptionLoc,
944+
int64_t alignment, mlir::Value offsetValue) {
945+
QualType ty = expr->getType();
946+
SourceLocation loc = expr->getExprLoc();
947+
return emitAlignmentAssumption(ptrValue, ty, loc, assumptionLoc, alignment,
948+
offsetValue);
949+
}
950+
934951
// TODO(cir): Most of this function can be shared between CIRGen
935952
// and traditional LLVM codegen
936953
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+
int64_t alignment,
833+
mlir::Value offsetValue = nullptr);
834+
835+
mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, const Expr *expr,
836+
SourceLocation assumptionLoc,
837+
int64_t 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 = mlir::LLVM::ConstantOp::create(
469+
rewriter, op.getLoc(), rewriter.getI64Type(), adaptor.getAlignment());
470+
opBundleArgs.push_back(alignment);
471+
472+
if (mlir::Value offset = adaptor.getOffset())
473+
opBundleArgs.push_back(offset);
474+
475+
auto cond = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
476+
rewriter.getI1Type(), 1);
477+
mlir::LLVM::AssumeOp::create(rewriter, 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)