Skip to content

Commit 1c78d8d

Browse files
authored
[clang][bytecode] Fix shifts with an allocated RHS (#145280)
This was broken before because we ended up using a constructor that was disabled via assert(false). Use ShiftAP() if either LHS or RHS is allocated.
1 parent 529662a commit 1c78d8d

File tree

3 files changed

+52
-27
lines changed

3 files changed

+52
-27
lines changed

clang/lib/AST/ByteCode/IntegralAP.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ template <bool Signed> class IntegralAP final {
131131
if (NumBits == 0)
132132
NumBits = sizeof(T) * 8;
133133
assert(NumBits > 0);
134+
assert(APInt::getNumWords(NumBits) == 1);
134135
APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);
135-
assert(false);
136136
return IntegralAP<Signed>(Copy);
137137
}
138138

clang/lib/AST/ByteCode/Interp.h

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,7 +2713,7 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
27132713
template <class LT, class RT, ShiftDir Dir>
27142714
inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
27152715
LT *Result) {
2716-
2716+
static_assert(!needsAlloc<LT>());
27172717
const unsigned Bits = LHS.bitWidth();
27182718

27192719
// OpenCL 6.3j: shift values are effectively % word size of LHS.
@@ -2770,7 +2770,10 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
27702770
LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
27712771
LT::AsUnsigned::from(RHS, Bits), Bits, &R);
27722772
}
2773-
} else {
2773+
S.Stk.push<LT>(LT::from(R));
2774+
return true;
2775+
}
2776+
27742777
// Right shift.
27752778
if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
27762779
ComparisonCategoryResult::Greater) {
@@ -2779,51 +2782,52 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
27792782
// Do the shift on potentially signed LT, then convert to unsigned type.
27802783
LT A;
27812784
LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2782-
// LT::shiftRight(LHS, LT(RHSTemp), Bits, &A);
27832785
R = LT::AsUnsigned::from(A);
27842786
}
2785-
}
27862787

27872788
S.Stk.push<LT>(LT::from(R));
27882789
return true;
27892790
}
27902791

27912792
/// A version of DoShift that works on IntegralAP.
27922793
template <class LT, class RT, ShiftDir Dir>
2793-
inline bool DoShiftAP(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
2794-
LT *Result) {
2795-
const unsigned Bits = LHS.bitWidth();
2796-
const APSInt &LHSAP = LHS.toAPSInt();
2797-
APSInt RHSAP = RHS.toAPSInt();
2794+
inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,
2795+
APSInt RHS, LT *Result) {
2796+
const unsigned Bits = LHS.getBitWidth();
27982797

27992798
// OpenCL 6.3j: shift values are effectively % word size of LHS.
28002799
if (S.getLangOpts().OpenCL)
2801-
RHSAP &= APSInt(llvm::APInt(RHSAP.getBitWidth(),
2802-
static_cast<uint64_t>(LHSAP.getBitWidth() - 1)),
2803-
RHSAP.isUnsigned());
2800+
RHS &=
2801+
APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),
2802+
RHS.isUnsigned());
28042803

28052804
if (RHS.isNegative()) {
28062805
// During constant-folding, a negative shift is an opposite shift. Such a
28072806
// shift is not a constant expression.
28082807
const SourceInfo &Loc = S.Current->getSource(OpPC);
2809-
S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2808+
S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();
28102809
if (!S.noteUndefinedBehavior())
28112810
return false;
2812-
RHS = -RHS;
28132811
return DoShiftAP<LT, RT,
28142812
Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2815-
S, OpPC, LHS, RHS, Result);
2813+
S, OpPC, LHS, -RHS, Result);
28162814
}
28172815

2818-
if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2816+
if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),
2817+
Bits))
28192818
return false;
28202819

2820+
unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1);
28212821
if constexpr (Dir == ShiftDir::Left) {
2822-
unsigned SA = (unsigned)RHSAP.getLimitedValue(LHS.bitWidth() - 1);
2823-
Result->copy(LHSAP << SA);
2822+
if constexpr (needsAlloc<LT>())
2823+
Result->copy(LHS << SA);
2824+
else
2825+
*Result = LT(LHS << SA);
28242826
} else {
2825-
unsigned SA = (unsigned)RHSAP.getLimitedValue(LHS.bitWidth() - 1);
2826-
Result->copy(LHSAP >> SA);
2827+
if constexpr (needsAlloc<LT>())
2828+
Result->copy(LHS >> SA);
2829+
else
2830+
*Result = LT(LHS >> SA);
28272831
}
28282832

28292833
S.Stk.push<LT>(*Result);
@@ -2837,9 +2841,12 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
28372841
auto RHS = S.Stk.pop<RT>();
28382842
auto LHS = S.Stk.pop<LT>();
28392843

2840-
if constexpr (needsAlloc<LT>()) {
2841-
LT Result = S.allocAP<LT>(LHS.bitWidth());
2842-
return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
2844+
if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2845+
LT Result;
2846+
if constexpr (needsAlloc<LT>())
2847+
Result = S.allocAP<LT>(LHS.bitWidth());
2848+
return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
2849+
RHS.toAPSInt(), &Result);
28432850
} else {
28442851
LT Result;
28452852
return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
@@ -2852,9 +2859,13 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
28522859
using RT = typename PrimConv<NameR>::T;
28532860
auto RHS = S.Stk.pop<RT>();
28542861
auto LHS = S.Stk.pop<LT>();
2855-
if constexpr (needsAlloc<LT>()) {
2856-
LT Result = S.allocAP<LT>(LHS.bitWidth());
2857-
return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
2862+
2863+
if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2864+
LT Result;
2865+
if constexpr (needsAlloc<LT>())
2866+
Result = S.allocAP<LT>(LHS.bitWidth());
2867+
return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
2868+
RHS.toAPSInt(), &Result);
28582869
} else {
28592870
LT Result;
28602871
return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);

clang/test/AST/ByteCode/intap.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,18 @@ namespace IncDec {
273273
#endif
274274
}
275275

276+
#if __cplusplus >= 201402L
277+
const __int128_t a = ( (__int128_t)1 << 64 );
278+
const _BitInt(72) b = ( 1 << 72 ); // both-warning {{shift count >= width of type}}
279+
constexpr int shifts() { // both-error {{never produces a constant expression}}
280+
(void)(2 >> a); // both-warning {{shift count >= width of type}} \
281+
// both-note {{shift count 18446744073709551616 >= width of type 'int' (32 bits)}}
282+
(void)(2 >> b); // ref-warning {{shift count is negative}}
283+
(void)(2 << a); // both-warning {{shift count >= width of type}}
284+
(void)(2 << b); // ref-warning {{shift count is negative}}
285+
return 1;
286+
}
287+
#endif
288+
289+
276290
#endif

0 commit comments

Comments
 (0)