; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=gvn -S | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:1"
target triple = "x86_64-unknown-linux-gnu"
declare void @llvm.memset.p0.i8(ptr, i8, i32, i1)
declare void @foo(ptr)
define i8 @test(i1 %cmp) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P:%.*]] = alloca i8
; CHECK-NEXT: store i8 5, ptr [[P]]
; CHECK-NEXT: br label [[HEADER:%.*]]
; CHECK: header:
; CHECK-NEXT: [[V:%.*]] = phi i8 [ 5, [[ENTRY:%.*]] ], [ -5, [[ALIVE:%.*]] ]
; CHECK-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[I_INC:%.*]], [[ALIVE]] ]
; CHECK-NEXT: br i1 [[CMP:%.*]], label [[ALIVE]], label [[DEAD:%.*]]
; CHECK: dead:
; CHECK-NEXT: call void @foo(ptr [[P]])
; CHECK-NEXT: [[I_1:%.*]] = add i8 [[I]], [[V]]
; CHECK-NEXT: br label [[ALIVE]]
; CHECK: alive:
; CHECK-NEXT: [[I_2:%.*]] = phi i8 [ [[I]], [[HEADER]] ], [ [[I_1]], [[DEAD]] ]
; CHECK-NEXT: store i8 -5, ptr [[P]]
; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 1 [[P]], i8 0, i32 1, i1 false)
; CHECK-NEXT: [[I_INC]] = add i8 [[I_2]], 1
; CHECK-NEXT: [[CMP_LOOP:%.*]] = icmp ugt i8 [[I_INC]], 100
; CHECK-NEXT: br i1 [[CMP_LOOP]], label [[EXIT:%.*]], label [[HEADER]]
; CHECK: exit:
; CHECK-NEXT: ret i8 0
;
entry:
%p = alloca i8
store i8 5, ptr %p
br label %header
header:
%i = phi i8 [0, %entry], [%i.inc, %backedge]
br i1 %cmp, label %alive, label %dead
dead:
call void @foo(ptr %p)
%v = load i8, ptr %p, !invariant.load !1
%i.1 = add i8 %i, %v
br label %alive
alive:
%i.2 = phi i8 [%i, %header], [%i.1, %dead]
store i8 -5, ptr %p
br label %backedge
backedge:
call void @llvm.memset.p0.i8(ptr align 1 %p, i8 0, i32 1, i1 false)
%i.inc = add i8 %i.2, 1
%cmp.loop = icmp ugt i8 %i.inc, 100
br i1 %cmp.loop, label %exit, label %header
exit:
%res = load i8, ptr %p
ret i8 %res
}
; Check that first two loads are not optimized out while the one marked with
; invariant.load reuses %res1
define i8 @test2(i1 %cmp, ptr %p) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RES1:%.*]] = load i8, ptr [[P:%.*]], align 1
; CHECK-NEXT: call void @foo(ptr [[P]])
; CHECK-NEXT: br i1 [[CMP:%.*]], label [[B2:%.*]], label [[B1:%.*]]
; CHECK: b1:
; CHECK-NEXT: [[RES2:%.*]] = load i8, ptr [[P]]
; CHECK-NEXT: [[RES3:%.*]] = add i8 [[RES1]], [[RES2]]
; CHECK-NEXT: br label [[ALIVE:%.*]]
; CHECK: b2:
; CHECK-NEXT: [[RES_DEAD:%.*]] = add i8 [[RES1]], [[RES1]]
; CHECK-NEXT: br label [[ALIVE]]
; CHECK: alive:
; CHECK-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES3]], [[B1]] ], [ [[RES_DEAD]], [[B2]] ]
; CHECK-NEXT: ret i8 [[RES_PHI]]
;
entry:
%res1 = load i8, ptr %p
call void @foo(ptr %p)
br i1 %cmp, label %b2, label %b1
b1:
%res2 = load i8, ptr %p
%res3 = add i8 %res1, %res2
br label %alive
b2:
%v = load i8, ptr %p, !invariant.load !1
%res.dead = add i8 %v, %res1
br label %alive
alive:
%res.phi = phi i8 [%res3, %b1], [%res.dead, %b2]
ret i8 %res.phi
}
; This is essentially the same test case as the above one but with %b1 and %b2
; swapped in "br i1 %cmp, label %b1, label %b2" instruction. That helps us to
; ensure that results doesn't depend on visiting order.
define i8 @test3(i1 %cmp, ptr %p) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RES1:%.*]] = load i8, ptr [[P:%.*]], align 1
; CHECK-NEXT: call void @foo(ptr [[P]])
; CHECK-NEXT: br i1 [[CMP:%.*]], label [[B1:%.*]], label [[B2:%.*]]
; CHECK: b1:
; CHECK-NEXT: [[RES2:%.*]] = load i8, ptr [[P]]
; CHECK-NEXT: [[RES3:%.*]] = add i8 [[RES1]], [[RES2]]
; CHECK-NEXT: br label [[ALIVE:%.*]]
; CHECK: b2:
; CHECK-NEXT: [[RES_DEAD:%.*]] = add i8 [[RES1]], [[RES1]]
; CHECK-NEXT: br label [[ALIVE]]
; CHECK: alive:
; CHECK-NEXT: [[RES_PHI:%.*]] = phi i8 [ [[RES3]], [[B1]] ], [ [[RES_DEAD]], [[B2]] ]
; CHECK-NEXT: ret i8 [[RES_PHI]]
;
entry:
%res1 = load i8, ptr %p
call void @foo(ptr %p)
br i1 %cmp, label %b1, label %b2
b1:
%res2 = load i8, ptr %p
%res3 = add i8 %res1, %res2
br label %alive
b2:
%v = load i8, ptr %p, !invariant.load !1
%res.dead = add i8 %v, %res1
br label %alive
alive:
%res.phi = phi i8 [%res3, %b1], [%res.dead, %b2]
ret i8 %res.phi
}
; This is reduced test case catching regression in the first version of the
; fix for invariant loads (https://reviews.llvm.org/D64405).
define void @test4() {
; CHECK-LABEL: @test4(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = load float, ptr inttoptr (i64 8 to ptr), align 4
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[TMP0]], [[TMP0]]
; CHECK-NEXT: br label [[FUSION_LOOP_HEADER_DIM_1_PREHEADER:%.*]]
; CHECK: fusion.loop_header.dim.1.preheader:
; CHECK-NEXT: [[TMP2:%.*]] = phi float [ [[TMP0]], [[ENTRY:%.*]] ], [ [[DOTPRE:%.*]], [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]] ]
; CHECK-NEXT: [[FUSION_INVAR_ADDRESS_DIM_0_03:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[INVAR_INC3:%.*]], [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]] ]
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 [[FUSION_INVAR_ADDRESS_DIM_0_03]], i64 0, i64 2
; CHECK-NEXT: [[TMP4:%.*]] = fmul float [[TMP2]], [[TMP2]]
; CHECK-NEXT: [[INVAR_INC3]] = add nuw nsw i64 [[FUSION_INVAR_ADDRESS_DIM_0_03]], 1
; CHECK-NEXT: [[DOTPHI_TRANS_INSERT:%.*]] = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 [[INVAR_INC3]], i64 0, i64 2
; CHECK-NEXT: [[DOTPRE]] = load float, ptr [[DOTPHI_TRANS_INSERT]], align 4, !invariant.load !0
; CHECK-NEXT: br label [[FUSION_LOOP_HEADER_DIM_1_PREHEADER]]
;
entry:
%0 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 0, i64 0, i64 2
%1 = load float, ptr %0, align 4
%2 = fmul float %1, %1
br label %fusion.loop_header.dim.1.preheader
fusion.loop_header.dim.1.preheader: ; preds = %fusion.loop_header.dim.1.preheader, %entry
%fusion.invar_address.dim.0.03 = phi i64 [ 0, %entry ], [ %invar.inc3, %fusion.loop_header.dim.1.preheader ]
%3 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 %fusion.invar_address.dim.0.03, i64 0, i64 2
%4 = load float, ptr %3, align 4, !invariant.load !1
%5 = fmul float %4, %4
%6 = getelementptr inbounds [2 x [1 x [4 x float]]], ptr null, i64 0, i64 %fusion.invar_address.dim.0.03, i64 0, i64 2
%7 = load float, ptr %6, align 4, !invariant.load !1
%8 = fmul float %7, %7
%invar.inc3 = add nuw nsw i64 %fusion.invar_address.dim.0.03, 1
br label %fusion.loop_header.dim.1.preheader
}
!1 = !{}