Author: Sirui Mu Date: 2025-08-10T12:25:45+08:00 New Revision: b2cdd80411dab7b08a7649a5043370d816dbd3f4
URL: https://github.com/llvm/llvm-project/commit/b2cdd80411dab7b08a7649a5043370d816dbd3f4 DIFF: https://github.com/llvm/llvm-project/commit/b2cdd80411dab7b08a7649a5043370d816dbd3f4.diff LOG: [CIR] Add support for __builtin_assume_aligned (#152152) This patch upstreams CIRGen and LLVM lowering support for the `__builtin_assume_aligned` builtin function. Added: Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp clang/lib/CIR/CodeGen/CIRGenFunction.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h clang/test/CIR/CodeGen/builtin_call.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 32813c1a4f43a..51cef239aeda2 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3186,6 +3186,56 @@ def CIR_AssumeOp : CIR_Op<"assume"> { }]; } +def CIR_AssumeAlignedOp : CIR_Op<"assume_aligned", [ + Pure, AllTypesMatch<["pointer", "result"]> +]> { + let summary = "Tell the optimizer that a pointer is aligned"; + let description = [{ + The `cir.assume_aligned` operation takes two or three arguments. The first + argument `pointer` gives the pointer value whose alignment is to be assumed, + and the second argument `align` is an integer attribute that gives the + assumed alignment. + + The `offset` argument is optional. If given, it represents misalignment + offset. When it's present, this operation tells the optimizer that the + pointer is always misaligned to the alignment by `offset` bytes, a.k.a. the + pointer yielded by `(char *)pointer - offset` is aligned to the specified + alignment. Note that the `offset` argument is an SSA value rather than an + attribute, which means that you could pass a dynamically determined value + as the mialignment offset. + + The result of this operation has the same value as the `pointer` argument, + but it additionally carries any alignment information indicated by this + operation. + + This operation corresponds to the `__builtin_assume_aligned` builtin + function. + + Example: + + ```mlir + // Assume that %0 is a CIR pointer value of type !cir.ptr<!s32i> + %1 = cir.assume_aligned %0 alignment 16 : !cir.ptr<!s32i> + + // With a misalignment offset of 4 bytes: + %2 = cir.const #cir.int<4> : !u64i + %3 = cir.assume_aligned %0 alignment 16 [offset %2 : !u64i] : !cir.ptr<!s32i> + ``` + }]; + + let arguments = (ins CIR_PointerType:$pointer, + I64Attr:$alignment, + Optional<CIR_IntType>:$offset); + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $pointer + `alignment` $alignment + (`[` `offset` $offset^ `:` type($offset) `]`)? + `:` qualified(type($pointer)) attr-dict + }]; +} + def CIR_AssumeSepStorageOp : CIR_Op<"assume_separate_storage", [ SameTypeOperands ]> { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 7767bf481c795..16fc6501106d8 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -129,6 +129,24 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return RValue::get(nullptr); } + case Builtin::BI__builtin_assume_aligned: { + const Expr *ptrExpr = e->getArg(0); + mlir::Value ptrValue = emitScalarExpr(ptrExpr); + mlir::Value offsetValue = + (e->getNumArgs() > 2) ? emitScalarExpr(e->getArg(2)) : nullptr; + + std::optional<llvm::APSInt> alignment = + e->getArg(1)->getIntegerConstantExpr(getContext()); + assert(alignment.has_value() && + "the second argument to __builtin_assume_aligned must be an " + "integral constant expression"); + + mlir::Value result = + emitAlignmentAssumption(ptrValue, ptrExpr, ptrExpr->getExprLoc(), + alignment->getSExtValue(), offsetValue); + return RValue::get(result); + } + case Builtin::BI__builtin_complex: { mlir::Value real = emitScalarExpr(e->getArg(0)); mlir::Value imag = emitScalarExpr(e->getArg(1)); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 86f49f0c3c297..03555a52f1252 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -933,6 +933,23 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); } +mlir::Value CIRGenFunction::emitAlignmentAssumption( + mlir::Value ptrValue, QualType ty, SourceLocation loc, + SourceLocation assumptionLoc, int64_t alignment, mlir::Value offsetValue) { + assert(!cir::MissingFeatures::sanitizers()); + return cir::AssumeAlignedOp::create(builder, getLoc(assumptionLoc), ptrValue, + alignment, offsetValue); +} + +mlir::Value CIRGenFunction::emitAlignmentAssumption( + mlir::Value ptrValue, const Expr *expr, SourceLocation assumptionLoc, + int64_t alignment, mlir::Value offsetValue) { + QualType ty = expr->getType(); + SourceLocation loc = expr->getExprLoc(); + return emitAlignmentAssumption(ptrValue, ty, loc, assumptionLoc, alignment, + offsetValue); +} + // TODO(cir): Most of this function can be shared between CIRGen // and traditional LLVM codegen void CIRGenFunction::emitVariablyModifiedType(QualType type) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 68447082a5a1f..065039ec041e0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -829,6 +829,18 @@ class CIRGenFunction : public CIRGenTypeCache { /// ---------------------- /// CIR emit functions /// ---------------------- +public: + mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, QualType ty, + SourceLocation loc, + SourceLocation assumptionLoc, + int64_t alignment, + mlir::Value offsetValue = nullptr); + + mlir::Value emitAlignmentAssumption(mlir::Value ptrValue, const Expr *expr, + SourceLocation assumptionLoc, + int64_t alignment, + mlir::Value offsetValue = nullptr); + private: void emitAndUpdateRetAlloca(clang::QualType type, mlir::Location loc, clang::CharUnits alignment); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 43a1b512a6d2c..0a4aabda1ffac 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -460,6 +460,29 @@ mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMAssumeAlignedOpLowering::matchAndRewrite( + cir::AssumeAlignedOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + SmallVector<mlir::Value, 3> opBundleArgs{adaptor.getPointer()}; + + auto alignment = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), + adaptor.getAlignmentAttr()); + opBundleArgs.push_back(alignment); + + if (mlir::Value offset = adaptor.getOffset()) + opBundleArgs.push_back(offset); + + auto cond = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), + rewriter.getI1Type(), 1); + mlir::LLVM::AssumeOp::create(rewriter, op.getLoc(), cond, "align", + opBundleArgs); + + // The llvm.assume operation does not have a result, so we need to replace + // all uses of this cir.assume_aligned operation with the input ptr itself. + rewriter.replaceOp(op, adaptor.getPointer()); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMAssumeSepStorageOpLowering::matchAndRewrite( cir::AssumeSepStorageOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -2173,6 +2196,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { patterns.add< // clang-format off CIRToLLVMAssumeOpLowering, + CIRToLLVMAssumeAlignedOpLowering, CIRToLLVMAssumeSepStorageOpLowering, CIRToLLVMBaseClassAddrOpLowering, CIRToLLVMBinOpLowering, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index c5106cb33f452..51b191af24692 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -44,6 +44,16 @@ class CIRToLLVMAssumeOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMAssumeAlignedOpLowering + : public mlir::OpConversionPattern<cir::AssumeAlignedOp> { +public: + using mlir::OpConversionPattern<cir::AssumeAlignedOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::AssumeAlignedOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMAssumeSepStorageOpLowering : public mlir::OpConversionPattern<cir::AssumeSepStorageOp> { public: diff --git a/clang/test/CIR/CodeGen/builtin_call.cpp b/clang/test/CIR/CodeGen/builtin_call.cpp index c266f1a6d1637..09be7937a4330 100644 --- a/clang/test/CIR/CodeGen/builtin_call.cpp +++ b/clang/test/CIR/CodeGen/builtin_call.cpp @@ -111,6 +111,38 @@ void assume(bool arg) { // OGCG: call void @llvm.assume(i1 %{{.+}}) // OGCG: } +void *assume_aligned(void *ptr) { + return __builtin_assume_aligned(ptr, 16); +} + +// CIR: @_Z14assume_alignedPv +// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16 : !cir.ptr<!void> +// CIR: } + +// LLVM: @_Z14assume_alignedPv +// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] +// LLVM: } + +// OGCG: @_Z14assume_alignedPv +// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16) ] +// OGCG: } + +void *assume_aligned_misalignment(void *ptr, unsigned misalignment) { + return __builtin_assume_aligned(ptr, 16, misalignment); +} + +// CIR: @_Z27assume_aligned_misalignmentPvj +// CIR: %{{.+}} = cir.assume_aligned %{{.+}} alignment 16[offset %{{.+}} : !u64i] : !cir.ptr<!void> +// CIR: } + +// LLVM: @_Z27assume_aligned_misalignmentPvj +// LLVM: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] +// LLVM: } + +// OGCG: @_Z27assume_aligned_misalignmentPvj +// OGCG: call void @llvm.assume(i1 true) [ "align"(ptr %{{.+}}, i64 16, i64 %{{.+}}) ] +// OGCG: } + void assume_separate_storage(void *p1, void *p2) { __builtin_assume_separate_storage(p1, p2); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits