Skip to content

Commit 80c15c4

Browse files
authored
[clang][bytecode] Implement __builtin_assume_aligned (#111968)
1 parent 7771429 commit 80c15c4

File tree

5 files changed

+98
-19
lines changed

5 files changed

+98
-19
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ static T getParam(const InterpFrame *Frame, unsigned Index) {
3838
return Frame->getParam<T>(Offset);
3939
}
4040

41-
// static APSInt getAPSIntParam(InterpStack &Stk, size_t Offset = 0) {
4241
static APSInt getAPSIntParam(const InterpFrame *Frame, unsigned Index) {
4342
APSInt R;
4443
unsigned Offset = Frame->getFunction()->getParamOffset(Index);
@@ -1162,6 +1161,71 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
11621161
return false;
11631162
}
11641163

1164+
/// __builtin_assume_aligned(Ptr, Alignment[, ExtraOffset])
1165+
static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC,
1166+
const InterpFrame *Frame,
1167+
const Function *Func,
1168+
const CallExpr *Call) {
1169+
assert(Call->getNumArgs() == 2 || Call->getNumArgs() == 3);
1170+
1171+
// Might be called with function pointers in C.
1172+
std::optional<PrimType> PtrT = S.Ctx.classify(Call->getArg(0));
1173+
if (PtrT != PT_Ptr)
1174+
return false;
1175+
1176+
unsigned ArgSize = callArgSize(S, Call);
1177+
const Pointer &Ptr = S.Stk.peek<Pointer>(ArgSize);
1178+
std::optional<APSInt> ExtraOffset;
1179+
APSInt Alignment;
1180+
if (Call->getNumArgs() == 2) {
1181+
Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)));
1182+
} else {
1183+
PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1));
1184+
PrimType ExtraOffsetT = *S.Ctx.classify(Call->getArg(2));
1185+
Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)),
1186+
align(primSize(AlignmentT)) +
1187+
align(primSize(ExtraOffsetT)));
1188+
ExtraOffset = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2)));
1189+
}
1190+
1191+
CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
1192+
1193+
// If there is a base object, then it must have the correct alignment.
1194+
if (Ptr.isBlockPointer()) {
1195+
CharUnits BaseAlignment;
1196+
if (const auto *VD = Ptr.getDeclDesc()->asValueDecl())
1197+
BaseAlignment = S.getASTContext().getDeclAlign(VD);
1198+
else if (const auto *E = Ptr.getDeclDesc()->asExpr())
1199+
BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf);
1200+
1201+
if (BaseAlignment < Align) {
1202+
S.CCEDiag(Call->getArg(0),
1203+
diag::note_constexpr_baa_insufficient_alignment)
1204+
<< 0 << BaseAlignment.getQuantity() << Align.getQuantity();
1205+
return false;
1206+
}
1207+
}
1208+
1209+
APValue AV = Ptr.toAPValue(S.getASTContext());
1210+
CharUnits AVOffset = AV.getLValueOffset();
1211+
if (ExtraOffset)
1212+
AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue());
1213+
if (AVOffset.alignTo(Align) != AVOffset) {
1214+
if (Ptr.isBlockPointer())
1215+
S.CCEDiag(Call->getArg(0),
1216+
diag::note_constexpr_baa_insufficient_alignment)
1217+
<< 1 << AVOffset.getQuantity() << Align.getQuantity();
1218+
else
1219+
S.CCEDiag(Call->getArg(0),
1220+
diag::note_constexpr_baa_value_insufficient_alignment)
1221+
<< AVOffset.getQuantity() << Align.getQuantity();
1222+
return false;
1223+
}
1224+
1225+
S.Stk.push<Pointer>(Ptr);
1226+
return true;
1227+
}
1228+
11651229
static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC,
11661230
const InterpFrame *Frame,
11671231
const Function *Func,
@@ -1905,6 +1969,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
19051969
return false;
19061970
break;
19071971

1972+
case Builtin::BI__builtin_assume_aligned:
1973+
if (!interp__builtin_assume_aligned(S, OpPC, Frame, F, Call))
1974+
return false;
1975+
break;
1976+
19081977
case clang::X86::BI__builtin_ia32_bextr_u32:
19091978
case clang::X86::BI__builtin_ia32_bextr_u64:
19101979
case clang::X86::BI__builtin_ia32_bextri_u32:

clang/lib/AST/ExprConstShared.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@
1414
#ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
1515
#define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
1616

17+
#include "clang/Basic/TypeTraits.h"
18+
1719
namespace llvm {
1820
class APFloat;
1921
}
2022
namespace clang {
2123
class QualType;
2224
class LangOptions;
25+
class ASTContext;
26+
class CharUnits;
27+
class Expr;
2328
} // namespace clang
2429
using namespace clang;
2530
/// 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,
6671
llvm::APFloat D, llvm::APFloat &ResR,
6772
llvm::APFloat &ResI);
6873

74+
CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
75+
UnaryExprOrTypeTrait ExprKind);
76+
6977
#endif

clang/lib/AST/ExprConstant.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9620,7 +9620,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
96209620
return ExprEvaluatorBaseTy::VisitCastExpr(E);
96219621
}
96229622

9623-
static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
9623+
static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T,
96249624
UnaryExprOrTypeTrait ExprKind) {
96259625
// C++ [expr.alignof]p3:
96269626
// When alignof is applied to a reference type, the result is the
@@ -9631,23 +9631,22 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
96319631
return CharUnits::One();
96329632

96339633
const bool AlignOfReturnsPreferred =
9634-
Info.Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
9634+
Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
96359635

96369636
// __alignof is defined to return the preferred alignment.
96379637
// Before 8, clang returned the preferred alignment for alignof and _Alignof
96389638
// as well.
96399639
if (ExprKind == UETT_PreferredAlignOf || AlignOfReturnsPreferred)
9640-
return Info.Ctx.toCharUnitsFromBits(
9641-
Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
9640+
return Ctx.toCharUnitsFromBits(Ctx.getPreferredTypeAlign(T.getTypePtr()));
96429641
// alignof and _Alignof are defined to return the ABI alignment.
96439642
else if (ExprKind == UETT_AlignOf)
9644-
return Info.Ctx.getTypeAlignInChars(T.getTypePtr());
9643+
return Ctx.getTypeAlignInChars(T.getTypePtr());
96459644
else
96469645
llvm_unreachable("GetAlignOfType on a non-alignment ExprKind");
96479646
}
96489647

9649-
static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
9650-
UnaryExprOrTypeTrait ExprKind) {
9648+
CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E,
9649+
UnaryExprOrTypeTrait ExprKind) {
96519650
E = E->IgnoreParens();
96529651

96539652
// The kinds of expressions that we have special-case logic here for
@@ -9657,22 +9656,22 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
96579656
// alignof decl is always accepted, even if it doesn't make sense: we default
96589657
// to 1 in those cases.
96599658
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
9660-
return Info.Ctx.getDeclAlign(DRE->getDecl(),
9661-
/*RefAsPointee*/true);
9659+
return Ctx.getDeclAlign(DRE->getDecl(),
9660+
/*RefAsPointee*/ true);
96629661

96639662
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
9664-
return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
9665-
/*RefAsPointee*/true);
9663+
return Ctx.getDeclAlign(ME->getMemberDecl(),
9664+
/*RefAsPointee*/ true);
96669665

9667-
return GetAlignOfType(Info, E->getType(), ExprKind);
9666+
return GetAlignOfType(Ctx, E->getType(), ExprKind);
96689667
}
96699668

96709669
static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) {
96719670
if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>())
96729671
return Info.Ctx.getDeclAlign(VD);
96739672
if (const auto *E = Value.Base.dyn_cast<const Expr *>())
9674-
return GetAlignOfExpr(Info, E, UETT_AlignOf);
9675-
return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf);
9673+
return GetAlignOfExpr(Info.Ctx, E, UETT_AlignOf);
9674+
return GetAlignOfType(Info.Ctx, Value.Base.getTypeInfoType(), UETT_AlignOf);
96769675
}
96779676

96789677
/// Evaluate the value of the alignment argument to __builtin_align_{up,down},
@@ -14475,11 +14474,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
1447514474
case UETT_PreferredAlignOf:
1447614475
case UETT_AlignOf: {
1447714476
if (E->isArgumentType())
14478-
return Success(GetAlignOfType(Info, E->getArgumentType(), E->getKind()),
14479-
E);
14477+
return Success(
14478+
GetAlignOfType(Info.Ctx, E->getArgumentType(), E->getKind()), E);
1448014479
else
14481-
return Success(GetAlignOfExpr(Info, E->getArgumentExpr(), E->getKind()),
14482-
E);
14480+
return Success(
14481+
GetAlignOfExpr(Info.Ctx, E->getArgumentExpr(), E->getKind()), E);
1448314482
}
1448414483

1448514484
case UETT_PtrAuthTypeDiscriminator: {

clang/test/Sema/builtin-assume-aligned.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s
22
// RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -triple i386-freebsd -verify %s
3+
// RUN: %clang_cc1 -DSIZE_T_64 -fsyntax-only -Wno-strict-prototypes -triple x86_64-linux -verify %s -fexperimental-new-constant-interpreter
4+
// RUN: %clang_cc1 -fsyntax-only -Wno-strict-prototypes -triple i386-freebsd -verify %s -fexperimental-new-constant-interpreter
35

46
// __builtin_assume_aligned's second parameter is size_t, which may be 32 bits,
57
// so test differently when size_t is 32 bits and when it is 64 bits.

clang/test/SemaCXX/builtin-assume-aligned.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -triple x86_64-linux-gnu %s -fexperimental-new-constant-interpreter
23

34
int n;
45
constexpr int *p = 0;

0 commit comments

Comments
 (0)