@@ -977,6 +977,117 @@ static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
977977 return true ;
978978}
979979
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+
9801091bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const Function *F,
9811092 const CallExpr *Call) {
9821093 const InterpFrame *Frame = S.Current ;
@@ -1291,6 +1402,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
12911402 return false ;
12921403 break ;
12931404
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+
12941412 default :
12951413 S.FFDiag (S.Current ->getLocation (OpPC),
12961414 diag::note_invalid_subexpr_in_const_expr)
0 commit comments