Skip to content

Commit 48caa07

Browse files
authored
[LAA] Analyze pointers forked by a phi (#65834)
Given a function like the following: https://godbolt.org/z/T9c99fr88 ```c 1161_noReadWrite(int *Preds) { for (int i = 0; i < LEN_1D-1; ++i) { if (Preds[i] != 0) b[i] = c[i] + 1; else a[i] = i * i; } } ``` LLVM will optimize the IR to a single store by a phi instruction: ```llvm %1 = load ptr, ptr @A, align 64 %2 = load ptr, ptr @b, align 64 ... for.inc: %.sink = phi ptr [ %1, %if.then ], [ %2, %if.else ] %add.sink = phi double [ %add, %if.then ], [ %conv8, %if.else ] %arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv store double %add.sink, ptr %arrayidx7, align 8 ``` LAA is currently unable to analyze such IR, since ScalarEvolution will return a SCEVUnknown for the forked pointer operand of the store. This patch adds initial optional support for analyzing both possibilities for the pointer and allowing LAA to generate runtime checks for the bounds if required, refers to D108699, but here address the phi node. Fixes #64888 Reviewed By: huntergr-arm, fhahn Differential Revision: https://reviews.llvm.org/D158965
1 parent 542f91f commit 48caa07

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,22 @@ static void findForkedSCEVs(
942942
ScevList.emplace_back(Scev, !isGuaranteedNotToBeUndefOrPoison(Ptr));
943943
break;
944944
}
945+
case Instruction::PHI: {
946+
SmallVector<PointerIntPair<const SCEV *, 1, bool>, 2> ChildScevs;
947+
// A phi means we've found a forked pointer, but we currently only
948+
// support a single phi per pointer so if there's another behind this
949+
// then we just bail out and return the generic SCEV.
950+
if (I->getNumOperands() == 2) {
951+
findForkedSCEVs(SE, L, I->getOperand(0), ChildScevs, Depth);
952+
findForkedSCEVs(SE, L, I->getOperand(1), ChildScevs, Depth);
953+
}
954+
if (ChildScevs.size() == 2) {
955+
ScevList.push_back(ChildScevs[0]);
956+
ScevList.push_back(ChildScevs[1]);
957+
} else
958+
ScevList.emplace_back(Scev, !isGuaranteedNotToBeUndefOrPoison(Ptr));
959+
break;
960+
}
945961
case Instruction::Add:
946962
case Instruction::Sub: {
947963
SmallVector<PointerIntPair<const SCEV *, 1, bool>> LScevs;

llvm/test/Analysis/LoopAccessAnalysis/forked-pointers.ll

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,3 +936,126 @@ for.body:
936936
exit:
937937
ret void
938938
}
939+
940+
define void @forked_ptrs_with_different_base(ptr nocapture readonly %Preds, ptr nocapture %a, ptr nocapture %b, ptr nocapture readonly %c) {
941+
; CHECK: for.body:
942+
; CHECK-NEXT: Memory dependences are safe with run-time checks
943+
; CHECK-NEXT: Dependences:
944+
; CHECK-NEXT: Run-time memory checks:
945+
; CHECK-NEXT: Check 0:
946+
; CHECK-NEXT: Comparing group ([[G1:.+]]):
947+
; CHECK-NEXT: %arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
948+
; CHECK-NEXT: Against group ([[G2:.+]]):
949+
; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
950+
; CHECK-NEXT: Check 1:
951+
; CHECK-NEXT: Comparing group ([[G1]]):
952+
; CHECK-NEXT: %arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
953+
; CHECK-NEXT: Against group ([[G4:.+]]):
954+
; CHECK-NEXT: %arrayidx5 = getelementptr inbounds double, ptr %0, i64 %indvars.iv
955+
; CHECK-NEXT: Check 2:
956+
; CHECK-NEXT: Comparing group ([[G3:.+]]):
957+
; CHECK-NEXT: %arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
958+
; CHECK-NEXT: Against group ([[G2]]):
959+
; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
960+
; CHECK-NEXT: Check 3:
961+
; CHECK-NEXT: Comparing group ([[G3]]):
962+
; CHECK-NEXT: %arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
963+
; CHECK-NEXT: Against group ([[G4]]):
964+
; CHECK-NEXT: %arrayidx5 = getelementptr inbounds double, ptr %0, i64 %indvars.iv
965+
; CHECK-NEXT: Grouped accesses:
966+
; CHECK-NEXT: Group [[G1]]:
967+
; CHECK-NEXT: (Low: %1 High: (63992 + %1))
968+
; CHECK-NEXT: Member: {%1,+,8}<nw><%for.body>
969+
; CHECK-NEXT: Group [[G3]]:
970+
; CHECK-NEXT: (Low: %2 High: (63992 + %2))
971+
; CHECK-NEXT: Member: {%2,+,8}<nw><%for.body>
972+
; CHECK-NEXT: Group [[G2]]:
973+
; CHECK-NEXT: (Low: %Preds High: (31996 + %Preds))
974+
; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body>
975+
; CHECK-NEXT: Group [[G4]]:
976+
; CHECK-NEXT: (Low: %0 High: (63992 + %0))
977+
; CHECK-NEXT: Member: {%0,+,8}<nw><%for.body>
978+
; CHECK-EMPTY:
979+
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
980+
entry:
981+
%0 = load ptr, ptr %c, align 64
982+
%1 = load ptr, ptr %a, align 64
983+
%2 = load ptr, ptr %b, align 64
984+
br label %for.body
985+
986+
for.cond.cleanup: ; preds = %for.inc
987+
ret void
988+
989+
for.body: ; preds = %entry, %for.inc
990+
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
991+
%arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
992+
%3 = load i32, ptr %arrayidx, align 4
993+
%cmp2.not = icmp eq i32 %3, 0
994+
br i1 %cmp2.not, label %if.else, label %if.then
995+
996+
if.then: ; preds = %for.body
997+
%arrayidx5 = getelementptr inbounds double, ptr %0, i64 %indvars.iv
998+
%4 = load double, ptr %arrayidx5, align 8
999+
%add = fadd fast double %4, 1.000000e+00
1000+
br label %for.inc
1001+
1002+
if.else: ; preds = %for.body
1003+
%5 = mul nuw nsw i64 %indvars.iv, %indvars.iv
1004+
%6 = trunc i64 %5 to i32
1005+
%conv8 = sitofp i32 %6 to double
1006+
br label %for.inc
1007+
1008+
for.inc: ; preds = %if.then, %if.else
1009+
%.sink = phi ptr [ %1, %if.then ], [ %2, %if.else ]
1010+
%add.sink = phi double [ %add, %if.then ], [ %conv8, %if.else ]
1011+
%arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
1012+
store double %add.sink, ptr %arrayidx7, align 8
1013+
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
1014+
%exitcond.not = icmp eq i64 %indvars.iv.next, 7999
1015+
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
1016+
}
1017+
1018+
; Negative test: the operator number of PhiNode is not 2.
1019+
define void @forked_ptrs_with_different_base3(ptr nocapture readonly %Preds, ptr nocapture %a, ptr nocapture %b, ptr nocapture readonly %c) {
1020+
; CHECK: for.body:
1021+
; CHECK-NEXT: Report: cannot identify array bounds
1022+
; CHECK-NEXT: Dependences:
1023+
; CHECK-NEXT: Run-time memory checks:
1024+
; CHECK-NEXT: Grouped accesses:
1025+
; CHECK-EMPTY:
1026+
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
1027+
entry:
1028+
%ld.c = load ptr, ptr %c, align 64
1029+
%ld.a = load ptr, ptr %a, align 64
1030+
%ld.b = load ptr, ptr %b, align 64
1031+
br label %for.body
1032+
1033+
for.body: ; preds = %entry, %for.inc
1034+
%indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.inc ]
1035+
%arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
1036+
%ld.preds = load i32, ptr %arrayidx, align 4
1037+
switch i32 %ld.preds, label %if.else [
1038+
i32 0, label %if.br0
1039+
i32 1, label %if.br1
1040+
]
1041+
1042+
if.br0: ; preds = %for.body
1043+
br label %for.inc
1044+
1045+
if.br1: ; preds = %for.body
1046+
br label %for.inc
1047+
1048+
if.else: ; preds = %for.body
1049+
br label %for.inc
1050+
1051+
for.inc: ; preds = %if.br1, %if.br0
1052+
%.sink = phi ptr [ %ld.a, %if.br0 ], [ %ld.b, %if.br1 ], [ %ld.c, %if.else ]
1053+
%arrayidx7 = getelementptr inbounds double, ptr %.sink, i64 %indvars.iv
1054+
store double 1.000000e+00, ptr %arrayidx7, align 8
1055+
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
1056+
%exitcond.not = icmp eq i64 %indvars.iv.next, 7999
1057+
br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
1058+
1059+
for.cond.cleanup: ; preds = %for.inc
1060+
ret void
1061+
}

0 commit comments

Comments
 (0)