xref: /llvm-project/llvm/test/Transforms/TailCallElim/tre-multiple-exits.ll (revision 8dc14a3bc05e50e86d7b26ac141364eccbceb134)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s
3
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.
11
12; IR for that test was generated from the following C++ source:
13;
14; void capture_arg (int*);
15; void test_multiple_exits (int param);
16;   if (param >= 0 && param < 10) {
17;     int temp;
18;     capture_arg(&temp);
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);
29;     func();
30;   }
31;
32;   return;
33; }
34
35; Function Attrs: noinline optnone uwtable
36declare void @_Z11capture_argPi(ptr %param) #0
37
38; Function Attrs: noinline optnone uwtable
39declare void @_Z4funcv() #0
40
41; Function Attrs: noinline nounwind uwtable
42define dso_local void @_Z19test_multiple_exitsi(i32 %param) local_unnamed_addr #2 {
43; CHECK-LABEL: @_Z19test_multiple_exitsi(
44; CHECK-NEXT:  entry:
45; CHECK-NEXT:    [[TEMP:%.*]] = alloca i32, align 4
46; CHECK-NEXT:    br label [[TAILRECURSE:%.*]]
47; CHECK:       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:%.*]]
51; CHECK:       if.then:
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:%.*]]
58; CHECK:       if.else:
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:%.*]]
62; CHECK:       if.then5:
63; CHECK-NEXT:    [[ADD6]] = add nuw nsw i32 [[PARAM_TR]], 1
64; CHECK-NEXT:    br label [[TAILRECURSE]]
65; CHECK:       if.else7:
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]]
69; CHECK:       if.then11:
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
74; CHECK:       if.end14:
75; CHECK-NEXT:    ret void
76;
77entry:
78  %temp = alloca i32, align 4
79  %0 = icmp ult i32 %param, 10
80  br i1 %0, label %if.then, label %if.else
81
82if.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
88  br label %if.end14
89
90if.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
94
95if.then5:                                         ; preds = %if.else
96  %add6 = add nuw nsw i32 %param, 1
97  call void @_Z19test_multiple_exitsi(i32 %add6)
98  br label %if.end14
99
100if.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
104
105if.then11:                                        ; preds = %if.else7
106  %add12 = add nsw i32 %param, 1
107  call void @_Z19test_multiple_exitsi(i32 %add12)
108  call void @_Z4funcv()
109  br label %if.end14
110
111if.end14:                                         ; preds = %if.then5, %if.then11, %if.else7, %if.then
112  ret void
113}
114
115; Function Attrs: argmemonly nounwind willreturn
116declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2
117
118; Function Attrs: argmemonly nounwind willreturn
119declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2
120
121attributes #0 = { nofree noinline norecurse nounwind uwtable }
122attributes #1 = { nounwind uwtable }
123attributes #2 = { argmemonly nounwind willreturn }
124