Skip to content

Commit 23db972

Browse files
committed
[InstCombine] Fix infinite loop in min/max load/store bitcast combine (PR44835)
Fixes https://bugs.llvm.org/show_bug.cgi?id=44835. Skip the transform if it wouldn't actually do anything (apart from removing and reinserting the same instructions). Note that the test case doesn't loop on current master anymore, only on the LLVM 10 release branch. The issue is already mitigated on master due to worklist order fixes, but we should fix the root cause there as well. As a side note, we should probably assert in combineLoadToNewType() that it does not combine to the same type. Not doing this here, because this assertion would also be triggered in another place right now. Differential Revision: https://reviews.llvm.org/D74278
1 parent c8bc89a commit 23db972

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,11 @@ static bool removeBitcastsFromLoadStoreOnMinMax(InstCombiner &IC,
13201320
if (!isMinMaxWithLoads(LoadAddr, CmpLoadTy))
13211321
return false;
13221322

1323+
// Make sure the type would actually change.
1324+
// This condition can be hit with chains of bitcasts.
1325+
if (LI->getType() == CmpLoadTy)
1326+
return false;
1327+
13231328
// Make sure we're not changing the size of the load/store.
13241329
const auto &DL = IC.getDataLayout();
13251330
if (DL.getTypeStoreSizeInBits(LI->getType()) !=
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -instcombine < %s | FileCheck %s
3+
4+
; This test used to cause an infinite loop in the load/store min/max bitcast
5+
; transform.
6+
7+
define void @test(i32* %p, i32* %p2) {
8+
; CHECK-LABEL: @test(
9+
; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[P:%.*]], align 4
10+
; CHECK-NEXT: [[V2:%.*]] = load i32, i32* [[P2:%.*]], align 4
11+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[V2]], [[V]]
12+
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP]], i32 [[V2]], i32 [[V]]
13+
; CHECK-NEXT: store i32 [[TMP1]], i32* [[P]], align 4
14+
; CHECK-NEXT: ret void
15+
;
16+
%v = load i32, i32* %p, align 4
17+
%v2 = load i32, i32* %p2, align 4
18+
%cmp = icmp ult i32 %v2, %v
19+
%sel = select i1 %cmp, i32* %p2, i32* %p
20+
%p8 = bitcast i32* %p to i8*
21+
%sel8 = bitcast i32* %sel to i8*
22+
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %p8, i8* align 4 %sel8, i64 4, i1 false)
23+
ret void
24+
}
25+
26+
; Function Attrs: argmemonly nounwind willreturn
27+
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
28+
29+
attributes #0 = { argmemonly nounwind willreturn }

0 commit comments

Comments
 (0)