Files
clang-p2996/llvm/test/Transforms/LICM/hoist-load-without-store.ll
Djordje Todorovic 2cdc6f2ca6 Reland "[LICM] Hoist LOAD without sinking the STORE"
When doing load/store promotion within LICM, if we
cannot prove that it is safe to sink the store we won't
hoist the load, even though we can prove the load could
be dereferenced and moved outside the loop. This patch
implements the load promotion by moving it in the loop
preheader by inserting proper PHI in the loop. The store
is kept as is in the loop. By doing this, we avoid doing
the load from a memory location in each iteration.

Please consider this small example:

loop {
  var = *ptr;
  if (var) break;
  *ptr= var + 1;
}
After this patch, it will be:

var0 = *ptr;
loop {
  var1 = phi (var0, var2);
  if (var1) break;
  var2 = var1 + 1;
  *ptr = var2;
}
This addresses some problems from [0].

[0] https://bugs.llvm.org/show_bug.cgi?id=51193

Differential revision: https://reviews.llvm.org/D113289
2021-12-02 03:53:50 -08:00

68 lines
2.5 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -licm -S < %s | FileCheck %s
;; C reproducer:
;; void f(int *ptr, int n) {
;; for (int i = 0; i < n; ++i) {
;; int x = *ptr;
;; if (x)
;; break;
;;
;; *ptr = x + 1;
;; }
;; }
define dso_local void @f(i32* nocapture %ptr, i32 %n) {
; CHECK-LABEL: @f(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP7:%.*]] = icmp slt i32 0, [[N:%.*]]
; CHECK-NEXT: br i1 [[CMP7]], label [[FOR_BODY_LR_PH:%.*]], label [[CLEANUP1:%.*]]
; CHECK: for.body.lr.ph:
; CHECK-NEXT: [[PTR_PROMOTED:%.*]] = load i32, i32* [[PTR:%.*]], align 4
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ [[PTR_PROMOTED]], [[FOR_BODY_LR_PH]] ], [ 1, [[IF_END:%.*]] ]
; CHECK-NEXT: [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END]] ]
; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END]], label [[FOR_BODY_CLEANUP1_CRIT_EDGE:%.*]]
; CHECK: if.end:
; CHECK-NEXT: store i32 1, i32* [[PTR]], align 4
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_08]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[N]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_COND_CLEANUP1_CRIT_EDGE:%.*]]
; CHECK: for.body.cleanup1_crit_edge:
; CHECK-NEXT: br label [[CLEANUP1]]
; CHECK: for.cond.cleanup1_crit_edge:
; CHECK-NEXT: br label [[CLEANUP1]]
; CHECK: cleanup1:
; CHECK-NEXT: ret void
;
entry:
%cmp7 = icmp slt i32 0, %n
br i1 %cmp7, label %for.body.lr.ph, label %cleanup1
for.body.lr.ph: ; preds = %entry
br label %for.body
for.body: ; preds = %for.body.lr.ph, %if.end
%i.08 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %if.end ]
%0 = load i32, i32* %ptr, align 4
%tobool.not = icmp eq i32 %0, 0
br i1 %tobool.not, label %if.end, label %for.body.cleanup1_crit_edge
if.end: ; preds = %for.body
store i32 1, i32* %ptr, align 4
%inc = add nuw nsw i32 %i.08, 1
%cmp = icmp slt i32 %inc, %n
br i1 %cmp, label %for.body, label %for.cond.cleanup1_crit_edge
for.body.cleanup1_crit_edge: ; preds = %for.body
br label %cleanup1
for.cond.cleanup1_crit_edge: ; preds = %if.end
br label %cleanup1
cleanup1: ; preds = %for.cond.cleanup1_crit_edge, %for.body.cleanup1_crit_edge, %entry
ret void
}