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