Skip to content

Commit 56e6c37

Browse files
artagnonpfusik
andcommitted
[HashRecognize] Fix LHS ConstantRange check for BE
The ConstantRange of the LHS of the ICmp in the Select(ICmp()) significant-bit check is not checked in the big-endian case, leading to a potential miscompile. Fix this. Co-authored-by: Piotr Fusik <[email protected]>
1 parent c9ca354 commit 56e6c37

File tree

2 files changed

+68
-31
lines changed

2 files changed

+68
-31
lines changed

llvm/lib/Analysis/HashRecognize.cpp

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class ValueEvolution {
9090
const bool ByteOrderSwapped;
9191
APInt GenPoly;
9292
StringRef ErrStr;
93+
unsigned AtIter;
9394

9495
// Compute the KnownBits of a BinaryOperator.
9596
KnownBits computeBinOp(const BinaryOperator *I);
@@ -190,43 +191,54 @@ KnownBits ValueEvolution::computeInstr(const Instruction *I) {
190191
return KnownPhis.lookup_or(P, BitWidth);
191192

192193
// Compute the KnownBits for a Select(Cmp()), forcing it to take the branch
193-
// that is predicated on the (least|most)-significant-bit check.
194+
// that is (least|most)-significant-bit-clear.
194195
CmpPredicate Pred;
195196
Value *L, *R;
196197
Instruction *TV, *FV;
197198
if (match(I, m_Select(m_ICmp(Pred, m_Value(L), m_Value(R)), m_Instruction(TV),
198199
m_Instruction(FV)))) {
199200
Visited.insert(cast<Instruction>(I->getOperand(0)));
200201

201-
// We need to check LCR against [0, 2) in the little-endian case, because
202-
// the RCR check is insufficient: it is simply [0, 1).
203-
if (!ByteOrderSwapped) {
204-
KnownBits KnownL = compute(L);
205-
unsigned ICmpBW = KnownL.getBitWidth();
206-
auto LCR = ConstantRange::fromKnownBits(KnownL, false);
207-
auto CheckLCR = ConstantRange(APInt::getZero(ICmpBW), APInt(ICmpBW, 2));
208-
if (LCR != CheckLCR) {
209-
ErrStr = "Bad LHS of significant-bit-check";
210-
return {BitWidth};
211-
}
202+
// Check that the predication is on (most|least) significant bit. We check
203+
// that the compare is `>= 0` in the big-endian case, and `== 0` in the
204+
// little-endian case (or the inverse, in which case the branches of the
205+
// compare are swapped). We check LCR against CheckLCR, which is full-set,
206+
// [0, -1), [0, -3), [0, -7), etc. depending on AtIter in the big-endian
207+
// case, and [0, 2) in the little-endian case: CheckLCR checks that we are
208+
// shifting in zero bits in every loop iteration in the big-endian case, and
209+
// the compare 0 or 1 in the little-endian case (as a value and'ed with 1 is
210+
// passed as the operand). We then check AllowedByR against CheckAllowedByR,
211+
// which is [0, smin) in the big-endian case, and [0, 1) in the
212+
// little-endian case: CheckAllowedByR checks for significant-bit-clear,
213+
// which means that we visit the bit-shift branch instead of the
214+
// bit-shift-and-xor-poly branch.
215+
KnownBits KnownL = compute(L);
216+
unsigned ICmpBW = KnownL.getBitWidth();
217+
auto LCR = ConstantRange::fromKnownBits(KnownL, false);
218+
auto CheckLCR = ConstantRange::getNonEmpty(
219+
APInt::getZero(ICmpBW), ByteOrderSwapped
220+
? -APInt::getLowBitsSet(ICmpBW, AtIter)
221+
: APInt(ICmpBW, 2));
222+
if (LCR != CheckLCR) {
223+
ErrStr = "Bad LHS of significant-bit-check";
224+
return {BitWidth};
212225
}
213226

214-
// Check that the predication is on (most|least) significant bit.
215227
KnownBits KnownR = compute(R);
216-
unsigned ICmpBW = KnownR.getBitWidth();
217228
auto RCR = ConstantRange::fromKnownBits(KnownR, false);
218-
auto AllowedR = ConstantRange::makeAllowedICmpRegion(Pred, RCR);
219-
ConstantRange CheckRCR(APInt::getZero(ICmpBW),
220-
ByteOrderSwapped ? APInt::getSignedMinValue(ICmpBW)
221-
: APInt(ICmpBW, 1));
222-
223-
// We only compute KnownBits of either TV or FV, as the other value would
224-
// just be a bit-shift as checked by isBigEndianBitShift.
225-
if (AllowedR == CheckRCR) {
229+
auto AllowedByR = ConstantRange::makeAllowedICmpRegion(Pred, RCR);
230+
ConstantRange CheckAllowedByR(
231+
APInt::getZero(ICmpBW),
232+
ByteOrderSwapped ? APInt::getSignedMinValue(ICmpBW) : APInt(ICmpBW, 1));
233+
234+
// We only compute KnownBits of either TV or FV, as the other branch would
235+
// be the bit-shift-and-xor-poly branch, as determined by the conditional
236+
// recurrence.
237+
if (AllowedByR == CheckAllowedByR) {
226238
Visited.insert(FV);
227239
return compute(TV);
228240
}
229-
if (AllowedR.inverse() == CheckRCR) {
241+
if (AllowedByR.inverse() == CheckAllowedByR) {
230242
Visited.insert(TV);
231243
return compute(FV);
232244
}
@@ -264,9 +276,11 @@ KnownBits ValueEvolution::compute(const Value *V) {
264276
}
265277

266278
bool ValueEvolution::computeEvolutions(ArrayRef<PhiStepPair> PhiEvolutions) {
267-
for (unsigned I = 0; I < TripCount; ++I)
279+
for (unsigned I = 0; I < TripCount; ++I) {
280+
AtIter = I;
268281
for (auto [Phi, Step] : PhiEvolutions)
269282
KnownPhis.emplace_or_assign(Phi, computeInstr(Step));
283+
}
270284

271285
return ErrStr.empty();
272286
}

llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ exit: ; preds = %loop
649649
define i16 @not.crc.wrong.sb.check.const(i8 %msg, i16 %checksum) {
650650
; CHECK-LABEL: 'not.crc.wrong.sb.check.const'
651651
; CHECK-NEXT: Did not find a hash algorithm
652-
; CHECK-NEXT: Reason: Bad RHS of significant-bit-check
652+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
653653
;
654654
entry:
655655
br label %loop
@@ -676,7 +676,7 @@ exit: ; preds = %loop
676676
define i16 @not.crc.wrong.sb.check.pred(i16 %crc.init) {
677677
; CHECK-LABEL: 'not.crc.wrong.sb.check.pred'
678678
; CHECK-NEXT: Did not find a hash algorithm
679-
; CHECK-NEXT: Reason: Bad RHS of significant-bit-check
679+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
680680
;
681681
entry:
682682
br label %loop
@@ -857,10 +857,10 @@ exit: ; preds = %loop
857857
ret i16 %crc.next
858858
}
859859

860-
define i16 @crc1.tc8.sb.check.endian.mismatch(i8 %msg, i16 %checksum) {
861-
; CHECK-LABEL: 'crc1.tc8.sb.check.endian.mismatch'
860+
define i16 @not.crc.sb.check.endian.mismatch(i8 %msg, i16 %checksum) {
861+
; CHECK-LABEL: 'not.crc.sb.check.endian.mismatch'
862862
; CHECK-NEXT: Did not find a hash algorithm
863-
; CHECK-NEXT: Reason: Bad RHS of significant-bit-check
863+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
864864
;
865865
entry:
866866
br label %loop
@@ -912,7 +912,7 @@ exit: ; preds = %loop
912912
define i16 @not.crc.bad.endian.swapped.sb.check(i8 %msg, i16 %checksum) {
913913
; CHECK-LABEL: 'not.crc.bad.endian.swapped.sb.check'
914914
; CHECK-NEXT: Did not find a hash algorithm
915-
; CHECK-NEXT: Reason: Found stray unvisited instructions
915+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
916916
;
917917
entry:
918918
br label %loop
@@ -1219,7 +1219,7 @@ declare void @print(i16)
12191219
define i16 @not.crc.call.sb.check(i16 %crc.init) {
12201220
; CHECK-LABEL: 'not.crc.call.sb.check'
12211221
; CHECK-NEXT: Did not find a hash algorithm
1222-
; CHECK-NEXT: Reason: Found stray unvisited instructions
1222+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
12231223
;
12241224
entry:
12251225
br label %loop
@@ -1241,3 +1241,26 @@ exit: ; preds = %loop
12411241
}
12421242

12431243
declare i16 @side.effect()
1244+
1245+
define i16 @not.crc.bad.lhs.sb.check.be(i16 %crc.init) {
1246+
; CHECK-LABEL: 'not.crc.bad.lhs.sb.check.be'
1247+
; CHECK-NEXT: Did not find a hash algorithm
1248+
; CHECK-NEXT: Reason: Bad LHS of significant-bit-check
1249+
;
1250+
entry:
1251+
br label %loop
1252+
1253+
loop: ; preds = %loop, %entry
1254+
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
1255+
%crc = phi i16 [ %crc.init, %entry ], [ %crc.next, %loop ]
1256+
%crc.shl = shl i16 %crc, 1
1257+
%crc.xor = xor i16 %crc.shl, 4129
1258+
%check.sb = icmp slt i16 %crc.shl, 0
1259+
%crc.next = select i1 %check.sb, i16 %crc.xor, i16 %crc.shl
1260+
%iv.next = add nuw nsw i32 %iv, 1
1261+
%exit.cond = icmp samesign ult i32 %iv, 7
1262+
br i1 %exit.cond, label %loop, label %exit
1263+
1264+
exit: ; preds = %loop
1265+
ret i16 %crc.next
1266+
}

0 commit comments

Comments
 (0)