1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 2; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s 3 4%struct.ListNode = type { i32, ptr } 5 6define i32 @umin(ptr readonly %a) { 7; CHECK-LABEL: define i32 @umin 8; CHECK-SAME: (ptr readonly [[A:%.*]]) { 9; CHECK-NEXT: entry: 10; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 11; CHECK: tailrecurse: 12; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 13; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 14; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 15; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 16; CHECK: common.ret6: 17; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 -1, i32 [[ACCUMULATOR_TR]]) 18; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 19; CHECK: if.end: 20; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 21; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 22; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 23; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) 24; CHECK-NEXT: br label [[TAILRECURSE]] 25; 26entry: 27 %tobool.not = icmp eq ptr %a, null 28 br i1 %tobool.not, label %common.ret6, label %if.end 29 30common.ret6: ; preds = %entry, %if.end 31 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ] 32 ret i32 %common.ret6.op 33 34if.end: ; preds = %entry 35 %0 = load i32, ptr %a 36 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 37 %1 = load ptr, ptr %next 38 %call = tail call i32 @umin(ptr %1) 39 %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %0, i32 %call) 40 br label %common.ret6 41} 42 43define i32 @umin2(ptr readonly %a) { 44; CHECK-LABEL: define i32 @umin2 45; CHECK-SAME: (ptr readonly [[A:%.*]]) { 46; CHECK-NEXT: entry: 47; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 48; CHECK: tailrecurse: 49; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 50; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 51; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 52; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 53; CHECK: common.ret6: 54; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 -1) 55; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 56; CHECK: if.end: 57; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 58; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 59; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 60; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) 61; CHECK-NEXT: br label [[TAILRECURSE]] 62; 63entry: 64 %tobool.not = icmp eq ptr %a, null 65 br i1 %tobool.not, label %common.ret6, label %if.end 66 67common.ret6: ; preds = %entry, %if.end 68 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ] 69 ret i32 %common.ret6.op 70 71if.end: ; preds = %entry 72 %0 = load i32, ptr %a 73 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 74 %1 = load ptr, ptr %next 75 %call = tail call i32 @umin2(ptr %1) 76 %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %call, i32 %0) 77 br label %common.ret6 78} 79 80define i32 @umax(ptr readonly %a) { 81; CHECK-LABEL: define i32 @umax 82; CHECK-SAME: (ptr readonly [[A:%.*]]) { 83; CHECK-NEXT: entry: 84; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 85; CHECK: tailrecurse: 86; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 87; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 88; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 89; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 90; CHECK: common.ret6: 91; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 0, i32 [[ACCUMULATOR_TR]]) 92; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 93; CHECK: if.end: 94; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 95; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 96; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 97; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) 98; CHECK-NEXT: br label [[TAILRECURSE]] 99; 100entry: 101 %tobool.not = icmp eq ptr %a, null 102 br i1 %tobool.not, label %common.ret6, label %if.end 103 104common.ret6: ; preds = %entry, %if.end 105 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ] 106 ret i32 %common.ret6.op 107 108if.end: ; preds = %entry 109 %0 = load i32, ptr %a 110 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 111 %1 = load ptr, ptr %next 112 %call = tail call i32 @umax(ptr %1) 113 %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %0, i32 %call) 114 br label %common.ret6 115} 116 117define i32 @umax2(ptr readonly %a) { 118; CHECK-LABEL: define i32 @umax2 119; CHECK-SAME: (ptr readonly [[A:%.*]]) { 120; CHECK-NEXT: entry: 121; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 122; CHECK: tailrecurse: 123; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 124; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 125; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 126; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 127; CHECK: common.ret6: 128; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 0) 129; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 130; CHECK: if.end: 131; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 132; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 133; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 134; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) 135; CHECK-NEXT: br label [[TAILRECURSE]] 136; 137entry: 138 %tobool.not = icmp eq ptr %a, null 139 br i1 %tobool.not, label %common.ret6, label %if.end 140 141common.ret6: ; preds = %entry, %if.end 142 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ] 143 ret i32 %common.ret6.op 144 145if.end: ; preds = %entry 146 %0 = load i32, ptr %a 147 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 148 %1 = load ptr, ptr %next 149 %call = tail call i32 @umax2(ptr %1) 150 %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %call, i32 %0) 151 br label %common.ret6 152} 153 154define i32 @smin(ptr readonly %a) { 155; CHECK-LABEL: define i32 @smin 156; CHECK-SAME: (ptr readonly [[A:%.*]]) { 157; CHECK-NEXT: entry: 158; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 159; CHECK: tailrecurse: 160; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 161; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 162; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 163; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 164; CHECK: common.ret6: 165; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 2147483647, i32 [[ACCUMULATOR_TR]]) 166; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 167; CHECK: if.end: 168; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 169; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 170; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 171; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) 172; CHECK-NEXT: br label [[TAILRECURSE]] 173; 174entry: 175 %tobool.not = icmp eq ptr %a, null 176 br i1 %tobool.not, label %common.ret6, label %if.end 177 178common.ret6: ; preds = %entry, %if.end 179 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ] 180 ret i32 %common.ret6.op 181 182if.end: ; preds = %entry 183 %0 = load i32, ptr %a 184 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 185 %1 = load ptr, ptr %next 186 %call = tail call i32 @smin(ptr %1) 187 %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %0, i32 %call) 188 br label %common.ret6 189} 190 191define i32 @smin2(ptr readonly %a) { 192; CHECK-LABEL: define i32 @smin2 193; CHECK-SAME: (ptr readonly [[A:%.*]]) { 194; CHECK-NEXT: entry: 195; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 196; CHECK: tailrecurse: 197; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 198; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 199; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 200; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 201; CHECK: common.ret6: 202; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 2147483647) 203; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 204; CHECK: if.end: 205; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 206; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 207; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 208; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) 209; CHECK-NEXT: br label [[TAILRECURSE]] 210; 211entry: 212 %tobool.not = icmp eq ptr %a, null 213 br i1 %tobool.not, label %common.ret6, label %if.end 214 215common.ret6: ; preds = %entry, %if.end 216 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ] 217 ret i32 %common.ret6.op 218 219if.end: ; preds = %entry 220 %0 = load i32, ptr %a 221 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 222 %1 = load ptr, ptr %next 223 %call = tail call i32 @smin2(ptr %1) 224 %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %call, i32 %0) 225 br label %common.ret6 226} 227 228define i32 @smax(ptr readonly %a) { 229; CHECK-LABEL: define i32 @smax 230; CHECK-SAME: (ptr readonly [[A:%.*]]) { 231; CHECK-NEXT: entry: 232; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 233; CHECK: tailrecurse: 234; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 235; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 236; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 237; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 238; CHECK: common.ret6: 239; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 -2147483648, i32 [[ACCUMULATOR_TR]]) 240; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 241; CHECK: if.end: 242; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 243; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 244; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 245; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) 246; CHECK-NEXT: br label [[TAILRECURSE]] 247; 248entry: 249 %tobool.not = icmp eq ptr %a, null 250 br i1 %tobool.not, label %common.ret6, label %if.end 251 252common.ret6: ; preds = %entry, %if.end 253 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ] 254 ret i32 %common.ret6.op 255 256if.end: ; preds = %entry 257 %0 = load i32, ptr %a 258 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 259 %1 = load ptr, ptr %next 260 %call = tail call i32 @smax(ptr %1) 261 %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %0, i32 %call) 262 br label %common.ret6 263} 264 265define i32 @smax2(ptr readonly %a) { 266; CHECK-LABEL: define i32 @smax2 267; CHECK-SAME: (ptr readonly [[A:%.*]]) { 268; CHECK-NEXT: entry: 269; CHECK-NEXT: br label [[TAILRECURSE:%.*]] 270; CHECK: tailrecurse: 271; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] 272; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] 273; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null 274; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] 275; CHECK: common.ret6: 276; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 -2147483648) 277; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] 278; CHECK: if.end: 279; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 280; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 281; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 282; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) 283; CHECK-NEXT: br label [[TAILRECURSE]] 284; 285entry: 286 %tobool.not = icmp eq ptr %a, null 287 br i1 %tobool.not, label %common.ret6, label %if.end 288 289common.ret6: ; preds = %entry, %if.end 290 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ] 291 ret i32 %common.ret6.op 292 293if.end: ; preds = %entry 294 %0 = load i32, ptr %a 295 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 296 %1 = load ptr, ptr %next 297 %call = tail call i32 @smax2(ptr %1) 298 %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %call, i32 %0) 299 br label %common.ret6 300} 301 302declare i32 @llvm.umin.i32(i32, i32) 303declare i32 @llvm.umax.i32(i32, i32) 304declare i32 @llvm.smin.i32(i32, i32) 305declare i32 @llvm.smax.i32(i32, i32) 306