mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[GuardWidening] Fix incorrect use of remove_if
I had used `std::remove_if` under the assumption that it moves the predicate matching elements to the end, but actaully the elements remaining towards the end (after the iterator returned by `std::remove_if`) are indeterminate. Fix the bug (and make the code more straightforward) by using a temporary SmallVector, and add a test case demonstrating the issue. llvm-svn: 270306
This commit is contained in:
parent
44230570f6
commit
9b7c91f0ad
@ -551,26 +551,33 @@ bool GuardWideningImpl::combineRangeChecks(
|
||||
SmallVectorImpl<GuardWideningImpl::RangeCheck> &RangeChecksOut) {
|
||||
unsigned OldCount = Checks.size();
|
||||
while (!Checks.empty()) {
|
||||
Value *Base = Checks[0].Base;
|
||||
Value *Length = Checks[0].Length;
|
||||
auto ChecksStart =
|
||||
remove_if(Checks, [&](GuardWideningImpl::RangeCheck &RC) {
|
||||
return RC.Base == Base && RC.Length == Length;
|
||||
});
|
||||
// Pick all of the range checks with a specific base and length, and try to
|
||||
// merge them.
|
||||
Value *CurrentBase = Checks.front().Base;
|
||||
Value *CurrentLength = Checks.front().Length;
|
||||
|
||||
unsigned CheckCount = std::distance(ChecksStart, Checks.end());
|
||||
assert(CheckCount != 0 && "We know we have at least one!");
|
||||
SmallVector<GuardWideningImpl::RangeCheck, 3> CurrentChecks;
|
||||
|
||||
if (CheckCount < 3) {
|
||||
RangeChecksOut.insert(RangeChecksOut.end(), ChecksStart, Checks.end());
|
||||
Checks.erase(ChecksStart, Checks.end());
|
||||
auto IsCurrentCheck = [&](GuardWideningImpl::RangeCheck &RC) {
|
||||
return RC.Base == CurrentBase && RC.Length == CurrentLength;
|
||||
};
|
||||
|
||||
std::copy_if(Checks.begin(), Checks.end(),
|
||||
std::back_inserter(CurrentChecks), IsCurrentCheck);
|
||||
Checks.erase(remove_if(Checks, IsCurrentCheck), Checks.end());
|
||||
|
||||
assert(CurrentChecks.size() != 0 && "We know we have at least one!");
|
||||
|
||||
if (CurrentChecks.size() < 3) {
|
||||
RangeChecksOut.insert(RangeChecksOut.end(), CurrentChecks.begin(),
|
||||
CurrentChecks.end());
|
||||
continue;
|
||||
}
|
||||
|
||||
// CheckCount will typically be 3 here, but so far there has been no need to
|
||||
// hard-code that fact.
|
||||
// CurrentChecks.size() will typically be 3 here, but so far there has been
|
||||
// no need to hard-code that fact.
|
||||
|
||||
std::sort(ChecksStart, Checks.end(),
|
||||
std::sort(CurrentChecks.begin(), CurrentChecks.end(),
|
||||
[&](const GuardWideningImpl::RangeCheck &LHS,
|
||||
const GuardWideningImpl::RangeCheck &RHS) {
|
||||
return LHS.Offset->getValue().slt(RHS.Offset->getValue());
|
||||
@ -578,8 +585,8 @@ bool GuardWideningImpl::combineRangeChecks(
|
||||
|
||||
// Note: std::sort should not invalidate the ChecksStart iterator.
|
||||
|
||||
ConstantInt *MinOffset = ChecksStart->Offset,
|
||||
*MaxOffset = Checks.back().Offset;
|
||||
ConstantInt *MinOffset = CurrentChecks.front().Offset,
|
||||
*MaxOffset = CurrentChecks.back().Offset;
|
||||
|
||||
unsigned BitWidth = MaxOffset->getValue().getBitWidth();
|
||||
if ((MaxOffset->getValue() - MinOffset->getValue())
|
||||
@ -593,7 +600,8 @@ bool GuardWideningImpl::combineRangeChecks(
|
||||
};
|
||||
|
||||
if (MaxDiff.isMinValue() ||
|
||||
!std::all_of(std::next(ChecksStart), Checks.end(), OffsetOK))
|
||||
!std::all_of(std::next(CurrentChecks.begin()), CurrentChecks.end(),
|
||||
OffsetOK))
|
||||
return false;
|
||||
|
||||
// We have a series of f+1 checks as:
|
||||
@ -631,12 +639,8 @@ bool GuardWideningImpl::combineRangeChecks(
|
||||
// For Chk_0 to succeed, we'd have to have k_f-k_0 (the range highlighted
|
||||
// with 'x' above) to be at least >u INT_MIN.
|
||||
|
||||
RangeChecksOut.emplace_back(Base, MinOffset, Length,
|
||||
ChecksStart->CheckInst);
|
||||
RangeChecksOut.emplace_back(Base, MaxOffset, Length,
|
||||
Checks.back().CheckInst);
|
||||
|
||||
Checks.erase(ChecksStart, Checks.end());
|
||||
RangeChecksOut.emplace_back(CurrentChecks.front());
|
||||
RangeChecksOut.emplace_back(CurrentChecks.back());
|
||||
}
|
||||
|
||||
assert(RangeChecksOut.size() <= OldCount && "We pessimized!");
|
||||
|
@ -194,4 +194,42 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define void @f_7(i32 %x, i32* %length_buf) {
|
||||
; CHECK-LABEL: @f_7(
|
||||
|
||||
; CHECK: [[COND_0:%[^ ]+]] = and i1 %chk3.b, %chk0.b
|
||||
; CHECK: [[COND_1:%[^ ]+]] = and i1 %chk0.a, [[COND_0]]
|
||||
; CHECK: [[COND_2:%[^ ]+]] = and i1 %chk3.a, [[COND_1]]
|
||||
; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ]
|
||||
|
||||
entry:
|
||||
%length_a = load volatile i32, i32* %length_buf, !range !0
|
||||
%length_b = load volatile i32, i32* %length_buf, !range !0
|
||||
%chk0.a = icmp ult i32 %x, %length_a
|
||||
%chk0.b = icmp ult i32 %x, %length_b
|
||||
%chk0 = and i1 %chk0.a, %chk0.b
|
||||
call void(i1, ...) @llvm.experimental.guard(i1 %chk0) [ "deopt"() ]
|
||||
|
||||
%x.inc1 = add i32 %x, 1
|
||||
%chk1.a = icmp ult i32 %x.inc1, %length_a
|
||||
%chk1.b = icmp ult i32 %x.inc1, %length_b
|
||||
%chk1 = and i1 %chk1.a, %chk1.b
|
||||
call void(i1, ...) @llvm.experimental.guard(i1 %chk1) [ "deopt"() ]
|
||||
|
||||
%x.inc2 = add i32 %x, 2
|
||||
%chk2.a = icmp ult i32 %x.inc2, %length_a
|
||||
%chk2.b = icmp ult i32 %x.inc2, %length_b
|
||||
%chk2 = and i1 %chk2.a, %chk2.b
|
||||
call void(i1, ...) @llvm.experimental.guard(i1 %chk2) [ "deopt"() ]
|
||||
|
||||
%x.inc3 = add i32 %x, 3
|
||||
%chk3.a = icmp ult i32 %x.inc3, %length_a
|
||||
%chk3.b = icmp ult i32 %x.inc3, %length_b
|
||||
%chk3 = and i1 %chk3.a, %chk3.b
|
||||
call void(i1, ...) @llvm.experimental.guard(i1 %chk3) [ "deopt"() ]
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
!0 = !{i32 0, i32 2147483648}
|
||||
|
Loading…
x
Reference in New Issue
Block a user