Represent PHIs by their incoming values instead of an opaque value of themselves. This allows ForwardOpTree to "look through" the PHIs and forward the incoming values since forwardings PHIs is currently not supported. This is particularly useful to cope with PHIs inserted by GVN LoadPRE. The incoming values all resolve to a load from a single array element which then can be forwarded. It should in theory also reduce spurious conflicts in value mapping (DeLICM), but I have not yet found a profitable case yet, so it is not included here. To avoid transitive closure and potentially necessary overapproximations of those, PHIs that may reference themselves are excluded from normalization and keep their opaque self-representation. Differential Revision: https://reviews.llvm.org/D39333 llvm-svn: 317008
83 lines
2.6 KiB
LLVM
83 lines
2.6 KiB
LLVM
; RUN: opt %loadPolly -polly-optree-normalize-phi=true -polly-optree -analyze < %s | FileCheck %s -match-full-lines
|
|
;
|
|
; Rematerialize a load.
|
|
;
|
|
; for (int j = 0; j < n; j += 1) {
|
|
; bodyA:
|
|
; double val = B[j];
|
|
;
|
|
; bodyB:
|
|
; double phi = val;
|
|
;
|
|
; bodyC:
|
|
; A[j] = phi;
|
|
; }
|
|
;
|
|
define void @func(i32 %n, double* noalias nonnull %A, double* noalias nonnull %B) {
|
|
entry:
|
|
br label %for
|
|
|
|
for:
|
|
%j = phi i32 [0, %entry], [%j.inc, %inc]
|
|
%j.cmp = icmp slt i32 %j, %n
|
|
br i1 %j.cmp, label %bodyA, label %exit
|
|
|
|
bodyA:
|
|
%B_idx = getelementptr inbounds double, double* %B, i32 %j
|
|
%val = load double, double* %B_idx
|
|
br label %bodyB
|
|
|
|
bodyB:
|
|
%phi = phi double [%val, %bodyA]
|
|
br label %bodyC
|
|
|
|
bodyC:
|
|
%A_idx = getelementptr inbounds double, double* %A, i32 %j
|
|
store double %phi, double* %A_idx
|
|
br label %inc
|
|
|
|
inc:
|
|
%j.inc = add nuw nsw i32 %j, 1
|
|
br label %for
|
|
|
|
exit:
|
|
br label %return
|
|
|
|
return:
|
|
ret void
|
|
}
|
|
|
|
|
|
; CHECK: Statistics {
|
|
; CHECK: Reloads: 2
|
|
; CHECK: }
|
|
|
|
; CHECK-NEXT: After statements {
|
|
; CHECK-NEXT: Stmt_bodyA
|
|
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_B[i0] };
|
|
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyA[i0] -> MemRef_phi__phi[] };
|
|
; CHECK-NEXT: Instructions {
|
|
; CHECK-NEXT: %val = load double, double* %B_idx
|
|
; CHECK-NEXT: }
|
|
; CHECK-NEXT: Stmt_bodyB
|
|
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_phi__phi[] };
|
|
; CHECK-NEXT: new: [n] -> { Stmt_bodyB[i0] -> MemRef_B[i0] };
|
|
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyB[i0] -> MemRef_phi[] };
|
|
; CHECK-NEXT: Instructions {
|
|
; CHECK-NEXT: %phi = phi double [ %val, %bodyA ]
|
|
; CHECK-NEXT: }
|
|
; CHECK-NEXT: Stmt_bodyC
|
|
; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyC[i0] -> MemRef_A[i0] };
|
|
; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
|
; CHECK-NEXT: [n] -> { Stmt_bodyC[i0] -> MemRef_phi[] };
|
|
; CHECK-NEXT: new: [n] -> { Stmt_bodyC[i0] -> MemRef_B[i0] };
|
|
; CHECK-NEXT: Instructions {
|
|
; CHECK-NEXT: store double %phi, double* %A_idx
|
|
; CHECK-NEXT: }
|
|
; CHECK-NEXT: }
|