@@ -977,6 +977,117 @@ static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
977
977
return true ;
978
978
}
979
979
980
+ // / __builtin_is_aligned()
981
+ // / __builtin_align_up()
982
+ // / __builtin_align_down()
983
+ // / The first parameter is either an integer or a pointer.
984
+ // / The second parameter is the requested alignment as an integer.
985
+ static bool interp__builtin_is_aligned_up_down (InterpState &S, CodePtr OpPC,
986
+ const InterpFrame *Frame,
987
+ const Function *Func,
988
+ const CallExpr *Call) {
989
+ unsigned BuiltinOp = Func->getBuiltinID ();
990
+ unsigned CallSize = callArgSize (S, Call);
991
+
992
+ PrimType AlignmentT = *S.Ctx .classify (Call->getArg (1 ));
993
+ const APSInt &Alignment = peekToAPSInt (S.Stk , AlignmentT);
994
+
995
+ if (Alignment < 0 || !Alignment.isPowerOf2 ()) {
996
+ S.FFDiag (Call, diag::note_constexpr_invalid_alignment) << Alignment;
997
+ return false ;
998
+ }
999
+ unsigned SrcWidth = S.getCtx ().getIntWidth (Call->getArg (0 )->getType ());
1000
+ APSInt MaxValue (APInt::getOneBitSet (SrcWidth, SrcWidth - 1 ));
1001
+ if (APSInt::compareValues (Alignment, MaxValue) > 0 ) {
1002
+ S.FFDiag (Call, diag::note_constexpr_alignment_too_big)
1003
+ << MaxValue << Call->getArg (0 )->getType () << Alignment;
1004
+ return false ;
1005
+ }
1006
+
1007
+ // The first parameter is either an integer or a pointer (but not a function
1008
+ // pointer).
1009
+ PrimType FirstArgT = *S.Ctx .classify (Call->getArg (0 ));
1010
+
1011
+ if (isIntegralType (FirstArgT)) {
1012
+ const APSInt &Src = peekToAPSInt (S.Stk , FirstArgT, CallSize);
1013
+ APSInt Align = Alignment.extOrTrunc (Src.getBitWidth ());
1014
+ if (BuiltinOp == Builtin::BI__builtin_align_up) {
1015
+ APSInt AlignedVal =
1016
+ APSInt ((Src + (Align - 1 )) & ~(Align - 1 ), Src.isUnsigned ());
1017
+ pushInteger (S, AlignedVal, Call->getType ());
1018
+ } else if (BuiltinOp == Builtin::BI__builtin_align_down) {
1019
+ APSInt AlignedVal = APSInt (Src & ~(Align - 1 ), Src.isUnsigned ());
1020
+ pushInteger (S, AlignedVal, Call->getType ());
1021
+ } else {
1022
+ assert (*S.Ctx .classify (Call->getType ()) == PT_Bool);
1023
+ S.Stk .push <Boolean >((Src & (Align - 1 )) == 0 );
1024
+ }
1025
+ return true ;
1026
+ }
1027
+
1028
+ assert (FirstArgT == PT_Ptr);
1029
+ const Pointer &Ptr = S.Stk .peek <Pointer>(CallSize);
1030
+
1031
+ unsigned PtrOffset = Ptr .getByteOffset ();
1032
+ PtrOffset = Ptr .getIndex ();
1033
+ CharUnits BaseAlignment =
1034
+ S.getCtx ().getDeclAlign (Ptr .getDeclDesc ()->asValueDecl ());
1035
+ CharUnits PtrAlign =
1036
+ BaseAlignment.alignmentAtOffset (CharUnits::fromQuantity (PtrOffset));
1037
+
1038
+ if (BuiltinOp == Builtin::BI__builtin_is_aligned) {
1039
+ if (PtrAlign.getQuantity () >= Alignment) {
1040
+ S.Stk .push <Boolean >(true );
1041
+ return true ;
1042
+ }
1043
+ // If the alignment is not known to be sufficient, some cases could still
1044
+ // be aligned at run time. However, if the requested alignment is less or
1045
+ // equal to the base alignment and the offset is not aligned, we know that
1046
+ // the run-time value can never be aligned.
1047
+ if (BaseAlignment.getQuantity () >= Alignment &&
1048
+ PtrAlign.getQuantity () < Alignment) {
1049
+ S.Stk .push <Boolean >(false );
1050
+ return true ;
1051
+ }
1052
+
1053
+ S.FFDiag (Call->getArg (0 ), diag::note_constexpr_alignment_compute)
1054
+ << Alignment;
1055
+ return false ;
1056
+ }
1057
+
1058
+ assert (BuiltinOp == Builtin::BI__builtin_align_down ||
1059
+ BuiltinOp == Builtin::BI__builtin_align_up);
1060
+
1061
+ // For align_up/align_down, we can return the same value if the alignment
1062
+ // is known to be greater or equal to the requested value.
1063
+ if (PtrAlign.getQuantity () >= Alignment) {
1064
+ S.Stk .push <Pointer>(Ptr );
1065
+ return true ;
1066
+ }
1067
+
1068
+ // The alignment could be greater than the minimum at run-time, so we cannot
1069
+ // infer much about the resulting pointer value. One case is possible:
1070
+ // For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we
1071
+ // can infer the correct index if the requested alignment is smaller than
1072
+ // the base alignment so we can perform the computation on the offset.
1073
+ if (BaseAlignment.getQuantity () >= Alignment) {
1074
+ assert (Alignment.getBitWidth () <= 64 &&
1075
+ " Cannot handle > 64-bit address-space" );
1076
+ uint64_t Alignment64 = Alignment.getZExtValue ();
1077
+ CharUnits NewOffset =
1078
+ CharUnits::fromQuantity (BuiltinOp == Builtin::BI__builtin_align_down
1079
+ ? llvm::alignDown (PtrOffset, Alignment64)
1080
+ : llvm::alignTo (PtrOffset, Alignment64));
1081
+
1082
+ S.Stk .push <Pointer>(Ptr .atIndex (NewOffset.getQuantity ()));
1083
+ return true ;
1084
+ }
1085
+
1086
+ // Otherwise, we cannot constant-evaluate the result.
1087
+ S.FFDiag (Call->getArg (0 ), diag::note_constexpr_alignment_adjust) << Alignment;
1088
+ return false ;
1089
+ }
1090
+
980
1091
bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const Function *F,
981
1092
const CallExpr *Call) {
982
1093
const InterpFrame *Frame = S.Current ;
@@ -1291,6 +1402,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
1291
1402
return false ;
1292
1403
break ;
1293
1404
1405
+ case Builtin::BI__builtin_is_aligned:
1406
+ case Builtin::BI__builtin_align_up:
1407
+ case Builtin::BI__builtin_align_down:
1408
+ if (!interp__builtin_is_aligned_up_down (S, OpPC, Frame, F, Call))
1409
+ return false ;
1410
+ break ;
1411
+
1294
1412
default :
1295
1413
S.FFDiag (S.Current ->getLocation (OpPC),
1296
1414
diag::note_invalid_subexpr_in_const_expr)
0 commit comments