[GVN] Add tests showing generation of already existent PHIs for non-local loads

When we eliminate a non-local load in a loop, we create a new PHI for the loaded value,
while there already may be the exact same PHIs in the loop.

IndVarsSimplify currently can handle this case eliminating the duplicated PHIs.

However, if the loop PHI is of type of the load and also there exists
an use of the z(s)ext'ed of it, IndVarSimplify wouldn't eliminate the duplicating PHI.
It would just replace the IV with a widened one, leaving the GVN-generated PHI as is.
This commit is contained in:
Dmitry Makogon 2021-10-29 16:25:53 +07:00
parent 9020e22a87
commit 96591a14cd
1 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,128 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -gvn -indvars -S %s | FileCheck %s
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
declare void @escape(i32* %ptr)
declare void @foo(i64 %v)
define void @non_local_load(i32* %ptr) {
; CHECK-LABEL: @non_local_load(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i32 0, i32* [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL_INC:%.*]], [[LOOP]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[VAL_INC]] = add nuw nsw i32 [[VAL]], 1
; CHECK-NEXT: store i32 [[VAL_INC]], i32* [[PTR]], align 4
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i32 [[VAL]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[EXIT:%.*]], label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
store i32 0, i32* %ptr
br label %loop
loop:
%iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
%val = load i32, i32* %ptr
%val.inc = add i32 %val, 1
store i32 %val.inc, i32* %ptr
%iv.next = add i32 %iv, 1
%loop.cond = icmp eq i32 %iv, 1000
br i1 %loop.cond, label %exit, label %loop
exit:
ret void
}
define void @non_local_load_with_iv_zext(i32* %ptr) {
; CHECK-LABEL: @non_local_load_with_iv_zext(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i32 0, i32* [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[VAL_INC:%.*]] = add i32 [[VAL]], 1
; CHECK-NEXT: store i32 [[VAL_INC]], i32* [[PTR]], align 4
; CHECK-NEXT: call void @foo(i64 [[INDVARS_IV]])
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i64 [[INDVARS_IV]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[EXIT:%.*]], label [[LOOP_LOOP_CRIT_EDGE]]
; CHECK: loop.loop_crit_edge:
; CHECK-NEXT: [[VAL_PRE]] = load i32, i32* [[PTR]], align 4
; CHECK-NEXT: br label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
store i32 0, i32* %ptr
br label %loop
loop:
%iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
%val = load i32, i32* %ptr
%val.inc = add i32 %val, 1
store i32 %val.inc, i32* %ptr
%iv.wide = zext i32 %iv to i64
call void @foo(i64 %iv.wide)
%iv.next = add i32 %iv, 1
%loop.cond = icmp eq i32 %iv, 1000
br i1 %loop.cond, label %exit, label %loop
exit:
ret void
}
define void @two_non_local_loads(i32* %ptr1) {
; CHECK-LABEL: @two_non_local_loads(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr inbounds i32, i32* [[PTR1:%.*]], i64 1
; CHECK-NEXT: store i32 0, i32* [[PTR1]], align 4
; CHECK-NEXT: store i32 0, i32* [[PTR2]], align 4
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[VAL2:%.*]] = phi i32 [ [[VAL2_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[VAL1:%.*]] = phi i32 [ [[VAL1_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[VAL1_INC:%.*]] = add i32 [[VAL1]], 1
; CHECK-NEXT: store i32 [[VAL1_INC]], i32* [[PTR1]], align 4
; CHECK-NEXT: [[VAL2_INC:%.*]] = add i32 [[VAL2]], 1
; CHECK-NEXT: store i32 [[VAL2_INC]], i32* [[PTR2]], align 4
; CHECK-NEXT: call void @foo(i64 [[INDVARS_IV]])
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp eq i64 [[INDVARS_IV]], 1000
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[EXIT:%.*]], label [[LOOP_LOOP_CRIT_EDGE]]
; CHECK: loop.loop_crit_edge:
; CHECK-NEXT: [[VAL1_PRE]] = load i32, i32* [[PTR1]], align 4
; CHECK-NEXT: [[VAL2_PRE]] = load i32, i32* [[PTR2]], align 4
; CHECK-NEXT: br label [[LOOP]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%ptr2 = getelementptr inbounds i32, i32* %ptr1, i64 1
store i32 0, i32* %ptr1
store i32 0, i32* %ptr2
br label %loop
loop:
%iv = phi i32 [ %iv.next, %loop ], [ 0, %entry ]
%val1 = load i32, i32* %ptr1
%val1.inc = add i32 %val1, 1
store i32 %val1.inc, i32* %ptr1
%val2 = load i32, i32* %ptr2
%val2.inc = add i32 %val2, 1
store i32 %val2.inc, i32* %ptr2
%iv.wide = zext i32 %iv to i64
call void @foo(i64 %iv.wide)
%iv.next = add i32 %iv, 1
%loop.cond = icmp eq i32 %iv, 1000
br i1 %loop.cond, label %exit, label %loop
exit:
ret void
}