Imported Upstream version 5.18.0.205

Former-commit-id: 7f59f7e792705db773f1caecdaa823092f4e2927
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-11-16 08:20:38 +00:00
parent 5cd5df71cc
commit 8e12397d70
28486 changed files with 3867013 additions and 66 deletions

View File

@@ -0,0 +1,28 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
; Check that the call and fcmp are hoisted.
; CHECK-LABEL: define void @fun(
; CHECK: call float
; CHECK: fcmp oeq
; CHECK-NOT: call float
; CHECK-NOT: fcmp oeq
define void @fun(float %__b) minsize {
entry:
br label %if.then
if.then: ; preds = %entry
br i1 undef, label %if.then8, label %lor.lhs.false
lor.lhs.false: ; preds = %if.then
%0 = call float @llvm.fabs.f32(float %__b) #2
%cmpinf7 = fcmp oeq float %0, 0x7FF0000000000000
unreachable
if.then8: ; preds = %if.then
%1 = call float @llvm.fabs.f32(float %__b) #2
%cmpinf10 = fcmp oeq float %1, 0x7FF0000000000000
ret void
}
declare float @llvm.fabs.f32(float)

View File

@@ -0,0 +1,93 @@
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
; Check that convergent calls are not hoisted.
;
; CHECK-LABEL: @no_convergent_func_hoisting(
; CHECK: if.then:
; CHECK: call float @convergent_func(
; CHECK: if.else:
; CHECK: call float @convergent_func(
define float @no_convergent_func_hoisting(float %d, float %min, float %max, float %a) {
entry:
%div = fdiv float 1.000000e+00, %d
%cmp = fcmp oge float %div, 0.000000e+00
br i1 %cmp, label %if.then, label %if.else
if.then:
%sub1 = fsub float %max, %a
%mul2 = call float @convergent_func(float %sub1, float %div)
br label %if.end
if.else:
%sub5 = fsub float %max, %a
%mul6 = call float @convergent_func(float %sub5, float %div)
br label %if.end
if.end:
%tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ]
%add = fadd float %tmax.0, 10.0
ret float %add
}
; The call site is convergent but the declaration is not.
; CHECK-LABEL: @no_convergent_call_hoisting(
; CHECK: if.then:
; CHECK: call float @func(
; CHECK: if.else:
; CHECK: call float @func(
define float @no_convergent_call_hoisting(float %d, float %min, float %max, float %a) {
entry:
%div = fdiv float 1.000000e+00, %d
%cmp = fcmp oge float %div, 0.000000e+00
br i1 %cmp, label %if.then, label %if.else
if.then:
%sub1 = fsub float %max, %a
%mul2 = call float @func(float %sub1, float %div) #0
br label %if.end
if.else:
%sub5 = fsub float %max, %a
%mul6 = call float @func(float %sub5, float %div) #0
br label %if.end
if.end:
%tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ]
%add = fadd float %tmax.0, 10.0
ret float %add
}
; The call site is convergent but the declaration is not.
; CHECK-LABEL: @call_hoisting(
; CHECK: call float @func(
; CHECK-NOT: call float @func(
define float @call_hoisting(float %d, float %min, float %max, float %a) {
entry:
%div = fdiv float 1.000000e+00, %d
%cmp = fcmp oge float %div, 0.000000e+00
br i1 %cmp, label %if.then, label %if.else
if.then:
%sub1 = fsub float %max, %a
%mul2 = call float @func(float %sub1, float %div)
br label %if.end
if.else:
%sub5 = fsub float %max, %a
%mul6 = call float @func(float %sub5, float %div)
br label %if.end
if.end:
%tmax.0 = phi float [ %mul2, %if.then ], [ %mul6, %if.else ]
%add = fadd float %tmax.0, 10.0
ret float %add
}
declare float @convergent_func(float, float) #0
declare float @func(float, float) #1
attributes #0 = { nounwind readnone convergent }
attributes #1 = { nounwind readnone }

View File

@@ -0,0 +1,38 @@
; RUN: opt -S -O2 -enable-gvn-hoist < %s | FileCheck %s
; Check that the inlined loads are hoisted.
; CHECK-LABEL: define i32 @fun(
; CHECK-LABEL: entry:
; CHECK: load i32, i32* @A
; CHECK: if.then:
@A = external global i32
@B = external global i32
@C = external global i32
define i32 @loadA() {
%a = load i32, i32* @A
ret i32 %a
}
define i32 @fun(i1 %c) {
entry:
br i1 %c, label %if.then, label %if.else
if.then:
store i32 1, i32* @B
%call1 = call i32 @loadA()
store i32 2, i32* @C
br label %if.endif
if.else:
store i32 2, i32* @C
%call2 = call i32 @loadA()
store i32 1, i32* @B
br label %if.endif
if.endif:
%ret = phi i32 [ %call1, %if.then ], [ %call2, %if.else ]
ret i32 %ret
}

View File

@@ -0,0 +1,98 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define void @test1(i1 %b, i32* %x) {
entry:
br i1 %b, label %if.then, label %if.else
if.then: ; preds = %entry
store i32 2, i32* %x, align 4, !tbaa !1
br label %if.end
if.else: ; preds = %entry
store i32 2, i32* %x, align 4, !tbaa !5
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void
}
; CHECK-LABEL: define void @test1(
; CHECK: store i32 2, i32* %x, align 4
; CHECK-NEXT: br i1 %b
define void @test2(i1 %b, i32* %x) {
entry:
br i1 %b, label %if.then, label %if.else
if.then: ; preds = %entry
%gep1 = getelementptr inbounds i32, i32* %x, i64 1
store i32 2, i32* %gep1, align 4, !tbaa !1
br label %if.end
if.else: ; preds = %entry
%gep2 = getelementptr inbounds i32, i32* %x, i64 1
store i32 2, i32* %gep2, align 4, !tbaa !5
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void
}
; CHECK-LABEL: define void @test2(
; CHECK: %[[gep:.*]] = getelementptr inbounds i32, i32* %x, i64 1
; CHECK: store i32 2, i32* %[[gep]], align 4
; CHECK-NEXT: br i1 %b
define void @test3(i1 %b, i32* %x) {
entry:
br i1 %b, label %if.then, label %if.else
if.then: ; preds = %entry
%gep1 = getelementptr inbounds i32, i32* %x, i64 1
store i32 2, i32* %gep1, align 4, !tbaa !1
br label %if.end
if.else: ; preds = %entry
%gep2 = getelementptr i32, i32* %x, i64 1
store i32 2, i32* %gep2, align 4, !tbaa !5
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void
}
; CHECK-LABEL: define void @test3(
; CHECK: %[[gep:.*]] = getelementptr i32, i32* %x, i64 1
; CHECK: store i32 2, i32* %[[gep]], align 4
; CHECK-NEXT: br i1 %b
!1 = !{!2, !2, i64 0}
!2 = !{!"int", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C++ TBAA"}
!5 = !{!6, !6, i64 0}
!6 = !{!"_ZTS1e", !3, i64 0}
define i32 @test4(i1 %b, i32* %y) {
entry:
br i1 %b, label %if.then, label %if.end
if.then: ; preds = %entry
%0 = load i32, i32* %y, align 4, !range !7
br label %return
if.end: ; preds = %entry
%1 = load i32, i32* %y, align 4, !range !8
br label %return
return: ; preds = %if.end, %if.then
%retval.0 = phi i32 [ %0, %if.then ], [ %1, %if.end ]
ret i32 %retval.0
}
; CHECK-LABEL: define i32 @test4(
; CHECK: %[[load:.*]] = load i32, i32* %y, align 4, !range ![[range_md:.*]]
; CHECK: %[[phi:.*]] = phi i32 [ %[[load]], %{{.*}} ], [ %[[load]], %{{.*}} ]
; CHECK: ret i32 %[[phi]]
!7 = !{i32 0, i32 2}
!8 = !{i32 3, i32 4}
; CHECK: ![[range_md]] = !{i32 0, i32 2, i32 3, i32 4}

View File

@@ -0,0 +1,31 @@
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
; CHECK: store
; CHECK-NOT: store
; Check that an instruction can be hoisted to a basic block
; with more than two successors.
@G = external global i32, align 4
define void @foo(i32 %c1) {
entry:
switch i32 %c1, label %exit1 [
i32 0, label %sw0
i32 1, label %sw1
]
sw0:
store i32 1, i32* @G
br label %exit
sw1:
store i32 1, i32* @G
br label %exit
exit1:
store i32 1, i32* @G
ret void
exit:
ret void
}

View File

@@ -0,0 +1,69 @@
; RUN: opt -S -gvn-hoist -newgvn < %s | FileCheck %s
; Check that store hoisting works: there should be only one store left.
; CHECK-LABEL: @getopt
; CHECK: store i32
; CHECK-NOT: store i32
@optind = external global i32, align 4
define void @getopt() {
bb:
br label %bb1
bb1: ; preds = %bb
br i1 undef, label %bb2, label %bb3
bb2: ; preds = %bb1
br label %bb13
bb3: ; preds = %bb1
br i1 undef, label %bb4, label %bb9
bb4: ; preds = %bb3
%tmp = load i32, i32* @optind, align 4
br i1 undef, label %bb5, label %bb7
bb5: ; preds = %bb4
%tmp6 = add nsw i32 %tmp, 1
store i32 %tmp6, i32* @optind, align 4
br label %bb12
bb7: ; preds = %bb4
%tmp8 = add nsw i32 %tmp, 1
store i32 %tmp8, i32* @optind, align 4
br label %bb13
bb9: ; preds = %bb3
%tmp10 = load i32, i32* @optind, align 4
%tmp11 = add nsw i32 %tmp10, 1
store i32 %tmp11, i32* @optind, align 4
br label %bb12
bb12: ; preds = %bb9, %bb5
br label %bb13
bb13: ; preds = %bb12, %bb7, %bb2
ret void
}
@GlobalVar = internal global float 1.000000e+00
; Check that we hoist stores and remove the MSSA phi node.
; CHECK-LABEL: @hoistStoresUpdateMSSA
; CHECK: store float
; CHECK-NOT: store float
define float @hoistStoresUpdateMSSA(float %d) {
entry:
store float 0.000000e+00, float* @GlobalVar
%cmp = fcmp oge float %d, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end
if.then:
store float 0.000000e+00, float* @GlobalVar
br label %if.end
if.end:
%tmp = load float, float* @GlobalVar, align 4
ret float %tmp
}

View File

@@ -0,0 +1,105 @@
; RUN: opt -gvn-hoist -newgvn -S < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@GlobalVar = internal global float 1.000000e+00
; Check that we hoist load and scalar expressions in dominator.
; CHECK-LABEL: @dominatorHoisting
; CHECK: load
; CHECK: load
; CHECK: fsub
; CHECK: fmul
; CHECK: load
; CHECK: fsub
; CHECK: fmul
; CHECK-NOT: load
; CHECK-NOT: fmul
; CHECK-NOT: fsub
define float @dominatorHoisting(float %d, float* %min, float* %max, float* %a) {
entry:
%div = fdiv float 1.000000e+00, %d
%0 = load float, float* %min, align 4
%1 = load float, float* %a, align 4
%sub = fsub float %0, %1
%mul = fmul float %sub, %div
%2 = load float, float* %max, align 4
%sub1 = fsub float %2, %1
%mul2 = fmul float %sub1, %div
%cmp = fcmp oge float %div, 0.000000e+00
br i1 %cmp, label %if.then, label %if.end
if.then: ; preds = %entry
%3 = load float, float* %max, align 4
%4 = load float, float* %a, align 4
%sub3 = fsub float %3, %4
%mul4 = fmul float %sub3, %div
%5 = load float, float* %min, align 4
%sub5 = fsub float %5, %4
%mul6 = fmul float %sub5, %div
br label %if.end
if.end: ; preds = %entry
%p1 = phi float [ %mul4, %if.then ], [ 0.000000e+00, %entry ]
%p2 = phi float [ %mul6, %if.then ], [ 0.000000e+00, %entry ]
%x = fadd float %p1, %mul2
%y = fadd float %p2, %mul
%z = fadd float %x, %y
ret float %z
}
; Check that we hoist load and scalar expressions in dominator.
; CHECK-LABEL: @domHoisting
; CHECK: load
; CHECK: load
; CHECK: fsub
; CHECK: fmul
; CHECK: load
; CHECK: fsub
; CHECK: fmul
; CHECK-NOT: load
; CHECK-NOT: fmul
; CHECK-NOT: fsub
define float @domHoisting(float %d, float* %min, float* %max, float* %a) {
entry:
%div = fdiv float 1.000000e+00, %d
%0 = load float, float* %min, align 4
%1 = load float, float* %a, align 4
%sub = fsub float %0, %1
%mul = fmul float %sub, %div
%2 = load float, float* %max, align 4
%sub1 = fsub float %2, %1
%mul2 = fmul float %sub1, %div
%cmp = fcmp oge float %div, 0.000000e+00
br i1 %cmp, label %if.then, label %if.else
if.then:
%3 = load float, float* %max, align 4
%4 = load float, float* %a, align 4
%sub3 = fsub float %3, %4
%mul4 = fmul float %sub3, %div
%5 = load float, float* %min, align 4
%sub5 = fsub float %5, %4
%mul6 = fmul float %sub5, %div
br label %if.end
if.else:
%6 = load float, float* %max, align 4
%7 = load float, float* %a, align 4
%sub9 = fsub float %6, %7
%mul10 = fmul float %sub9, %div
%8 = load float, float* %min, align 4
%sub12 = fsub float %8, %7
%mul13 = fmul float %sub12, %div
br label %if.end
if.end:
%p1 = phi float [ %mul4, %if.then ], [ %mul10, %if.else ]
%p2 = phi float [ %mul6, %if.then ], [ %mul13, %if.else ]
%x = fadd float %p1, %mul2
%y = fadd float %p2, %mul
%z = fadd float %x, %y
ret float %z
}

View File

@@ -0,0 +1,77 @@
; RUN: opt -gvn-hoist -newgvn -gvn-hoist -S < %s | FileCheck %s
; Test to demonstrate that newgvn creates opportunities for
; more gvn-hoist when sibling branches contain identical expressions.
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Check that all "or" expressions are hoisted.
; CHECK-LABEL: @encode
; CHECK: or i32
; CHECK-NOT: or i32
define i8* @encode(i8* %p, i32 %v) {
entry:
%p.addr = alloca i8*, align 8
%v.addr = alloca i32, align 4
store i8* %p, i8** %p.addr, align 8
store i32 %v, i32* %v.addr, align 4
%0 = load i32, i32* %v.addr, align 4
%cmp = icmp ult i32 %0, 23
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %entry
%1 = load i32, i32* %v.addr, align 4
%or = or i32 %1, 128
%conv = trunc i32 %or to i8
%2 = load i8*, i8** %p.addr, align 8
%incdec.ptr = getelementptr inbounds i8, i8* %2, i32 1
store i8* %incdec.ptr, i8** %p.addr, align 8
store i8 %conv, i8* %2, align 1
br label %if.end15
if.else: ; preds = %entry
%3 = load i32, i32* %v.addr, align 4
%cmp1 = icmp ult i32 %3, 42
br i1 %cmp1, label %if.then3, label %if.else9
if.then3: ; preds = %if.else
%4 = load i32, i32* %v.addr, align 4
%or4 = or i32 %4, 128
%conv5 = trunc i32 %or4 to i8
%5 = load i8*, i8** %p.addr, align 8
%incdec.ptr6 = getelementptr inbounds i8, i8* %5, i32 1
store i8* %incdec.ptr6, i8** %p.addr, align 8
store i8 %conv5, i8* %5, align 1
%6 = load i32, i32* %v.addr, align 4
%conv7 = trunc i32 %6 to i8
%7 = load i8*, i8** %p.addr, align 8
%incdec.ptr8 = getelementptr inbounds i8, i8* %7, i32 1
store i8* %incdec.ptr8, i8** %p.addr, align 8
store i8 %conv7, i8* %7, align 1
br label %if.end
if.else9: ; preds = %if.else
%8 = load i32, i32* %v.addr, align 4
%or10 = or i32 %8, 128
%conv11 = trunc i32 %or10 to i8
%9 = load i8*, i8** %p.addr, align 8
%incdec.ptr12 = getelementptr inbounds i8, i8* %9, i32 1
store i8* %incdec.ptr12, i8** %p.addr, align 8
store i8 %conv11, i8* %9, align 1
%10 = load i32, i32* %v.addr, align 4
%shr = lshr i32 %10, 7
%conv13 = trunc i32 %shr to i8
%11 = load i8*, i8** %p.addr, align 8
%incdec.ptr14 = getelementptr inbounds i8, i8* %11, i32 1
store i8* %incdec.ptr14, i8** %p.addr, align 8
store i8 %conv13, i8* %11, align 1
br label %if.end
if.end: ; preds = %if.else9, %if.then3
br label %if.end15
if.end15: ; preds = %if.end, %if.then
%12 = load i8*, i8** %p.addr, align 8
ret i8* %12
}

View File

@@ -0,0 +1,30 @@
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Check that all "sub" expressions are hoisted.
; CHECK-LABEL: @fun
; CHECK: sub i64
; CHECK-NOT: sub i64
define i64 @fun(i8* %out, i8* %end) {
%1 = icmp ult i8* %out, %end
br i1 %1, label %2, label %6
; <label>:2 ; preds = %0
%3 = ptrtoint i8* %end to i64
%4 = ptrtoint i8* %out to i64
%5 = sub i64 %3, %4
br label %10
; <label>:6 ; preds = %0
%7 = ptrtoint i8* %out to i64
%8 = ptrtoint i8* %end to i64
%9 = sub i64 %8, %7
br label %10
; <label>:10 ; preds = %6, %2
%.in = phi i64 [ %5, %2 ], [ %9, %6 ]
%11 = add i64 %.in, 257
ret i64 %11
}

View File

@@ -0,0 +1,50 @@
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc18.0.0"
%struct.S = type { i8* }
declare void @f(<{ %struct.S }>* inalloca)
; Check that we don't clone the %x alloca and insert it in the live range of
; %argmem, which would break the inalloca contract.
;
; CHECK-LABEL: @test
; CHECK: alloca i8
; CHECK: stacksave
; CHECK: alloca inalloca
; CHECK-NOT: alloca i8
; Check that store instructions are hoisted.
; CHECK: store i8
; CHECK-NOT: store i8
; CHECK: stackrestore
define void @test(i1 %b) {
entry:
%x = alloca i8
%inalloca.save = call i8* @llvm.stacksave()
%argmem = alloca inalloca <{ %struct.S }>, align 4
%0 = getelementptr inbounds <{ %struct.S }>, <{ %struct.S }>* %argmem, i32 0, i32 0
br i1 %b, label %true, label %false
true:
%p = getelementptr inbounds %struct.S, %struct.S* %0, i32 0, i32 0
store i8* %x, i8** %p, align 4
br label %exit
false:
%p2 = getelementptr inbounds %struct.S, %struct.S* %0, i32 0, i32 0
store i8* %x, i8** %p2, align 4
br label %exit
exit:
call void @f(<{ %struct.S }>* inalloca %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)

View File

@@ -0,0 +1,20 @@
; RUN: opt -S -gvn-hoist -verify-memoryssa -newgvn < %s | FileCheck %s
; Check that we end up with one load and one store, in the right order
; CHECK-LABEL: define void @test_it(
; CHECK: store
; CHECK-NOT: store
; CHECK-NOT: load
%rec894.0.1.2.3.12 = type { i16 }
@a = external global %rec894.0.1.2.3.12
define void @test_it() {
bb2:
store i16 undef, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1
%_tmp61 = load i16, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1
store i16 undef, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1
%_tmp92 = load i16, i16* getelementptr inbounds (%rec894.0.1.2.3.12, %rec894.0.1.2.3.12* @a, i16 0, i32 0), align 1
ret void
}

View File

@@ -0,0 +1,83 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
; Hoisted inlinable calls need to have accurate scope information, but we're
; allowed to erase the line information.
source_filename = "t.c"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.0.24215"
; Function Attrs: noinline nounwind readnone uwtable
define float @fabsf(float %f) #0 !dbg !7 {
entry:
%conv = fpext float %f to double, !dbg !9
%call = call double @fabs(double %conv) #1, !dbg !10
%conv1 = fptrunc double %call to float, !dbg !11
ret float %conv1, !dbg !12
}
; Function Attrs: nounwind readnone
declare double @fabs(double) #1
; Function Attrs: noinline nounwind uwtable
define void @hoistit(i32 %cond, float %f) #2 !dbg !13 {
entry:
%tobool = icmp ne i32 %cond, 0, !dbg !14
br i1 %tobool, label %if.then, label %if.else, !dbg !14
if.then: ; preds = %entry
%call = call float @fabsf(float %f) #1, !dbg !15
call void @useit1(float %call), !dbg !16
br label %if.end, !dbg !18
if.else: ; preds = %entry
%call1 = call float @fabsf(float %f) #1, !dbg !19
call void @useit2(float %call1), !dbg !20
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void, !dbg !21
}
; CHECK-LABEL: define void @hoistit
; CHECK-SAME: !dbg ![[sp_hoistit:[0-9]+]]
; CHECK: call float @fabsf(float %f) {{.*}} !dbg ![[dbgloc:[0-9]+]]
; CHECK: br i1 %tobool, label %if.then, label %if.else
; CHECK: ![[sp_hoistit]] = distinct !DISubprogram(name: "hoistit", {{.*}})
; CHECK: ![[dbgloc]] = !DILocation({{.*}}, scope: ![[sp_hoistit]])
declare void @useit1(float)
declare void @useit2(float)
attributes #0 = { noinline nounwind readnone uwtable }
attributes #1 = { nounwind readnone }
attributes #2 = { noinline nounwind uwtable }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 5.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
!1 = !DIFile(filename: "t.c", directory: "C:\5Csrc\5Cllvm\5Cbuild")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"PIC Level", i32 2}
!6 = !{!"clang version 5.0.0 "}
!7 = distinct !DISubprogram(name: "fabsf", scope: !1, file: !1, line: 4, type: !8, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
!8 = !DISubroutineType(types: !2)
!9 = !DILocation(line: 5, column: 22, scope: !7)
!10 = !DILocation(line: 5, column: 17, scope: !7)
!11 = !DILocation(line: 5, column: 10, scope: !7)
!12 = !DILocation(line: 5, column: 3, scope: !7)
!13 = distinct !DISubprogram(name: "hoistit", scope: !1, file: !1, line: 7, type: !8, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
!14 = !DILocation(line: 8, column: 7, scope: !13)
!15 = !DILocation(line: 9, column: 12, scope: !13)
!16 = !DILocation(line: 9, column: 5, scope: !17)
!17 = !DILexicalBlockFile(scope: !13, file: !1, discriminator: 1)
!18 = !DILocation(line: 10, column: 3, scope: !13)
!19 = !DILocation(line: 11, column: 12, scope: !13)
!20 = !DILocation(line: 11, column: 5, scope: !17)
!21 = !DILocation(line: 13, column: 1, scope: !13)

View File

@@ -0,0 +1,106 @@
; RUN: opt -gvn-hoist -newgvn -gvn-hoist -S < %s | FileCheck %s
; Check that recursive GEPs are hoisted. Since hoisting creates
; fully redundant instructions, newgvn is run to remove them which then
; creates more opportunites for hoisting.
; CHECK-LABEL: @fun
; CHECK: load
; CHECK: fdiv
; CHECK: load
; CHECK: load
; CHECK: load
; CHECK: fsub
; CHECK: fmul
; CHECK: fsub
; CHECK: fmul
; CHECK-NOT: fsub
; CHECK-NOT: fmul
%0 = type { double, double, double }
%1 = type { double, double, double }
%2 = type { %3, %1, %1 }
%3 = type { i32 (...)**, %4, %10*, %11, %11, %11, %11, %11, %11, %11, %11, %11 }
%4 = type { %5 }
%5 = type { %6 }
%6 = type { %7 }
%7 = type { %8 }
%8 = type { %9 }
%9 = type { i64, i64, i8* }
%10 = type <{ i32 (...)**, i32, [4 x i8] }>
%11 = type { [4 x [4 x double]] }
%12 = type <{ %1, %0, i32, [4 x i8] }>
%13 = type { %1, %0, %12, %3*, %14* }
%14 = type opaque
@d = external global %0, align 8
@p = external global %1, align 8
define zeroext i1 @fun(%2*, %12* dereferenceable(56), double*, %13*) {
%5 = alloca %2*, align 8
%6 = alloca %12*, align 8
%7 = alloca double*, align 8
%8 = alloca %13*, align 8
%9 = alloca double, align 8
%10 = alloca double, align 8
%11 = alloca double, align 8
%12 = alloca double, align 8
%13 = alloca double, align 8
%14 = alloca double, align 8
%15 = alloca double, align 8
store %2* %0, %2** %5, align 8
store %12* %1, %12** %6, align 8
store double* %2, double** %7, align 8
store %13* %3, %13** %8, align 8
%16 = load %2*, %2** %5, align 8
%17 = load double, double* getelementptr inbounds (%0, %0* @d, i32 0, i32 0), align 8
%18 = fdiv double 1.000000e+00, %17
store double %18, double* %15, align 8
%19 = load double, double* %15, align 8
%20 = fcmp oge double %19, 0.000000e+00
br i1 %20, label %21, label %36
; <label>:21: ; preds = %4
%22 = getelementptr inbounds %2, %2* %16, i32 0, i32 1
%23 = getelementptr inbounds %1, %1* %22, i32 0, i32 0
%24 = load double, double* %23, align 8
%25 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8
%26 = fsub double %24, %25
%27 = load double, double* %15, align 8
%28 = fmul double %26, %27
store double %28, double* %9, align 8
%29 = getelementptr inbounds %2, %2* %16, i32 0, i32 2
%30 = getelementptr inbounds %1, %1* %29, i32 0, i32 0
%31 = load double, double* %30, align 8
%32 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8
%33 = fsub double %31, %32
%34 = load double, double* %15, align 8
%35 = fmul double %33, %34
store double %35, double* %12, align 8
br label %51
; <label>:36: ; preds = %4
%37 = getelementptr inbounds %2, %2* %16, i32 0, i32 2
%38 = getelementptr inbounds %1, %1* %37, i32 0, i32 0
%39 = load double, double* %38, align 8
%40 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8
%41 = fsub double %39, %40
%42 = load double, double* %15, align 8
%43 = fmul double %41, %42
store double %43, double* %9, align 8
%44 = getelementptr inbounds %2, %2* %16, i32 0, i32 1
%45 = getelementptr inbounds %1, %1* %44, i32 0, i32 0
%46 = load double, double* %45, align 8
%47 = load double, double* getelementptr inbounds (%1, %1* @p, i32 0, i32 0), align 8
%48 = fsub double %46, %47
%49 = load double, double* %15, align 8
%50 = fmul double %48, %49
store double %50, double* %12, align 8
br label %51
; <label>:51: ; preds = %36, %21
%52 = load double, double* %12, align 8
%53 = load double, double* %9, align 8
%54 = fcmp olt double %52, %53
ret i1 %54
}

View File

@@ -0,0 +1,81 @@
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
; Check that urem is not hoisted.
; CHECK-LABEL: @main
; CHECK: urem
; CHECK: urem
; CHECK: urem
@g_x_s = global i32 -470211272, align 4
@g_z_s = global i32 2007237709, align 4
@g_x_u = global i32 282475249, align 4
@g_z_u = global i32 984943658, align 4
@g_m = global i32 16807, align 4
@res = common global i32 0, align 4
; Function Attrs:
define i64 @func() #0 {
entry:
ret i64 1
}
; Function Attrs:
define i32 @main() {
entry:
%0 = load volatile i32, i32* @g_x_s, align 4
%1 = load volatile i32, i32* @g_z_s, align 4
%2 = load volatile i32, i32* @g_x_u, align 4
%3 = load volatile i32, i32* @g_z_u, align 4
%4 = load volatile i32, i32* @g_m, align 4
%call = call i64 @func() #4
%conv = sext i32 %1 to i64
%cmp = icmp ne i64 %call, %conv
br i1 %cmp, label %if.end, label %lor.lhs.false
lor.lhs.false:
%div = udiv i32 %4, %1
%rem = urem i32 %0, %div
%cmp2 = icmp eq i32 %rem, 0
br i1 %cmp2, label %if.end, label %if.then
if.then:
br label %cleanup
if.end:
%call4 = call i64 @func() #4
%conv5 = zext i32 %3 to i64
%cmp6 = icmp ne i64 %call4, %conv5
br i1 %cmp6, label %if.end14, label %lor.lhs.false8
lor.lhs.false8:
%div9 = udiv i32 %4, %3
%rem10 = urem i32 %0, %div9
%cmp11 = icmp eq i32 %rem10, 0
br i1 %cmp11, label %if.end14, label %if.then13
if.then13:
br label %cleanup
if.end14:
%call15 = call i64 @func() #4
%cmp17 = icmp ne i64 %call15, %conv
br i1 %cmp17, label %if.end25, label %lor.lhs.false19
lor.lhs.false19:
%div20 = udiv i32 %4, %1
%rem21 = urem i32 %0, %div20
%cmp22 = icmp eq i32 %rem21, 0
br i1 %cmp22, label %if.end25, label %if.then24
if.then24:
br label %cleanup
if.end25:
br label %cleanup
cleanup:
%retval.0 = phi i32 [ 0, %if.end25 ], [ 1, %if.then24 ], [ 1, %if.then13 ], [ 1, %if.then ]
ret i32 %retval.0
}
attributes #0 = { minsize noinline nounwind optsize uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

View File

@@ -0,0 +1,55 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
%struct.__jmp_buf_tag = type { [8 x i64], i32 }
; Check that hoisting only happens when the expression is very busy.
; CHECK: store
; CHECK: store
@test_exit_buf = global %struct.__jmp_buf_tag zeroinitializer
@G = global i32 0
define void @test_command(i32 %c1) {
entry:
switch i32 %c1, label %exit [
i32 0, label %sw0
i32 1, label %sw1
]
sw0:
store i32 1, i32* @G
br label %exit
sw1:
store i32 1, i32* @G
br label %exit
exit:
call void @longjmp(%struct.__jmp_buf_tag* @test_exit_buf, i32 1) #0
unreachable
}
declare void @longjmp(%struct.__jmp_buf_tag*, i32) #0
attributes #0 = { noreturn nounwind }
; Check that the store is hoisted.
; CHECK-LABEL: define void @fun(
; CHECK: store
; CHECK-NOT: store
define void @fun() {
entry:
br label %if.then
if.then: ; preds = %entry
br i1 undef, label %sw0, label %sw1
sw0:
store i32 1, i32* @G
unreachable
sw1:
store i32 1, i32* @G
ret void
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
; Checking gvn-hoist in case of infinite loops and irreducible control flow.
; Check that bitcast is not hoisted beacuse down safety is not guaranteed.
; CHECK-LABEL: @bazv1
; CHECK: if.then.i:
; CHECK: bitcast
; CHECK-NEXT: load
; CHECK: if.then4.i:
; CHECK: bitcast
; CHECK-NEXT: load
%class.bar = type { i8*, %class.base* }
%class.base = type { i32 (...)** }
; Function Attrs: noreturn nounwind uwtable
define void @bazv1() local_unnamed_addr {
entry:
%agg.tmp = alloca %class.bar, align 8
%x.sroa.2.0..sroa_idx2 = getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
store %class.base* null, %class.base** %x.sroa.2.0..sroa_idx2, align 8
call void @_Z3foo3bar(%class.bar* nonnull %agg.tmp)
%0 = load %class.base*, %class.base** %x.sroa.2.0..sroa_idx2, align 8
%1 = bitcast %class.bar* %agg.tmp to %class.base*
%cmp.i = icmp eq %class.base* %0, %1
br i1 %cmp.i, label %if.then.i, label %if.else.i
if.then.i: ; preds = %entry
%2 = bitcast %class.base* %0 to void (%class.base*)***
%vtable.i = load void (%class.base*)**, void (%class.base*)*** %2, align 8
%vfn.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %vtable.i, i64 2
%3 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
call void %3(%class.base* %0)
br label %while.cond.preheader
if.else.i: ; preds = %entry
%tobool.i = icmp eq %class.base* %0, null
br i1 %tobool.i, label %while.cond.preheader, label %if.then4.i
if.then4.i: ; preds = %if.else.i
%4 = bitcast %class.base* %0 to void (%class.base*)***
%vtable6.i = load void (%class.base*)**, void (%class.base*)*** %4, align 8
%vfn7.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %vtable6.i, i64 3
%5 = load void (%class.base*)*, void (%class.base*)** %vfn7.i, align 8
call void %5(%class.base* nonnull %0)
br label %while.cond.preheader
while.cond.preheader: ; preds = %if.then.i, %if.else.i, %if.then4.i
br label %while.cond
while.cond: ; preds = %while.cond.preheader, %while.cond
%call = call i32 @sleep(i32 10)
br label %while.cond
}
declare void @_Z3foo3bar(%class.bar*) local_unnamed_addr
declare i32 @sleep(i32) local_unnamed_addr
; Check that the load is hoisted even if it is inside an irreducible control flow
; because the load is anticipable on all paths.
; CHECK-LABEL: @bazv
; CHECK: bb2:
; CHECK-NOT: load
; CHECK-NOT: bitcast
define void @bazv() {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%0 = load %class.base*, %class.base** %x, align 8
%1 = bitcast %class.bar* %agg.tmp to %class.base*
%cmp.i = icmp eq %class.base* %0, %1
br i1 %cmp.i, label %bb1, label %bb4
bb1:
%b1 = bitcast %class.base* %0 to void (%class.base*)***
%i = load void (%class.base*)**, void (%class.base*)*** %b1, align 8
%vfn.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %i, i64 2
%cmp.j = icmp eq %class.base* %0, %1
br i1 %cmp.j, label %bb2, label %bb3
bb2:
%l1 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
br label %bb3
bb3:
%l2 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
br label %bb2
bb4:
%b2 = bitcast %class.base* %0 to void (%class.base*)***
ret void
}

View File

@@ -0,0 +1,285 @@
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
; Checking gvn-hoist in case of indirect branches.
; Check that the bitcast is is not hoisted because it is after an indirect call
; CHECK-LABEL: @foo
; CHECK-LABEL: l1.preheader:
; CHECK-NEXT: bitcast
; CHECK-LABEL: l1
; CHECK: bitcast
%class.bar = type { i8*, %class.base* }
%class.base = type { i32 (...)** }
@bar = local_unnamed_addr global i32 ()* null, align 8
@bar1 = local_unnamed_addr global i32 ()* null, align 8
define i32 @foo(i32* nocapture readonly %i) {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%y = load %class.base*, %class.base** %x, align 8
%0 = load i32, i32* %i, align 4
%.off = add i32 %0, -1
%switch = icmp ult i32 %.off, 2
br i1 %switch, label %l1.preheader, label %sw.default
l1.preheader: ; preds = %sw.default, %entry
%b1 = bitcast %class.base* %y to void (%class.base*)***
br label %l1
l1: ; preds = %l1.preheader, %l1
%1 = load i32 ()*, i32 ()** @bar, align 8
%call = tail call i32 %1()
%b2 = bitcast %class.base* %y to void (%class.base*)***
br label %l1
sw.default: ; preds = %entry
%2 = load i32 ()*, i32 ()** @bar1, align 8
%call2 = tail call i32 %2()
br label %l1.preheader
}
; Any instruction inside an infinite loop will not be hoisted because
; there is no path to exit of the function.
; CHECK-LABEL: @foo1
; CHECK-LABEL: l1.preheader:
; CHECK-NEXT: bitcast
; CHECK-LABEL: l1:
; CHECK: bitcast
define i32 @foo1(i32* nocapture readonly %i) {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%y = load %class.base*, %class.base** %x, align 8
%0 = load i32, i32* %i, align 4
%.off = add i32 %0, -1
%switch = icmp ult i32 %.off, 2
br i1 %switch, label %l1.preheader, label %sw.default
l1.preheader: ; preds = %sw.default, %entry
%b1 = bitcast %class.base* %y to void (%class.base*)***
%y1 = load %class.base*, %class.base** %x, align 8
br label %l1
l1: ; preds = %l1.preheader, %l1
%b2 = bitcast %class.base* %y to void (%class.base*)***
%1 = load i32 ()*, i32 ()** @bar, align 8
%y2 = load %class.base*, %class.base** %x, align 8
%call = tail call i32 %1()
br label %l1
sw.default: ; preds = %entry
%2 = load i32 ()*, i32 ()** @bar1, align 8
%call2 = tail call i32 %2()
br label %l1.preheader
}
; Check that bitcast is hoisted even when one of them is partially redundant.
; CHECK-LABEL: @test13
; CHECK: bitcast
; CHECK-NOT: bitcast
define i32 @test13(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%y = load %class.base*, %class.base** %x, align 8
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
B2:
%b1 = bitcast %class.base* %y to void (%class.base*)***
store i32 4, i32 *%P
br label %BrBlock
BrBlock:
%b2 = bitcast %class.base* %y to void (%class.base*)***
%L = load i32, i32* %P
%C = icmp eq i32 %L, 42
br i1 %C, label %T, label %F
T:
ret i32 123
F:
ret i32 1422
}
; Check that the bitcast is not hoisted because anticipability
; cannot be guaranteed here as one of the indirect branch targets
; do not have the bitcast instruction.
; CHECK-LABEL: @test14
; CHECK-LABEL: B2:
; CHECK-NEXT: bitcast
; CHECK-LABEL: BrBlock:
; CHECK-NEXT: bitcast
define i32 @test14(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%y = load %class.base*, %class.base** %x, align 8
indirectbr i8* %Ptr, [label %BrBlock, label %B2, label %T]
B2:
%b1 = bitcast %class.base* %y to void (%class.base*)***
store i32 4, i32 *%P
br label %BrBlock
BrBlock:
%b2 = bitcast %class.base* %y to void (%class.base*)***
%L = load i32, i32* %P
%C = icmp eq i32 %L, 42
br i1 %C, label %T, label %F
T:
%pi = load i32, i32* %i, align 4
ret i32 %pi
F:
%pl = load i32, i32* %P
ret i32 %pl
}
; Check that the bitcast is not hoisted because of a cycle
; due to indirect branches
; CHECK-LABEL: @test16
; CHECK-LABEL: B2:
; CHECK-NEXT: bitcast
; CHECK-LABEL: BrBlock:
; CHECK-NEXT: bitcast
define i32 @test16(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
entry:
%agg.tmp = alloca %class.bar, align 8
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
%y = load %class.base*, %class.base** %x, align 8
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
B2:
%b1 = bitcast %class.base* %y to void (%class.base*)***
%0 = load i32, i32* %i, align 4
store i32 %0, i32 *%P
br label %BrBlock
BrBlock:
%b2 = bitcast %class.base* %y to void (%class.base*)***
%L = load i32, i32* %P
%C = icmp eq i32 %L, 42
br i1 %C, label %T, label %F
T:
indirectbr i32* %P, [label %BrBlock, label %B2]
F:
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
}
@_ZTIi = external constant i8*
; Check that an instruction is not hoisted out of landing pad (%lpad4)
; Also within a landing pad no redundancies are removed by gvn-hoist,
; however an instruction may be hoisted into a landing pad if
; landing pad has direct branches (e.g., %lpad to %catch1, %catch)
; This CFG has a cycle (%lpad -> %catch1 -> %lpad4 -> %lpad)
; CHECK-LABEL: @foo2
; Check that nothing gets hoisted out of %lpad
; CHECK-LABEL: lpad:
; CHECK: %bc1 = add i32 %0, 10
; CHECK: %bc7 = add i32 %0, 10
; Check that the add is hoisted
; CHECK-LABEL: catch1:
; CHECK-NEXT: invoke
; Check that the add is hoisted
; CHECK-LABEL: catch:
; CHECK-NEXT: load
; Check that other adds are not hoisted
; CHECK-LABEL: lpad4:
; CHECK: %bc5 = add i32 %0, 10
; CHECK-LABEL: unreachable:
; CHECK: %bc2 = add i32 %0, 10
; Function Attrs: noinline uwtable
define i32 @foo2(i32* nocapture readonly %i) local_unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
%0 = load i32, i32* %i, align 4
%cmp = icmp eq i32 %0, 0
br i1 %cmp, label %try.cont, label %if.then
if.then:
%exception = tail call i8* @__cxa_allocate_exception(i64 4) #2
%1 = bitcast i8* %exception to i32*
store i32 %0, i32* %1, align 16
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
to label %unreachable unwind label %lpad
lpad:
%2 = landingpad { i8*, i32 }
catch i8* bitcast (i8** @_ZTIi to i8*)
catch i8* null
%bc1 = add i32 %0, 10
%3 = extractvalue { i8*, i32 } %2, 0
%4 = extractvalue { i8*, i32 } %2, 1
%5 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #2
%matches = icmp eq i32 %4, %5
%bc7 = add i32 %0, 10
%6 = tail call i8* @__cxa_begin_catch(i8* %3) #2
br i1 %matches, label %catch1, label %catch
catch1:
%bc3 = add i32 %0, 10
invoke void @__cxa_rethrow() #3
to label %unreachable unwind label %lpad4
catch:
%bc4 = add i32 %0, 10
%7 = load i32, i32* %i, align 4
%add = add nsw i32 %7, 1
tail call void @__cxa_end_catch()
br label %try.cont
lpad4:
%8 = landingpad { i8*, i32 }
cleanup
%bc5 = add i32 %0, 10
tail call void @__cxa_end_catch() #2
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
to label %unreachable unwind label %lpad
try.cont:
%k.0 = phi i32 [ %add, %catch ], [ 0, %entry ]
%bc6 = add i32 %0, 10
ret i32 %k.0
unreachable:
%bc2 = add i32 %0, 10
ret i32 %bc2
}
declare i8* @__cxa_allocate_exception(i64) local_unnamed_addr
declare void @__cxa_throw(i8*, i8*, i8*) local_unnamed_addr
declare i32 @__gxx_personality_v0(...)
; Function Attrs: nounwind readnone
declare i32 @llvm.eh.typeid.for(i8*) #1
declare i8* @__cxa_begin_catch(i8*) local_unnamed_addr
declare void @__cxa_end_catch() local_unnamed_addr
declare void @__cxa_rethrow() local_unnamed_addr
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }
attributes #3 = { noreturn }

View File

@@ -0,0 +1,30 @@
; RUN: opt -S < %s -gvn-hoist | FileCheck %s
declare void @llvm.sideeffect()
; GVN hoisting across a @llvm.sideeffect.
; CHECK-LABEL: scalarsHoisting
; CHECK: = fsub
; CHECK: br i1 %cmp,
; CHECK-NOT: fsub
define float @scalarsHoisting(float %d, float %m, float %a, i1 %cmp) {
entry:
br i1 %cmp, label %if.then, label %if.else
if.then:
call void @llvm.sideeffect()
%sub0 = fsub float %m, %a
%mul = fmul float %sub0, %d
br label %if.end
if.else:
%sub1 = fsub float %m, %a
%div = fdiv float %sub1, %d
br label %if.end
if.end:
%phi = phi float [ %mul, %if.then ], [ %div, %if.else ]
ret float %phi
}

View File

@@ -0,0 +1,64 @@
; Test load hoist
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc_linux"
; Function Attrs: nounwind uwtable
define float* @foo(i32* noalias nocapture readonly %in, float* noalias %out, i32 %size, i32* nocapture readonly %trigger) {
entry:
%cmp11 = icmp eq i32 %size, 0
br i1 %cmp11, label %for.end, label %for.body.lr.ph
for.body.lr.ph: ; preds = %entry
%0 = add i32 %size, -1
br label %for.body
; CHECK-LABEL: for.body
; CHECK: load
; CHECK: %2 = getelementptr inbounds i32, i32* %in, i64 %indvars.iv
; CHECK: %3 = load i32, i32* %2, align 4
for.body: ; preds = %for.body.lr.ph, %for.inc
%indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.inc ]
%arrayidx = getelementptr inbounds i32, i32* %trigger, i64 %indvars.iv
%1 = load i32, i32* %arrayidx, align 4
%cmp1 = icmp sgt i32 %1, 0
br i1 %cmp1, label %if.then, label %if.else
; CHECK-LABEL: if.then
if.then: ; preds = %for.body
; This load should be hoisted
%arrayidx3 = getelementptr inbounds i32, i32* %in, i64 %indvars.iv
%2 = load i32, i32* %arrayidx3, align 4
%conv = sitofp i32 %2 to float
%add = fadd float %conv, 5.000000e-01
%arrayidx5 = getelementptr inbounds float, float* %out, i64 %indvars.iv
store float %add, float* %arrayidx5, align 4
br label %for.inc
if.else: ; preds = %for.body
%arrayidx7 = getelementptr inbounds float, float* %out, i64 %indvars.iv
%3 = load float, float* %arrayidx7, align 4
%div = fdiv float %3, 3.000000e+00
store float %div, float* %arrayidx7, align 4
; This load should be hoisted in spite of store
%arrayidx9 = getelementptr inbounds i32, i32* %in, i64 %indvars.iv
%4 = load i32, i32* %arrayidx9, align 4
%conv10 = sitofp i32 %4 to float
%add13 = fadd float %div, %conv10
store float %add13, float* %arrayidx7, align 4
br label %for.inc
for.inc: ; preds = %if.then, %if.else
%indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
%lftr.wideiv = trunc i64 %indvars.iv to i32
%exitcond = icmp ne i32 %lftr.wideiv, %0
br i1 %exitcond, label %for.body, label %for.cond.for.end_crit_edge
for.cond.for.end_crit_edge: ; preds = %for.inc
br label %for.end
for.end: ; preds = %entry, %for.cond.for.end_crit_edge
ret float* %out
}

Some files were not shown because too many files have changed in this diff Show More