Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,13 @@
; RUN: opt < %s -jump-threading -S | grep "ret i32 0"
; PR3138
define i32 @jt() {
entry:
br i1 true, label %bb3, label %bb
bb: ; preds = %entry
unreachable
bb3: ; preds = %entry
ret i32 0
}

View File

@ -0,0 +1,162 @@
; RUN: opt -jump-threading -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-darwin10.0.0"
%class.StringSwitch = type { i8*, i32, i32, i8 }
@.str = private constant [4 x i8] c"red\00" ; <[4 x i8]*> [#uses=1]
@.str1 = private constant [7 x i8] c"orange\00" ; <[7 x i8]*> [#uses=1]
@.str2 = private constant [7 x i8] c"yellow\00" ; <[7 x i8]*> [#uses=1]
@.str3 = private constant [6 x i8] c"green\00" ; <[6 x i8]*> [#uses=1]
@.str4 = private constant [5 x i8] c"blue\00" ; <[5 x i8]*> [#uses=1]
@.str5 = private constant [7 x i8] c"indigo\00" ; <[7 x i8]*> [#uses=1]
@.str6 = private constant [7 x i8] c"violet\00" ; <[7 x i8]*> [#uses=1]
@.str7 = private constant [12 x i8] c"Color = %d\0A\00" ; <[12 x i8]*> [#uses=1]
define i32 @main(i32 %argc, i8** nocapture %argv) nounwind ssp {
entry:
%cmp142 = icmp sgt i32 %argc, 1 ; <i1> [#uses=1]
br i1 %cmp142, label %bb.nph, label %for.end
bb.nph: ; preds = %entry
%tmp = add i32 %argc, -2 ; <i32> [#uses=1]
%tmp144 = zext i32 %tmp to i64 ; <i64> [#uses=1]
%tmp145 = add i64 %tmp144, 1 ; <i64> [#uses=1]
br label %land.lhs.true.i
land.lhs.true.i: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134, %bb.nph
%retval.0.i.pre161 = phi i32 [ undef, %bb.nph ], [ %retval.0.i.pre, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134 ] ; <i32> [#uses=3]
%indvar = phi i64 [ 0, %bb.nph ], [ %tmp146, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134 ] ; <i64> [#uses=1]
%tmp146 = add i64 %indvar, 1 ; <i64> [#uses=3]
%arrayidx = getelementptr i8*, i8** %argv, i64 %tmp146 ; <i8**> [#uses=1]
%tmp6 = load i8*, i8** %arrayidx, align 8 ; <i8*> [#uses=8]
%call.i.i = call i64 @strlen(i8* %tmp6) nounwind ; <i64> [#uses=1]
%conv.i.i = trunc i64 %call.i.i to i32 ; <i32> [#uses=6]\
; CHECK: switch i32 %conv.i.i
; CHECK-NOT: if.then.i40
; CHECK: }
switch i32 %conv.i.i, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit [
i32 3, label %land.lhs.true5.i
i32 6, label %land.lhs.true5.i37
]
land.lhs.true5.i: ; preds = %land.lhs.true.i
%call.i = call i32 @memcmp(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i8* %tmp6, i64 4) nounwind ; <i32> [#uses=1]
%cmp9.i = icmp eq i32 %call.i, 0 ; <i1> [#uses=1]
br i1 %cmp9.i, label %_ZN12StringSwitchI5ColorE4CaseILj4EEERS1_RAT__KcRKS0_.exit, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
_ZN12StringSwitchI5ColorE4CaseILj4EEERS1_RAT__KcRKS0_.exit: ; preds = %land.lhs.true5.i
br label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
land.lhs.true5.i37: ; preds = %land.lhs.true.i
%call.i35 = call i32 @memcmp(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str1, i64 0, i64 0), i8* %tmp6, i64 7) nounwind ; <i32> [#uses=1]
%cmp9.i36 = icmp eq i32 %call.i35, 0 ; <i1> [#uses=1]
br i1 %cmp9.i36, label %if.then.i40, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
if.then.i40: ; preds = %land.lhs.true5.i37
br label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit: ; preds = %if.then.i40, %land.lhs.true5.i37, %_ZN12StringSwitchI5ColorE4CaseILj4EEERS1_RAT__KcRKS0_.exit, %land.lhs.true5.i, %land.lhs.true.i
%retval.0.i.pre159 = phi i32 [ 1, %_ZN12StringSwitchI5ColorE4CaseILj4EEERS1_RAT__KcRKS0_.exit ], [ %retval.0.i.pre161, %land.lhs.true5.i37 ], [ 2, %if.then.i40 ], [ %retval.0.i.pre161, %land.lhs.true5.i ], [ %retval.0.i.pre161, %land.lhs.true.i ] ; <i32> [#uses=2]
%tmp2.i44 = phi i8 [ 1, %_ZN12StringSwitchI5ColorE4CaseILj4EEERS1_RAT__KcRKS0_.exit ], [ 0, %land.lhs.true5.i37 ], [ 1, %if.then.i40 ], [ 0, %land.lhs.true5.i ], [ 0, %land.lhs.true.i ] ; <i8> [#uses=3]
%tobool.i46 = icmp eq i8 %tmp2.i44, 0 ; <i1> [#uses=1]
%cmp.i49 = icmp eq i32 %conv.i.i, 6 ; <i1> [#uses=1]
%or.cond = and i1 %tobool.i46, %cmp.i49 ; <i1> [#uses=1]
br i1 %or.cond, label %land.lhs.true5.i55, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60
land.lhs.true5.i55: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
%call.i53 = call i32 @memcmp(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str2, i64 0, i64 0), i8* %tmp6, i64 7) nounwind ; <i32> [#uses=1]
%cmp9.i54 = icmp eq i32 %call.i53, 0 ; <i1> [#uses=1]
br i1 %cmp9.i54, label %if.then.i58, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60
if.then.i58: ; preds = %land.lhs.true5.i55
br label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60
_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60: ; preds = %if.then.i58, %land.lhs.true5.i55, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit
%retval.0.i.pre158 = phi i32 [ %retval.0.i.pre159, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit ], [ %retval.0.i.pre159, %land.lhs.true5.i55 ], [ 3, %if.then.i58 ] ; <i32> [#uses=2]
%tmp2.i63 = phi i8 [ %tmp2.i44, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit ], [ %tmp2.i44, %land.lhs.true5.i55 ], [ 1, %if.then.i58 ] ; <i8> [#uses=3]
%tmp14.i64 = and i8 %tmp2.i63, 1 ; <i8> [#uses=1]
%tobool.i65 = icmp eq i8 %tmp14.i64, 0 ; <i1> [#uses=1]
%cmp.i68 = icmp eq i32 %conv.i.i, 5 ; <i1> [#uses=1]
%or.cond168 = and i1 %tobool.i65, %cmp.i68 ; <i1> [#uses=1]
br i1 %or.cond168, label %land.lhs.true5.i74, label %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit
land.lhs.true5.i74: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60
%call.i72 = call i32 @memcmp(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str3, i64 0, i64 0), i8* %tmp6, i64 6) nounwind ; <i32> [#uses=1]
%cmp9.i73 = icmp eq i32 %call.i72, 0 ; <i1> [#uses=1]
br i1 %cmp9.i73, label %if.then.i77, label %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit
if.then.i77: ; preds = %land.lhs.true5.i74
br label %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit
_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit: ; preds = %if.then.i77, %land.lhs.true5.i74, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60
%retval.0.i.pre157 = phi i32 [ %retval.0.i.pre158, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60 ], [ %retval.0.i.pre158, %land.lhs.true5.i74 ], [ 4, %if.then.i77 ] ; <i32> [#uses=2]
%tmp2.i81 = phi i8 [ %tmp2.i63, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit60 ], [ %tmp2.i63, %land.lhs.true5.i74 ], [ 1, %if.then.i77 ] ; <i8> [#uses=3]
%tmp14.i82 = and i8 %tmp2.i81, 1 ; <i8> [#uses=1]
%tobool.i83 = icmp eq i8 %tmp14.i82, 0 ; <i1> [#uses=1]
%cmp.i86 = icmp eq i32 %conv.i.i, 4 ; <i1> [#uses=1]
%or.cond169 = and i1 %tobool.i83, %cmp.i86 ; <i1> [#uses=1]
br i1 %or.cond169, label %land.lhs.true5.i92, label %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit
land.lhs.true5.i92: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit
%call.i90 = call i32 @memcmp(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str4, i64 0, i64 0), i8* %tmp6, i64 5) nounwind ; <i32> [#uses=1]
%cmp9.i91 = icmp eq i32 %call.i90, 0 ; <i1> [#uses=1]
br i1 %cmp9.i91, label %if.then.i95, label %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit
if.then.i95: ; preds = %land.lhs.true5.i92
br label %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit
_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit: ; preds = %if.then.i95, %land.lhs.true5.i92, %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit
%retval.0.i.pre156 = phi i32 [ %retval.0.i.pre157, %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit ], [ %retval.0.i.pre157, %land.lhs.true5.i92 ], [ 5, %if.then.i95 ] ; <i32> [#uses=2]
%tmp2.i99 = phi i8 [ %tmp2.i81, %_ZN12StringSwitchI5ColorE4CaseILj6EEERS1_RAT__KcRKS0_.exit ], [ %tmp2.i81, %land.lhs.true5.i92 ], [ 1, %if.then.i95 ] ; <i8> [#uses=3]
%tmp14.i100 = and i8 %tmp2.i99, 1 ; <i8> [#uses=1]
%tobool.i101 = icmp eq i8 %tmp14.i100, 0 ; <i1> [#uses=1]
%cmp.i104 = icmp eq i32 %conv.i.i, 6 ; <i1> [#uses=1]
%or.cond170 = and i1 %tobool.i101, %cmp.i104 ; <i1> [#uses=1]
br i1 %or.cond170, label %land.lhs.true5.i110, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115
land.lhs.true5.i110: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit
%call.i108 = call i32 @memcmp(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str5, i64 0, i64 0), i8* %tmp6, i64 7) nounwind ; <i32> [#uses=1]
%cmp9.i109 = icmp eq i32 %call.i108, 0 ; <i1> [#uses=1]
br i1 %cmp9.i109, label %if.then.i113, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115
if.then.i113: ; preds = %land.lhs.true5.i110
br label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115
_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115: ; preds = %if.then.i113, %land.lhs.true5.i110, %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit
%retval.0.i.pre155 = phi i32 [ %retval.0.i.pre156, %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit ], [ %retval.0.i.pre156, %land.lhs.true5.i110 ], [ 6, %if.then.i113 ] ; <i32> [#uses=2]
%tmp2.i118 = phi i8 [ %tmp2.i99, %_ZN12StringSwitchI5ColorE4CaseILj5EEERS1_RAT__KcRKS0_.exit ], [ %tmp2.i99, %land.lhs.true5.i110 ], [ 1, %if.then.i113 ] ; <i8> [#uses=3]
%tmp14.i119 = and i8 %tmp2.i118, 1 ; <i8> [#uses=1]
%tobool.i120 = icmp eq i8 %tmp14.i119, 0 ; <i1> [#uses=1]
%cmp.i123 = icmp eq i32 %conv.i.i, 6 ; <i1> [#uses=1]
%or.cond171 = and i1 %tobool.i120, %cmp.i123 ; <i1> [#uses=1]
br i1 %or.cond171, label %land.lhs.true5.i129, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134
land.lhs.true5.i129: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115
%call.i127 = call i32 @memcmp(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str6, i64 0, i64 0), i8* %tmp6, i64 7) nounwind ; <i32> [#uses=1]
%cmp9.i128 = icmp eq i32 %call.i127, 0 ; <i1> [#uses=1]
br i1 %cmp9.i128, label %if.then.i132, label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134
if.then.i132: ; preds = %land.lhs.true5.i129
br label %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134
_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134: ; preds = %if.then.i132, %land.lhs.true5.i129, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115
%retval.0.i.pre = phi i32 [ %retval.0.i.pre155, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115 ], [ %retval.0.i.pre155, %land.lhs.true5.i129 ], [ 7, %if.then.i132 ] ; <i32> [#uses=2]
%tmp2.i137 = phi i8 [ %tmp2.i118, %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit115 ], [ %tmp2.i118, %land.lhs.true5.i129 ], [ 1, %if.then.i132 ] ; <i8> [#uses=1]
%tmp7.i138 = and i8 %tmp2.i137, 1 ; <i8> [#uses=1]
%tobool.i139 = icmp eq i8 %tmp7.i138, 0 ; <i1> [#uses=1]
%retval.0.i = select i1 %tobool.i139, i32 0, i32 %retval.0.i.pre ; <i32> [#uses=1]
%call22 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str7, i64 0, i64 0), i32 %retval.0.i) ; <i32> [#uses=0]
%exitcond = icmp eq i64 %tmp146, %tmp145 ; <i1> [#uses=1]
br i1 %exitcond, label %for.end, label %land.lhs.true.i
for.end: ; preds = %_ZN12StringSwitchI5ColorE4CaseILj7EEERS1_RAT__KcRKS0_.exit134, %entry
ret i32 0
}
declare i32 @printf(i8* nocapture, ...) nounwind
declare i32 @memcmp(i8* nocapture, i8* nocapture, i64) nounwind readonly
declare i64 @strlen(i8* nocapture) nounwind readonly

View File

@ -0,0 +1,32 @@
; RUN: opt < %s -jump-threading
; PR9446
; Just check that it doesn't crash
define void @int327() nounwind {
entry:
unreachable
for.cond: ; preds = %for.cond4
%tobool3 = icmp eq i8 undef, 0
br i1 %tobool3, label %for.cond23, label %for.cond4
for.cond4: ; preds = %for.cond
br label %for.cond
for.cond23: ; preds = %for.body28, %for.cond23, %for.cond
%conv321 = phi i32 [ %conv32, %for.body28 ], [ 0, %for.cond ], [ %conv321, %for.cond23 ]
%l_266.0 = phi i32 [ %phitmp, %for.body28 ], [ 0, %for.cond ], [ 0, %for.cond23 ]
%cmp26 = icmp eq i32 %l_266.0, 0
br i1 %cmp26, label %for.body28, label %for.cond23
for.body28: ; preds = %for.cond23
%and = and i32 %conv321, 1
%conv32 = zext i8 undef to i32
%add = add nsw i32 %l_266.0, 1
%phitmp = and i32 %add, 255
br label %for.cond23
if.end43: ; No predecessors!
ret void
}

View File

@ -0,0 +1,27 @@
; RUN: opt -jump-threading < %s
; <rdar://problem/9284786>
%0 = type <{ i64, i16, i64, i8, i8 }>
@g_338 = external global %0, align 8
define void @func_1() nounwind ssp {
entry:
ret void
for.cond1177:
%inc1187 = add nsw i32 0, 1
%cmp1179 = icmp slt i32 %inc1187, 5
br i1 %cmp1179, label %for.cond1177, label %land.rhs1320
land.rhs1320:
%tmp1324 = load volatile i64, i64* getelementptr inbounds (%0, %0* @g_338, i64 0, i32 2), align 1
br label %if.end.i
if.end.i:
%tobool.pr.i = phi i1 [ false, %if.end.i ], [ false, %land.rhs1320 ]
br i1 %tobool.pr.i, label %return, label %if.end.i
return:
ret void
}

View File

@ -0,0 +1,8 @@
; RUN: opt < %s -jump-threading
; PR 13405
; Just check that it doesn't crash / assert
define i32 @f() nounwind {
entry:
indirectbr i8* undef, []
}

View File

@ -0,0 +1,37 @@
; RUN: opt < %s -jump-threading -mem2reg -instcombine -simplifycfg -S | FileCheck %s
declare i32 @f1()
declare i32 @f2()
declare void @f3()
define i32 @test(i1 %cond, i1 %cond2, i1 %cond3) {
; CHECK: test
br i1 %cond, label %T1, label %F1
; CHECK-NOT: T1:
T1:
%v1 = call i32 @f1()
br label %Merge
F1:
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge:
; CHECK: %v1 = call i32 @f1()
; CHECK-NEXT: %D = and i1 %cond2, %cond3
; CHECK-NEXT: br i1 %D
%A = phi i1 [true, %T1], [false, %F1]
%B = phi i32 [%v1, %T1], [%v2, %F1]
%C = and i1 %A, %cond2
%D = and i1 %C, %cond3
br i1 %D, label %T2, label %F2
T2:
call void @f3()
ret i32 %B
F2:
ret i32 %B
}

View File

@ -0,0 +1,35 @@
; RUN: opt < %s -jump-threading -mem2reg -instcombine -simplifycfg -S | FileCheck %s
declare i32 @f1()
declare i32 @f2()
declare void @f3()
define i32 @test(i1 %cond, i1 %cond2) {
; CHECK: test
br i1 %cond, label %T1, label %F1
; CHECK-NOT: T1
T1:
%v1 = call i32 @f1()
br label %Merge
F1:
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge:
; CHECK: %v1 = call i32 @f1()
; CHECK-NEXT: br i1 %cond2
%A = phi i1 [true, %T1], [false, %F1]
%B = phi i32 [%v1, %T1], [%v2, %F1]
%C = and i1 %A, %cond2
br i1 %C, label %T2, label %F2
T2:
call void @f3()
ret i32 %B
F2:
ret i32 %B
}

View File

@ -0,0 +1,39 @@
; RUN: opt -S -jump-threading < %s | FileCheck %s
declare i8* @escape()
declare void @llvm.assume(i1)
define i1 @test1(i1 %cond) {
entry:
br i1 %cond, label %taken, label %not_taken
; CHECK-LABEL: @test1
; CHECK: br i1 %cond, label %no, label %yes
; CHECK: ret i1 true
taken:
%res1 = call i8* @escape()
%a = icmp eq i8* %res1, null
tail call void @llvm.assume(i1 %a)
br label %done
not_taken:
%res2 = call i8* @escape()
%b = icmp ne i8* %res2, null
tail call void @llvm.assume(i1 %b)
br label %done
; An assume that can be used to simplify this comparison dominates each
; predecessor branch (although no assume dominates the cmp itself). Make sure
; this still can be simplified.
done:
%res = phi i8* [ %res1, %taken ], [ %res2, %not_taken ]
%cnd = icmp ne i8* %res, null
br i1 %cnd, label %yes, label %no
yes:
ret i1 true
no:
ret i1 false
}

View File

@ -0,0 +1,241 @@
; RUN: opt -S -jump-threading -dce < %s | FileCheck %s
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: nounwind uwtable
define i32 @test1(i32 %a, i32 %b) #0 {
entry:
%cmp = icmp sgt i32 %a, 5
tail call void @llvm.assume(i1 %cmp)
%cmp1 = icmp sgt i32 %b, 1234
br i1 %cmp1, label %if.then, label %if.else
; CHECK-LABEL: @test1
; CHECK: icmp sgt i32 %a, 5
; CHECK: call void @llvm.assume
; CHECK-NOT: icmp sgt i32 %a, 3
; CHECK: ret i32
if.then: ; preds = %entry
%cmp2 = icmp sgt i32 %a, 3
br i1 %cmp2, label %if.then3, label %return
if.then3: ; preds = %if.then
tail call void (...) @bar() #1
br label %return
if.else: ; preds = %entry
tail call void (...) @car() #1
br label %return
return: ; preds = %if.else, %if.then, %if.then3
%retval.0 = phi i32 [ 1, %if.then3 ], [ 0, %if.then ], [ 0, %if.else ]
ret i32 %retval.0
}
define i32 @test2(i32 %a) #0 {
entry:
%cmp = icmp sgt i32 %a, 5
tail call void @llvm.assume(i1 %cmp)
%cmp1 = icmp sgt i32 %a, 3
br i1 %cmp1, label %if.then, label %return
; CHECK-LABEL: @test2
; CHECK: icmp sgt i32 %a, 5
; CHECK: tail call void @llvm.assume
; CHECK: tail call void (...) @bar()
; CHECK: ret i32 1
if.then: ; preds = %entry
tail call void (...) @bar() #1
br label %return
return: ; preds = %entry, %if.then
%retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
ret i32 %retval.0
}
@g = external global i32
; Check that we do prove a fact using an assume within the block.
; We can fold the assume based on the semantics of assume.
define void @can_fold_assume(i32* %array) {
; CHECK-LABEL: @can_fold_assume
; CHECK-NOT: call void @llvm.assume
; CHECK-NOT: br
; CHECK: ret void
%notnull = icmp ne i32* %array, null
call void @llvm.assume(i1 %notnull)
br i1 %notnull, label %normal, label %error
normal:
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
declare void @f(i1)
declare void @exit()
; We can fold the assume but not the uses before the assume.
define void @cannot_fold_use_before_assume(i32* %array) {
; CHECK-LABEL:@cannot_fold_use_before_assume
; CHECK: @f(i1 %notnull)
; CHECK-NEXT: exit()
; CHECK-NOT: assume
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @f(i1 %notnull)
call void @exit()
call void @llvm.assume(i1 %notnull)
br i1 %notnull, label %normal, label %error
normal:
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
declare void @dummy(i1) nounwind argmemonly
define void @can_fold_some_use_before_assume(i32* %array) {
; CHECK-LABEL:@can_fold_some_use_before_assume
; CHECK: @f(i1 %notnull)
; CHECK-NEXT: @dummy(i1 true)
; CHECK-NOT: assume
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @f(i1 %notnull)
call void @dummy(i1 %notnull)
call void @llvm.assume(i1 %notnull)
br i1 %notnull, label %normal, label %error
normal:
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
; FIXME: can fold assume and all uses before/after assume.
; because the trapping exit call is after the assume.
define void @can_fold_assume_and_all_uses(i32* %array) {
; CHECK-LABEL:@can_fold_assume_and_all_uses
; CHECK: @dummy(i1 %notnull)
; CHECK-NEXT: assume(i1 %notnull)
; CHECK-NEXT: exit()
; CHECK-NEXT: %notnull2 = or i1 true, false
; CHECK-NEXT: @f(i1 %notnull2)
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @dummy(i1 %notnull)
call void @llvm.assume(i1 %notnull)
call void @exit()
br i1 %notnull, label %normal, label %error
normal:
%notnull2 = or i1 %notnull, false
call void @f(i1 %notnull2)
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
declare void @fz(i8)
; FIXME: We can fold assume to true, and the use after assume, but we do not do so
; currently, because of the function call after the assume.
define void @can_fold_assume2(i32* %array) {
; CHECK-LABEL:@can_fold_assume2
; CHECK: @f(i1 %notnull)
; CHECK-NEXT: assume(i1 %notnull)
; CHECK-NEXT: znotnull = zext i1 %notnull to i8
; CHECK-NEXT: @f(i1 %notnull)
; CHECK-NEXT: @f(i1 true)
; CHECK-NEXT: @fz(i8 %znotnull)
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @f(i1 %notnull)
call void @llvm.assume(i1 %notnull)
%znotnull = zext i1 %notnull to i8
call void @f(i1 %notnull)
br i1 %notnull, label %normal, label %error
normal:
call void @f(i1 %notnull)
call void @fz(i8 %znotnull)
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
declare void @llvm.experimental.guard(i1, ...)
; FIXME: We can fold assume to true, but we do not do so
; because of the guard following the assume.
define void @can_fold_assume3(i32* %array){
; CHECK-LABEL:@can_fold_assume3
; CHECK: @f(i1 %notnull)
; CHECK-NEXT: assume(i1 %notnull)
; CHECK-NEXT: guard(i1 %notnull)
; CHECK-NEXT: znotnull = zext i1 true to i8
; CHECK-NEXT: @f(i1 true)
; CHECK-NEXT: @fz(i8 %znotnull)
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @f(i1 %notnull)
call void @llvm.assume(i1 %notnull)
call void(i1, ...) @llvm.experimental.guard(i1 %notnull) [ "deopt"() ]
%znotnull = zext i1 %notnull to i8
br i1 %notnull, label %normal, label %error
normal:
call void @f(i1 %notnull)
call void @fz(i8 %znotnull)
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
; can fold all uses and remove the cond
define void @can_fold_assume4(i32* %array) {
; CHECK-LABEL: can_fold_assume4
; CHECK-NOT: notnull
; CHECK: dummy(i1 true)
; CHECK-NEXT: ret void
%notnull = icmp ne i32* %array, null
call void @exit()
call void @dummy(i1 %notnull)
call void @llvm.assume(i1 %notnull)
br i1 %notnull, label %normal, label %error
normal:
ret void
error:
store atomic i32 0, i32* @g unordered, align 4
ret void
}
; Function Attrs: nounwind
declare void @llvm.assume(i1) #1
declare void @bar(...)
declare void @car(...)
attributes #0 = { nounwind uwtable }
attributes #1 = { nounwind }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
; RUN: opt < %s -jump-threading -S | not grep phi
declare i8 @mcguffin()
define i32 @test(i1 %foo, i8 %b) {
entry:
%a = call i8 @mcguffin()
br i1 %foo, label %bb1, label %bb2
bb1:
br label %jt
bb2:
br label %jt
jt:
%x = phi i8 [%a, %bb1], [%b, %bb2]
%A = icmp eq i8 %x, %a
br i1 %A, label %rt, label %rf
rt:
ret i32 7
rf:
ret i32 8
}

View File

@ -0,0 +1,30 @@
; There should be no phi nodes left.
; RUN: opt < %s -jump-threading -S | not grep "phi i32"
declare i32 @f1()
declare i32 @f2()
declare void @f3()
define i32 @test(i1 %cond) {
br i1 %cond, label %T1, label %F1
T1:
%v1 = call i32 @f1()
br label %Merge
F1:
%v2 = call i32 @f2()
br label %Merge
Merge:
%B = phi i32 [%v1, %T1], [12, %F1]
%A = icmp ne i32 %B, 42
br i1 %A, label %T2, label %F2
T2:
call void @f3()
ret i32 1
F2:
ret i32 0
}

View File

@ -0,0 +1,58 @@
; RUN: opt -jump-threading -S %s | FileCheck %s
; Check that we thread arg2neg -> checkpos -> end.
;
; LazyValueInfo would previously fail to analyze the value of %arg in arg2neg
; because its predecessing blocks (checkneg) hadn't been processed yet (PR21238)
; CHECK-LABEL: @test_jump_threading
; CHECK: arg2neg:
; CHECK-NEXT: br i1 %arg1, label %end, label %checkpos.thread
; CHECK: checkpos.thread:
; CHECK-NEXT: br label %end
define i32 @test_jump_threading(i1 %arg1, i32 %arg2) {
checkneg:
%cmp = icmp slt i32 %arg2, 0
br i1 %cmp, label %arg2neg, label %checkpos
arg2neg:
br i1 %arg1, label %end, label %checkpos
checkpos:
%cmp2 = icmp sgt i32 %arg2, 0
br i1 %cmp2, label %arg2pos, label %end
arg2pos:
br label %end
end:
%0 = phi i32 [ 1, %arg2neg ], [ 2, %checkpos ], [ 3, %arg2pos ]
ret i32 %0
}
; arg2neg has an edge back to itself. If LazyValueInfo is not careful when
; visiting predecessors, it could get into an infinite loop.
; CHECK-LABEL: test_infinite_loop
define i32 @test_infinite_loop(i1 %arg1, i32 %arg2) {
checkneg:
%cmp = icmp slt i32 %arg2, 0
br i1 %cmp, label %arg2neg, label %checkpos
arg2neg:
br i1 %arg1, label %arg2neg, label %checkpos
checkpos:
%cmp2 = icmp sgt i32 %arg2, 0
br i1 %cmp2, label %arg2pos, label %end
arg2pos:
br label %end
end:
%0 = phi i32 [ 2, %checkpos ], [ 3, %arg2pos ]
ret i32 %0
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
; RUN: opt < %s -jump-threading -disable-output -verify-dom-info
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@global = external local_unnamed_addr global i64, align 8
@global.1 = external local_unnamed_addr global i64, align 8
@global.2 = external local_unnamed_addr global i64, align 8
; Function Attrs: norecurse noreturn nounwind uwtable
define void @hoge() local_unnamed_addr #0 {
bb:
br label %bb1
bb1: ; preds = %bb26, %bb
%tmp = load i64, i64* @global, align 8, !tbaa !1
%tmp2 = icmp eq i64 %tmp, 0
br i1 %tmp2, label %bb27, label %bb3
bb3: ; preds = %bb1
%tmp4 = load i64, i64* @global.1, align 8, !tbaa !1
%tmp5 = icmp eq i64 %tmp4, 0
br i1 %tmp5, label %bb23, label %bb23
bb23: ; preds = %bb3, %bb3
br label %bb26
bb26: ; preds = %bb27, %bb23
br label %bb1
bb27: ; preds = %bb1
br label %bb26
}
attributes #0 = { norecurse noreturn nounwind 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" }
!llvm.ident = !{!0}
!0 = !{!"clang version 7.0.0 "}
!1 = !{!2, !2, i64 0}
!2 = !{!"long", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C/C++ TBAA"}

View File

@ -0,0 +1,75 @@
; RUN: opt < %s -jump-threading -disable-output -verify-dom-info
@global = external global i64, align 8
define void @f() {
bb:
br label %bb1
bb1:
%tmp = load i64, i64* @global, align 8
%tmp2 = icmp eq i64 %tmp, 0
br i1 %tmp2, label %bb27, label %bb3
bb3:
%tmp4 = load i64, i64* @global, align 8
%tmp5 = icmp eq i64 %tmp4, 0
br i1 %tmp5, label %bb6, label %bb7
bb6:
br label %bb7
bb7:
%tmp8 = phi i1 [ true, %bb3 ], [ undef, %bb6 ]
%tmp9 = select i1 %tmp8, i64 %tmp4, i64 0
br i1 false, label %bb10, label %bb23
bb10:
%tmp11 = load i64, i64* @global, align 8
%tmp12 = icmp slt i64 %tmp11, 5
br i1 %tmp12, label %bb13, label %bb17
bb13:
br label %bb14
bb14:
br i1 undef, label %bb15, label %bb16
bb15:
unreachable
bb16:
br label %bb10
bb17:
br label %bb18
bb18:
br i1 undef, label %bb22, label %bb13
bb19:
br i1 undef, label %bb20, label %bb21
bb20:
unreachable
bb21:
br label %bb18
bb22:
br label %bb23
bb23:
br i1 undef, label %bb24, label %bb13
bb24:
br i1 undef, label %bb26, label %bb25
bb25:
br label %bb19
bb26:
br label %bb1
bb27:
br label %bb24
}

View File

@ -0,0 +1,24 @@
; RUN: opt -jump-threading -disable-output < %s
; PR9112
; This is actually a test for value tracking. Jump threading produces
; "%phi = phi i16" when it removes all edges leading to %unreachable.
; The .ll parser won't let us write that directly since it's invalid code.
define void @func() nounwind {
entry:
br label %bb
bb:
br label %bb
unreachable:
%phi = phi i16 [ %add, %unreachable ], [ 0, %next ]
%add = add i16 0, %phi
%cmp = icmp slt i16 %phi, 0
br i1 %cmp, label %unreachable, label %next
next:
br label %unreachable
}

View File

@ -0,0 +1,246 @@
; RUN: opt -jump-threading -S -verify < %s | FileCheck %s
declare i32 @f1()
declare i32 @f2()
declare void @f3()
declare void @f4(i32)
; Make sure we update the phi node properly.
;
; CHECK-LABEL: define void @test_br_folding_not_threading_update_phi(
; CHECK: br label %L1
; Make sure we update the phi node properly here, i.e. we only have 2 predecessors, entry and L0
; CHECK: %res.0 = phi i32 [ 0, %L0 ], [ 1, %entry ]
define void @test_br_folding_not_threading_update_phi(i32 %val) nounwind {
entry:
%cmp = icmp eq i32 %val, 32
br i1 %cmp, label %L0, label %L1
L0:
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
switch i32 %val, label %L2 [
i32 0, label %L1
i32 32, label %L1
]
L1:
%res.0 = phi i32 [ 0, %L0 ], [ 0, %L0 ], [1, %entry]
call void @f4(i32 %res.0)
ret void
L2:
call void @f3()
ret void
}
; Make sure we can fold this branch ... We will not be able to thread it as
; L0 is too big to duplicate. L2 is the unreachable block here.
;
; CHECK-LABEL: @test_br_folding_not_threading(
; CHECK: L1:
; CHECK: call i32 @f2()
; CHECK: call void @f3()
; CHECK-NEXT: ret void
; CHECK-NOT: br
; CHECK: L3:
define void @test_br_folding_not_threading(i1 %cond) nounwind {
entry:
br i1 %cond, label %L0, label %L3
L0:
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
br i1 %cond, label %L1, label %L2
L1:
call void @f3()
ret void
L2:
call void @f3()
ret void
L3:
call void @f3()
ret void
}
; Make sure we can fold this branch ... We will not be able to thread it as
; L0 is too big to duplicate. L2 is the unreachable block here.
; With more than 1 predecessors.
;
; CHECK-LABEL: @test_br_folding_not_threading_multiple_preds(
; CHECK: L1:
; CHECK: call i32 @f2()
; CHECK: call void @f3()
; CHECK-NEXT: ret void
; CHECK-NOT: br
; CHECK: L3:
define void @test_br_folding_not_threading_multiple_preds(i1 %condx, i1 %cond) nounwind {
entry:
br i1 %condx, label %X0, label %X1
X0:
br i1 %cond, label %L0, label %L3
X1:
br i1 %cond, label %L0, label %L3
L0:
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
br i1 %cond, label %L1, label %L2
L1:
call void @f3()
ret void
L2:
call void @f3()
ret void
L3:
call void @f3()
ret void
}
; Make sure we can do the RAUW for %add...
;
; CHECK-LABEL: @rauw_if_possible(
; CHECK: call void @f4(i32 96)
define void @rauw_if_possible(i32 %value) nounwind {
entry:
%cmp = icmp eq i32 %value, 32
br i1 %cmp, label %L0, label %L3
L0:
call i32 @f2()
call i32 @f2()
%add = add i32 %value, 64
switch i32 %add, label %L3 [
i32 32, label %L1
i32 96, label %L2
]
L1:
call void @f3()
ret void
L2:
call void @f4(i32 %add)
ret void
L3:
call void @f3()
ret void
}
; Make sure we can NOT do the RAUW for %add...
;
; CHECK-LABEL: @rauw_if_possible2(
; CHECK: call void @f4(i32 %add)
define void @rauw_if_possible2(i32 %value) nounwind {
entry:
%cmp = icmp eq i32 %value, 32
%add = add i32 %value, 64
br i1 %cmp, label %L0, label %L2
L0:
call i32 @f2()
call i32 @f2()
switch i32 %add, label %L3 [
i32 32, label %L1
i32 96, label %L2
]
L1:
call void @f3()
ret void
L2:
call void @f4(i32 %add)
ret void
L3:
call void @f3()
ret void
}
; Make sure we can fold this branch ... We will not be able to thread it as
; L0 is too big to duplicate.
; We do not attempt to rewrite the indirectbr target here, but we still take
; its target after L0 into account and that enables us to fold.
;
; L2 is the unreachable block here.
;
; CHECK-LABEL: @test_br_folding_not_threading_indirect_branch(
; CHECK: L1:
; CHECK: call i32 @f2()
; CHECK: call void @f3()
; CHECK-NEXT: ret void
; CHECK-NOT: br
; CHECK: L3:
define void @test_br_folding_not_threading_indirect_branch(i1 %condx, i1 %cond) nounwind {
entry:
br i1 %condx, label %X0, label %X1
X0:
br i1 %cond, label %L0, label %L3
X1:
br i1 %cond, label %XX1, label %L3
XX1:
indirectbr i8* blockaddress(@test_br_folding_not_threading_indirect_branch, %L0), [label %L0]
L0:
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
call i32 @f2()
br i1 %cond, label %L1, label %L2
L1:
call void @f3()
ret void
L2:
call void @f3()
ret void
L3:
call void @f3()
ret void
}

View File

@ -0,0 +1,383 @@
; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
declare void @llvm.experimental.guard(i1, ...)
declare i32 @f1()
declare i32 @f2()
define i32 @branch_implies_guard(i32 %a) {
; CHECK-LABEL: @branch_implies_guard(
%cond = icmp slt i32 %a, 10
br i1 %cond, label %T1, label %F1
T1:
; CHECK: T1.split
; CHECK: %v1 = call i32 @f1()
; CHECK-NEXT: %retVal
; CHECK-NEXT: br label %Merge
%v1 = call i32 @f1()
br label %Merge
F1:
; CHECK: F1.split
; CHECK: %v2 = call i32 @f2()
; CHECK-NEXT: %retVal
; CHECK-NEXT: %condGuard
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
; CHECK-NEXT: br label %Merge
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge
; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard(
%retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
%retVal = add i32 %retPhi, 10
%condGuard = icmp slt i32 %a, 20
call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
ret i32 %retVal
}
define i32 @not_branch_implies_guard(i32 %a) {
; CHECK-LABEL: @not_branch_implies_guard(
%cond = icmp slt i32 %a, 20
br i1 %cond, label %T1, label %F1
T1:
; CHECK: T1.split:
; CHECK-NEXT: %v1 = call i32 @f1()
; CHECK-NEXT: %retVal
; CHECK-NEXT: %condGuard
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
; CHECK-NEXT: br label %Merge
%v1 = call i32 @f1()
br label %Merge
F1:
; CHECK: F1.split:
; CHECK-NEXT: %v2 = call i32 @f2()
; CHECK-NEXT: %retVal
; CHECK-NEXT: br label %Merge
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge
; CHECK-NOT: call void(i1, ...) @llvm.experimental.guard(
%retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
%retVal = add i32 %retPhi, 10
%condGuard = icmp sgt i32 %a, 10
call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
ret i32 %retVal
}
define i32 @branch_overlaps_guard(i32 %a) {
; CHECK-LABEL: @branch_overlaps_guard(
%cond = icmp slt i32 %a, 20
br i1 %cond, label %T1, label %F1
T1:
; CHECK: T1:
; CHECK-NEXT: %v1 = call i32 @f1()
; CHECK-NEXT: br label %Merge
%v1 = call i32 @f1()
br label %Merge
F1:
; CHECK: F1:
; CHECK-NEXT: %v2 = call i32 @f2()
; CHECK-NEXT: br label %Merge
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge
; CHECK: %condGuard = icmp slt i32 %a, 10
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
%retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
%retVal = add i32 %retPhi, 10
%condGuard = icmp slt i32 %a, 10
call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
ret i32 %retVal
}
define i32 @branch_doesnt_overlap_guard(i32 %a) {
; CHECK-LABEL: @branch_doesnt_overlap_guard(
%cond = icmp slt i32 %a, 10
br i1 %cond, label %T1, label %F1
T1:
; CHECK: T1:
; CHECK-NEXT: %v1 = call i32 @f1()
; CHECK-NEXT: br label %Merge
%v1 = call i32 @f1()
br label %Merge
F1:
; CHECK: F1:
; CHECK-NEXT: %v2 = call i32 @f2()
; CHECK-NEXT: br label %Merge
%v2 = call i32 @f2()
br label %Merge
Merge:
; CHECK: Merge
; CHECK: %condGuard = icmp sgt i32 %a, 20
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
%retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
%retVal = add i32 %retPhi, 10
%condGuard = icmp sgt i32 %a, 20
call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
ret i32 %retVal
}
define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
; CHECK-LABEL: @not_a_diamond1(
br i1 %cond1, label %Pred, label %Exit
Pred:
; CHECK: Pred:
; CHECK-NEXT: switch i32 %a, label %Exit
switch i32 %a, label %Exit [
i32 10, label %Merge
i32 20, label %Merge
]
Merge:
; CHECK: Merge:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
; CHECK-NEXT: br label %Exit
call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
br label %Exit
Exit:
; CHECK: Exit:
; CHECK-NEXT: ret i32 %a
ret i32 %a
}
define void @not_a_diamond2(i32 %a, i1 %cond1) {
; CHECK-LABEL: @not_a_diamond2(
br label %Parent
Merge:
call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
ret void
Pred:
; CHECK-NEXT: Pred:
; CHECK-NEXT: switch i32 %a, label %Exit
switch i32 %a, label %Exit [
i32 10, label %Merge
i32 20, label %Merge
]
Parent:
br label %Pred
Exit:
; CHECK: Merge:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
; CHECK-NEXT: ret void
ret void
}
declare void @never_called(i1)
; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that
; guard with guard(true & c1).
define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) {
; CHECK-LABEL: dont_fold_guard
; CHECK: %wide.chk = and i1 %c1, %c2
; CHECK-NEXT: experimental.guard(i1 %wide.chk)
; CHECK-NEXT: call void @never_called(i1 true)
; CHECK-NEXT: ret void
%c1 = icmp ult i32 %i, %length
%c2 = icmp eq i32 %i, 0
%wide.chk = and i1 %c1, %c2
call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
br i1 %c2, label %BB1, label %BB2
BB1:
call void @never_called(i1 %c2)
ret void
BB2:
ret void
}
declare void @dummy(i1) nounwind argmemonly
; same as dont_fold_guard1 but there's a use immediately after guard and before
; branch. We can fold that use.
define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) {
; CHECK-LABEL: dont_fold_guard2
; CHECK: %wide.chk = and i1 %c1, %c2
; CHECK-NEXT: experimental.guard(i1 %wide.chk)
; CHECK-NEXT: dummy(i1 true)
; CHECK-NEXT: call void @never_called(i1 true)
; CHECK-NEXT: ret void
%c1 = icmp ult i32 %i, %length
%c2 = icmp eq i32 %i, 0
%wide.chk = and i1 %c1, %c2
call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
call void @dummy(i1 %c2)
br i1 %c2, label %BB1, label %BB2
BB1:
call void @never_called(i1 %c2)
ret void
BB2:
ret void
}
; same as dont_fold_guard1 but condition %cmp is not an instruction.
; We cannot fold the guard under any circumstance.
; FIXME: We can merge unreachableBB2 into not_zero.
define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) {
; CHECK-LABEL: dont_fold_guard3
; CHECK: guard(i1 %cmp)
call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
br i1 %cmp, label %BB1, label %BB2
BB1:
call void @never_called(i1 %cmp)
ret void
BB2:
ret void
}
declare void @f(i1)
; Same as dont_fold_guard1 but use switch instead of branch.
; triggers source code `ProcessThreadableEdges`.
define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind {
; CHECK-LABEL: dont_fold_guard4
; CHECK-LABEL: L2:
; CHECK-NEXT: %cmp = icmp eq i32 %i, 0
; CHECK-NEXT: guard(i1 %cmp)
; CHECK-NEXT: dummy(i1 true)
; CHECK-NEXT: @f(i1 true)
; CHECK-NEXT: ret void
entry:
br i1 %cmp1, label %L0, label %L3
L0:
%cmp = icmp eq i32 %i, 0
call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
call void @dummy(i1 %cmp)
switch i1 %cmp, label %L3 [
i1 false, label %L1
i1 true, label %L2
]
L1:
ret void
L2:
call void @f(i1 %cmp)
ret void
L3:
ret void
}
; Make sure that we don't PRE a non-speculable load across a guard.
define void @unsafe_pre_across_guard(i8* %p, i1 %load.is.valid) {
; CHECK-LABEL: @unsafe_pre_across_guard(
; CHECK-NOT: loaded.pr
; CHECK: entry:
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
; CHECK-NEXT: %loaded = load i8, i8* %p
; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0
; CHECK-NEXT: br i1 %continue, label %exit, label %loop
entry:
br label %loop
loop: ; preds = %loop, %entry
call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
%loaded = load i8, i8* %p
%continue = icmp eq i8 %loaded, 0
br i1 %continue, label %exit, label %loop
exit: ; preds = %loop
ret void
}
; Make sure that we can safely PRE a speculable load across a guard.
define void @safe_pre_across_guard(i8* noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) {
; CHECK-LABEL: @safe_pre_across_guard(
; CHECK: entry:
; CHECK-NEXT: %loaded.pr = load i8, i8* %p
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0
; CHECK-NEXT: br i1 %continue, label %exit, label %loop
entry:
br label %loop
loop: ; preds = %loop, %entry
call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
%loaded = load i8, i8* %p
%continue = icmp eq i8 %loaded, 0
br i1 %continue, label %exit, label %loop
exit: ; preds = %loop
ret void
}
; Make sure that we don't PRE a non-speculable load across a call which may
; alias with the load.
define void @unsafe_pre_across_call(i8* %p) {
; CHECK-LABEL: @unsafe_pre_across_call(
; CHECK-NOT: loaded.pr
; CHECK: entry:
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: call i32 @f1()
; CHECK-NEXT: %loaded = load i8, i8* %p
; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0
; CHECK-NEXT: br i1 %continue, label %exit, label %loop
entry:
br label %loop
loop: ; preds = %loop, %entry
call i32 @f1()
%loaded = load i8, i8* %p
%continue = icmp eq i8 %loaded, 0
br i1 %continue, label %exit, label %loop
exit: ; preds = %loop
ret void
}
; Make sure that we can safely PRE a speculable load across a call.
define void @safe_pre_across_call(i8* noalias nocapture readonly dereferenceable(8) %p) {
; CHECK-LABEL: @safe_pre_across_call(
; CHECK: entry:
; CHECK-NEXT: %loaded.pr = load i8, i8* %p
; CHECK-NEXT: br label %loop
; CHECK: loop:
; CHECK-NEXT: %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ]
; CHECK-NEXT: call i32 @f1()
; CHECK-NEXT: %continue = icmp eq i8 %loaded, 0
; CHECK-NEXT: br i1 %continue, label %exit, label %loop
entry:
br label %loop
loop: ; preds = %loop, %entry
call i32 @f1()
%loaded = load i8, i8* %p
%continue = icmp eq i8 %loaded, 0
br i1 %continue, label %exit, label %loop
exit: ; preds = %loop
ret void
}

View File

@ -0,0 +1,99 @@
; RUN: opt -S -jump-threading < %s | FileCheck %s
; Check that the heuristic for avoiding accidental introduction of irreducible
; loops doesn't also prevent us from threading simple constructs where this
; isn't a problem.
declare void @opaque_body()
define void @jump_threading_loopheader() {
; CHECK-LABEL: @jump_threading_loopheader
top:
br label %entry
entry:
%ind = phi i32 [0, %top], [%nextind, %latch]
%nextind = add i32 %ind, 1
%cmp = icmp ule i32 %ind, 10
; CHECK: br i1 %cmp, label %latch, label %exit
br i1 %cmp, label %body, label %latch
body:
call void @opaque_body()
; CHECK: br label %entry
br label %latch
latch:
%cond = phi i2 [1, %entry], [2, %body]
switch i2 %cond, label %unreach [
i2 2, label %entry
i2 1, label %exit
]
unreach:
unreachable
exit:
ret void
}
; We also need to check the opposite order of the branches, in the switch
; instruction because jump-threading relies on that to decide which edge to
; try to thread first.
define void @jump_threading_loopheader2() {
; CHECK-LABEL: @jump_threading_loopheader2
top:
br label %entry
entry:
%ind = phi i32 [0, %top], [%nextind, %latch]
%nextind = add i32 %ind, 1
%cmp = icmp ule i32 %ind, 10
; CHECK: br i1 %cmp, label %exit, label %latch
br i1 %cmp, label %body, label %latch
body:
call void @opaque_body()
; CHECK: br label %entry
br label %latch
latch:
%cond = phi i2 [1, %entry], [2, %body]
switch i2 %cond, label %unreach [
i2 1, label %entry
i2 2, label %exit
]
unreach:
unreachable
exit:
ret void
}
; Check if we can handle undef branch condition.
define void @jump_threading_loopheader3() {
; CHECK-LABEL: @jump_threading_loopheader3
top:
br label %entry
entry:
%ind = phi i32 [0, %top], [%nextind, %latch]
%nextind = add i32 %ind, 1
%cmp = icmp ule i32 %ind, 10
; CHECK: br i1 %cmp, label %latch, label %exit
br i1 %cmp, label %body, label %latch
body:
call void @opaque_body()
; CHECK: br label %entry
br label %latch
latch:
%phi = phi i32 [undef, %entry], [0, %body]
%cmp1 = icmp eq i32 %phi, 0
br i1 %cmp1, label %entry, label %exit
exit:
ret void
}

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