[clang] [clang][bytecode] Implement __builtin_assume_aligned (PR #111968)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 02:13:20 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/111968.diff
5 Files Affected:
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+70-1)
- (modified) clang/lib/AST/ExprConstShared.h (+8)
- (modified) clang/lib/AST/ExprConstant.cpp (+17-18)
- (modified) clang/test/Sema/builtin-assume-aligned.c (+2)
- (modified) clang/test/SemaCXX/builtin-assume-aligned.cpp (+1)
``````````diff
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 1765193f5bebbc..27ba3a3654faf3 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -38,7 +38,6 @@ static T getParam(const InterpFrame *Frame, unsigned Index) {
return Frame->getParam<T>(Offset);
}
-// static APSInt getAPSIntParam(InterpStack &Stk, size_t Offset = 0) {
static APSInt getAPSIntParam(const InterpFrame *Frame, unsigned Index) {
APSInt R;
unsigned Offset = Frame->getFunction()->getParamOffset(Index);
@@ -1162,6 +1161,71 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
return false;
}
+/// __builtin_assume_aligned(Ptr, Alignment[, ExtraOffset])
+static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame,
+ const Function *Func,
+ const CallExpr *Call) {
+ assert(Call->getNumArgs() == 2 || Call->getNumArgs() == 3);
+
+ // Might be called with function pointers in C.
+ std::optional<PrimType> PtrT = S.Ctx.classify(Call->getArg(0));
+ if (PtrT != PT_Ptr)
+ return false;
+
+ unsigned ArgSize = callArgSize(S, Call);
+ const Pointer &Ptr = S.Stk.peek<Pointer>(ArgSize);
+ std::optional<APSInt> ExtraOffset;
+ APSInt Alignment;
+ if (Call->getNumArgs() == 2) {
+ Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)));
+ } else {
+ PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1));
+ PrimType ExtraOffsetT = *S.Ctx.classify(Call->getArg(2));
+ Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)),
+ align(primSize(AlignmentT)) +
+ align(primSize(ExtraOffsetT)));
+ ExtraOffset = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2)));
+ }
+
+ CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
+
+ // If there is a base object, then it must have the correct alignment.
+ if (Ptr.isBlockPointer()) {
+ CharUnits BaseAlignment;
+ if (const auto *VD = Ptr.getDeclDesc()->asValueDecl())
+ BaseAlignment = S.getASTContext().getDeclAlign(VD);
+ else if (const auto *E = Ptr.getDeclDesc()->asExpr())
+ BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf);
+
+ if (BaseAlignment < Align) {
+ S.CCEDiag(Call->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment)
+ << 0 << BaseAlignment.getQuantity() << Align.getQuantity();
+ return false;
+ }
+ }
+
+ APValue AV = Ptr.toAPValue(S.getASTContext());
+ CharUnits AVOffset = AV.getLValueOffset();
+ if (ExtraOffset)
+ AVOffset += CharUnits::fromQuantity(-ExtraOffset->getZExtValue());
+ if (AVOffset.alignTo(Align) != AVOffset) {
+ if (Ptr.isBlockPointer())
+ S.CCEDiag(Call->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment)
+ << 1 << AVOffset.getQuantity() << Align.getQuantity();
+ else
+ S.CCEDiag(Call->getArg(0),
+ diag::note_constexpr_baa_value_insufficient_alignment)
+ << AVOffset.getQuantity() << Align.getQuantity();
+ return false;
+ }
+
+ S.Stk.push<Pointer>(Ptr);
+ return true;
+}
+
static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
@@ -1905,6 +1969,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;
+ case Builtin::BI__builtin_assume_aligned:
+ if (!interp__builtin_assume_aligned(S, OpPC, Frame, F, Call))
+ return false;
+ break;
+
case clang::X86::BI__builtin_ia32_bextr_u32:
case clang::X86::BI__builtin_ia32_bextr_u64:
case clang::X86::BI__builtin_ia32_bextri_u32:
diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h
index efe8ee986d29b3..401ae629c86bfd 100644
--- a/clang/lib/AST/ExprConstShared.h
+++ b/clang/lib/AST/ExprConstShared.h
@@ -14,12 +14,17 @@
#ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
#define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
+#include "clang/Basic/TypeTraits.h"
+
namespace llvm {
class APFloat;
}
namespace clang {
class QualType;
class LangOptions;
+class ASTContext;
+class CharUnits;
+class Expr;
} // namespace clang
using namespace clang;
/// Values returned by __builtin_classify_type, chosen to match the values
@@ -66,4 +71,7 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C,
llvm::APFloat D, llvm::APFloat &ResR,
llvm::APFloat &ResI);
+CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
+ UnaryExprOrTypeTrait ExprKind);
+
#endif
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4d5af96093cfeb..1d607bd5a502d0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9620,7 +9620,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
-static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
+static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T,
UnaryExprOrTypeTrait ExprKind) {
// C++ [expr.alignof]p3:
// When alignof is applied to a reference type, the result is the
@@ -9631,23 +9631,22 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
return CharUnits::One();
const bool AlignOfReturnsPreferred =
- Info.Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
+ Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
// __alignof is defined to return the preferred alignment.
// Before 8, clang returned the preferred alignment for alignof and _Alignof
// as well.
if (ExprKind == UETT_PreferredAlignOf || AlignOfReturnsPreferred)
- return Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
+ return Ctx.toCharUnitsFromBits(Ctx.getPreferredTypeAlign(T.getTypePtr()));
// alignof and _Alignof are defined to return the ABI alignment.
else if (ExprKind == UETT_AlignOf)
- return Info.Ctx.getTypeAlignInChars(T.getTypePtr());
+ return Ctx.getTypeAlignInChars(T.getTypePtr());
else
llvm_unreachable("GetAlignOfType on a non-alignment ExprKind");
}
-static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
- UnaryExprOrTypeTrait ExprKind) {
+CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
+ UnaryExprOrTypeTrait ExprKind) {
E = E->IgnoreParens();
// The kinds of expressions that we have special-case logic here for
@@ -9657,22 +9656,22 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlign(DRE->getDecl(),
- /*RefAsPointee*/true);
+ return Ctx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/ true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
- /*RefAsPointee*/true);
+ return Ctx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/ true);
- return GetAlignOfType(Info, E->getType(), ExprKind);
+ return GetAlignOfType(Ctx, E->getType(), ExprKind);
}
static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {
if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>())
return Info.Ctx.getDeclAlign(VD);
if (const auto *E = Value.Base.dyn_cast<const Expr *>())
- return GetAlignOfExpr(Info, E, UETT_AlignOf);
- return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf);
+ return GetAlignOfExpr(Info.Ctx, E, UETT_AlignOf);
+ return GetAlignOfType(Info.Ctx, Value.Base.getTypeInfoType(), UETT_AlignOf);
}
/// Evaluate the value of the alignment argument to __builtin_align_{up,down},
@@ -14478,11 +14477,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
case UETT_PreferredAlignOf:
case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(Info, E->getArgumentType(), E->getKind()),
- E);
+ return Success(
+ GetAlignOfType(Info.Ctx, E->getArgumentType(), E->getKind()), E);
else
- return Success(GetAlignOfExpr(Info, E->getArgumentExpr(), E->getKind()),
- E);
+ return Success(
+ GetAlignOfExpr(Info.Ctx, E->getArgumentExpr(), E->getKind()), E);
}
case UETT_PtrAuthTypeDiscriminator: {
diff --git a/clang/test/Sema/builtin-assume-aligned.c b/clang/test/Sema/builtin-assume-aligned.c
index c2e4f9d659dd4d..33e85578451529 100644
--- a/clang/test/Sema/builtin-assume-aligned.c
+++ b/clang/test/Sema/builtin-assume-aligned.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -triple i386-freebsd -verify %s
+// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -triple i386-freebsd -verify %s -fexperimental-new-constant-interpreter
// __builtin_assume_aligned's second parameter is size_t, which may be 32 bits,
// so test differently when size_t is 32 bits and when it is 64 bits.
diff --git a/clang/test/SemaCXX/builtin-assume-aligned.cpp b/clang/test/SemaCXX/builtin-assume-aligned.cpp
index 48bd8414fc50a1..85a7faee916181 100644
--- a/clang/test/SemaCXX/builtin-assume-aligned.cpp
+++ b/clang/test/SemaCXX/builtin-assume-aligned.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s -fexperimental-new-constant-interpreter
int n;
constexpr int *p = 0;
``````````
</details>
https://github.com/llvm/llvm-project/pull/111968
More information about the cfe-commits
mailing list