; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3 ; RUN: opt -p constraint-elimination -S %s | FileCheck %s declare void @use(i1) define void @start_value_of_inner_add_rec_is_add_rec_condition_can_be_simplified(i32 noundef %len) { ; CHECK-LABEL: define void @start_value_of_inner_add_rec_is_add_rec_condition_can_be_simplified( ; CHECK-SAME: i32 noundef [[LEN:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK: outer.header: ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]] ; CHECK: inner.header: ; CHECK-NEXT: [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_INC:%.*]], [[INNER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]] ; CHECK: inner.latch: ; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[K_INC]] = add i32 [[K_0]], 1 ; CHECK-NEXT: br label [[INNER_HEADER]] ; CHECK: outer.latch: ; CHECK-NEXT: [[I_INC]] = add i32 [[I_0]], 1 ; CHECK-NEXT: br label [[OUTER_HEADER]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %outer.header outer.header: %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ] %cmp = icmp ult i32 %i.0, %len br i1 %cmp, label %inner.header, label %exit inner.header: %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.inc, %inner.latch ] %cmp2.not = icmp eq i32 %k.0, %len br i1 %cmp2.not, label %outer.latch, label %inner.latch inner.latch: %cmp.not.i = icmp ult i32 %k.0, %len call void @use(i1 %cmp.not.i) %k.inc = add i32 %k.0, 1 br label %inner.header outer.latch: %i.inc = add i32 %i.0, 1 br label %outer.header exit: ret void } define void @start_value_of_inner_add_rec_is_add_rec_condition_cannot_be_simplified(i32 noundef %len) { ; CHECK-LABEL: define void @start_value_of_inner_add_rec_is_add_rec_condition_cannot_be_simplified( ; CHECK-SAME: i32 noundef [[LEN:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK: outer.header: ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]] ; CHECK: inner.header: ; CHECK-NEXT: [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_INC:%.*]], [[INNER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]] ; CHECK: inner.latch: ; CHECK-NEXT: [[CMP_NOT_I:%.*]] = icmp ult i32 [[K_0]], 3 ; CHECK-NEXT: call void @use(i1 [[CMP_NOT_I]]) ; CHECK-NEXT: [[K_INC]] = add i32 [[K_0]], 1 ; CHECK-NEXT: br label [[INNER_HEADER]] ; CHECK: outer.latch: ; CHECK-NEXT: [[I_INC]] = add i32 [[I_0]], 1 ; CHECK-NEXT: br label [[OUTER_HEADER]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %outer.header outer.header: %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ] %cmp = icmp ult i32 %i.0, %len br i1 %cmp, label %inner.header, label %exit inner.header: %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.inc, %inner.latch ] %cmp2.not = icmp eq i32 %k.0, %len br i1 %cmp2.not, label %outer.latch, label %inner.latch inner.latch: %cmp.not.i = icmp ult i32 %k.0, 3 call void @use(i1 %cmp.not.i) %k.inc = add i32 %k.0, 1 br label %inner.header outer.latch: %i.inc = add i32 %i.0, 1 br label %outer.header exit: ret void } define void @inner_add_rec_decreasing(i32 noundef %len) { ; CHECK-LABEL: define void @inner_add_rec_decreasing( ; CHECK-SAME: i32 noundef [[LEN:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK: outer.header: ; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[OUTER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[I_0]], [[LEN]] ; CHECK-NEXT: br i1 [[CMP]], label [[INNER_HEADER:%.*]], label [[EXIT:%.*]] ; CHECK: inner.header: ; CHECK-NEXT: [[K_0:%.*]] = phi i32 [ [[I_0]], [[OUTER_HEADER]] ], [ [[K_DEC:%.*]], [[INNER_LATCH:%.*]] ] ; CHECK-NEXT: [[CMP2_NOT:%.*]] = icmp eq i32 [[K_0]], 0 ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[OUTER_LATCH]], label [[INNER_LATCH]] ; CHECK: inner.latch: ; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[K_DEC]] = add i32 [[K_0]], -1 ; CHECK-NEXT: br label [[INNER_HEADER]] ; CHECK: outer.latch: ; CHECK-NEXT: [[I_INC]] = add i32 [[I_0]], 1 ; CHECK-NEXT: br label [[OUTER_HEADER]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: br label %outer.header outer.header: %i.0 = phi i32 [ 1, %entry ], [ %i.inc, %outer.latch ] %cmp = icmp ult i32 %i.0, %len br i1 %cmp, label %inner.header, label %exit inner.header: %k.0 = phi i32 [ %i.0, %outer.header ], [ %k.dec, %inner.latch ] %cmp2.not = icmp eq i32 %k.0, 0 br i1 %cmp2.not, label %outer.latch, label %inner.latch inner.latch: %cmp.not.i = icmp ult i32 %k.0, %len call void @use(i1 %cmp.not.i) %k.dec = add i32 %k.0, -1 br label %inner.header outer.latch: %i.inc = add i32 %i.0, 1 br label %outer.header exit: ret void }