| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 |
| ; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s |
| |
| %struct.ListNode = type { i32, ptr } |
| |
| define i32 @umin(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @umin |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 -1, i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @umin(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %0, i32 %call) |
| br label %common.ret6 |
| } |
| |
| define i32 @umin2(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @umin2 |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 -1) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @umin2(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %call, i32 %0) |
| br label %common.ret6 |
| } |
| |
| define i32 @umax(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @umax |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 0, i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @umax(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %0, i32 %call) |
| br label %common.ret6 |
| } |
| |
| define i32 @umax2(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @umax2 |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 0) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @umax2(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %call, i32 %0) |
| br label %common.ret6 |
| } |
| |
| define i32 @smin(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @smin |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 2147483647, i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @smin(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %0, i32 %call) |
| br label %common.ret6 |
| } |
| |
| define i32 @smin2(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @smin2 |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 2147483647) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @smin2(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %call, i32 %0) |
| br label %common.ret6 |
| } |
| |
| define i32 @smax(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @smax |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 -2147483648, i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @smax(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %0, i32 %call) |
| br label %common.ret6 |
| } |
| |
| define i32 @smax2(ptr readonly %a) { |
| ; CHECK-LABEL: define i32 @smax2 |
| ; CHECK-SAME: (ptr readonly [[A:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[TAILRECURSE:%.*]] |
| ; CHECK: tailrecurse: |
| ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ] |
| ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ] |
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null |
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]] |
| ; CHECK: common.ret6: |
| ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 -2147483648) |
| ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4 |
| ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1 |
| ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8 |
| ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]]) |
| ; CHECK-NEXT: br label [[TAILRECURSE]] |
| ; |
| entry: |
| %tobool.not = icmp eq ptr %a, null |
| br i1 %tobool.not, label %common.ret6, label %if.end |
| |
| common.ret6: ; preds = %entry, %if.end |
| %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ] |
| ret i32 %common.ret6.op |
| |
| if.end: ; preds = %entry |
| %0 = load i32, ptr %a |
| %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1 |
| %1 = load ptr, ptr %next |
| %call = tail call i32 @smax2(ptr %1) |
| %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %call, i32 %0) |
| br label %common.ret6 |
| } |
| |
| declare i32 @llvm.umin.i32(i32, i32) |
| declare i32 @llvm.umax.i32(i32, i32) |
| declare i32 @llvm.smin.i32(i32, i32) |
| declare i32 @llvm.smax.i32(i32, i32) |