1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s
4 ; This test checks that TRE would be done for only one recursive call.
5 ; The test_multiple_exits function has three recursive calls.
6 ; First recursive call could not be eliminated because there is
7 ; escaped pointer to local variable. Second recursive call could
8 ; be eliminated. Thrid recursive call could not be eliminated since
9 ; this is not last call. Thus, test checks that TRE would be done
10 ; for only second recursive call.
12 ; IR for that test was generated from the following C++ source:
14 ; void capture_arg (int*);
15 ; void test_multiple_exits (int param);
16 ; if (param >= 0 && param < 10) {
19 ; // TRE could not be done because pointer to local
20 ; // variable "temp" is escaped.
21 ; test_multiple_exits(param + 1);
22 ; } else if (param >=10 && param < 20) {
23 ; // TRE should be done.
24 ; test_multiple_exits(param + 1);
25 ; } else if (param >= 20 && param < 22) {
26 ; // TRE could not be done since recursive
27 ; // call is not last call.
28 ; test_multiple_exits(param + 1);
35 ; Function Attrs: noinline optnone uwtable
36 declare void @_Z11capture_argPi(ptr %param) #0
38 ; Function Attrs: noinline optnone uwtable
39 declare void @_Z4funcv() #0
41 ; Function Attrs: noinline nounwind uwtable
42 define dso_local void @_Z19test_multiple_exitsi(i32 %param) local_unnamed_addr #2 {
43 ; CHECK-LABEL: @_Z19test_multiple_exitsi(
45 ; CHECK-NEXT: [[TEMP:%.*]] = alloca i32, align 4
46 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
48 ; CHECK-NEXT: [[PARAM_TR:%.*]] = phi i32 [ [[PARAM:%.*]], [[ENTRY:%.*]] ], [ [[ADD6:%.*]], [[IF_THEN5:%.*]] ]
49 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[PARAM_TR]], 10
50 ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
52 ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[TEMP]]) #1
53 ; CHECK-NEXT: call void @_Z11capture_argPi(ptr nonnull [[TEMP]])
54 ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[PARAM_TR]], 1
55 ; CHECK-NEXT: call void @_Z19test_multiple_exitsi(i32 [[ADD]])
56 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[TEMP]]) #1
57 ; CHECK-NEXT: br label [[IF_END14:%.*]]
59 ; CHECK-NEXT: [[PARAM_OFF:%.*]] = add i32 [[PARAM_TR]], -10
60 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[PARAM_OFF]], 10
61 ; CHECK-NEXT: br i1 [[TMP2]], label [[IF_THEN5]], label [[IF_ELSE7:%.*]]
63 ; CHECK-NEXT: [[ADD6]] = add nuw nsw i32 [[PARAM_TR]], 1
64 ; CHECK-NEXT: br label [[TAILRECURSE]]
66 ; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[PARAM_TR]], -2
67 ; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 20
68 ; CHECK-NEXT: br i1 [[TMP4]], label [[IF_THEN11:%.*]], label [[IF_END14]]
70 ; CHECK-NEXT: [[ADD12:%.*]] = add nsw i32 [[PARAM_TR]], 1
71 ; CHECK-NEXT: tail call void @_Z19test_multiple_exitsi(i32 [[ADD12]])
72 ; CHECK-NEXT: tail call void @_Z4funcv()
73 ; CHECK-NEXT: ret void
75 ; CHECK-NEXT: ret void
78 %temp = alloca i32, align 4
79 %0 = icmp ult i32 %param, 10
80 br i1 %0, label %if.then, label %if.else
82 if.then: ; preds = %entry
83 call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %temp) #2
84 call void @_Z11capture_argPi(ptr nonnull %temp)
85 %add = add nuw nsw i32 %param, 1
86 call void @_Z19test_multiple_exitsi(i32 %add)
87 call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %temp) #2
90 if.else: ; preds = %entry
91 %param.off = add i32 %param, -10
92 %1 = icmp ult i32 %param.off, 10
93 br i1 %1, label %if.then5, label %if.else7
95 if.then5: ; preds = %if.else
96 %add6 = add nuw nsw i32 %param, 1
97 call void @_Z19test_multiple_exitsi(i32 %add6)
100 if.else7: ; preds = %if.else
101 %2 = and i32 %param, -2
102 %3 = icmp eq i32 %2, 20
103 br i1 %3, label %if.then11, label %if.end14
105 if.then11: ; preds = %if.else7
106 %add12 = add nsw i32 %param, 1
107 call void @_Z19test_multiple_exitsi(i32 %add12)
108 call void @_Z4funcv()
111 if.end14: ; preds = %if.then5, %if.then11, %if.else7, %if.then
115 ; Function Attrs: argmemonly nounwind willreturn
116 declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
118 ; Function Attrs: argmemonly nounwind willreturn
119 declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
121 attributes #0 = { nofree noinline norecurse nounwind uwtable }
122 attributes #1 = { nounwind uwtable }
123 attributes #2 = { argmemonly nounwind willreturn }