diff --git a/llvm/test/Transforms/ConstraintElimination/type-bounds.ll b/llvm/test/Transforms/ConstraintElimination/type-bounds.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/type-bounds.ll @@ -0,0 +1,423 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s + +declare void @use(i1) + +define void @zext_cmp_i1_to_i32(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i1 [[A:%.*]], false +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 1 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[A_EXT]], [[B]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i1 %a, false + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i1 %a to i32 + %cmp.1 = icmp ugt i32 %b, 1 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp ult i32 %a.ext, %b + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + +define void @zext_cmp_i1_to_i32_without_entry_check(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32_without_entry_check( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A:%.*]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 1 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT:%.*]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[A_EXT]], [[B]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %a.ext = zext i1 %a to i32 + %cmp.1 = icmp ugt i32 %b, 1 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp ult i32 %a.ext, %b + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + + +define void @zext_cmp_i1_to_i32_2(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i1 [[A:%.*]], false +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A_EXT]], [[B:%.*]] +; CHECK-NEXT: call void @use(i1 [[CMP]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i1 %a, false + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i1 %a to i32 + %cmp = icmp ult i32 %a.ext, %b + call void @use(i1 %cmp) + ret void + +exit: + ret void +} + +define void @zext_cmp_i1_to_i32_2_wihtout_initial_check(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32_2_wihtout_initial_check( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A:%.*]] to i32 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A_EXT]], [[B:%.*]] +; CHECK-NEXT: call void @use(i1 [[CMP]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %a.ext = zext i1 %a to i32 + %cmp = icmp ult i32 %a.ext, %b + call void @use(i1 %cmp) + ret void + +exit: + ret void +} + +define void @zext_cmp_i1_to_i32_signed(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32_signed( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i1 [[A:%.*]], false +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 1 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp slt i32 [[A_EXT]], [[B]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i1 %a, 0 + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i1 %a to i32 + %cmp.1 = icmp ugt i32 %b, 1 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp slt i32 %a.ext, %b + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + +define void @zext_cmp_i1_to_i32_signed_without_initial_check(i1 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i1_to_i32_signed_without_initial_check( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i1 [[A:%.*]], false +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i1 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 1 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp slt i32 [[A_EXT]], [[B]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i1 %a, 0 + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i1 %a to i32 + %cmp.1 = icmp ugt i32 %b, 1 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp slt i32 %a.ext, %b + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} +define void @zext_cmp_vector_bounds(<2 x i8> %a, <2 x i32> %b) { +; CHECK-LABEL: @zext_cmp_vector_bounds( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt <2 x i8> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[INIT_COND_1:%.*]] = extractelement <2 x i1> [[INIT_COND]], i32 0 +; CHECK-NEXT: [[INIT_COND_2:%.*]] = extractelement <2 x i1> [[INIT_COND]], i32 1 +; CHECK-NEXT: [[INIT_AND:%.*]] = and i1 [[INIT_COND_1]], [[INIT_COND_2]] +; CHECK-NEXT: br i1 [[INIT_AND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext <2 x i8> [[A]] to <2 x i32> +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt <2 x i32> [[B:%.*]], +; CHECK-NEXT: [[CONT_1:%.*]] = extractelement <2 x i1> [[CMP_1]], i32 0 +; CHECK-NEXT: [[CONT_2:%.*]] = extractelement <2 x i1> [[CMP_1]], i32 1 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[CONT_1]], [[CONT_2]] +; CHECK-NEXT: br i1 [[AND]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult <2 x i32> [[A_EXT]], [[B]] +; CHECK-NEXT: [[CONT_3:%.*]] = extractelement <2 x i1> [[CMP_1]], i32 0 +; CHECK-NEXT: [[CONT_4:%.*]] = extractelement <2 x i1> [[CMP_1]], i32 1 +; CHECK-NEXT: call void @use(i1 [[CONT_3]]) +; CHECK-NEXT: call void @use(i1 [[CONT_4]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt <2 x i8> %a, + %init.cond.1 = extractelement <2 x i1> %init.cond, i32 0 + %init.cond.2 = extractelement <2 x i1> %init.cond, i32 1 + %init.and = and i1 %init.cond.1, %init.cond.2 + br i1 %init.and, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext <2 x i8> %a to <2 x i32> + %cmp.1 = icmp ugt <2 x i32> %b, + %cont.1 = extractelement <2 x i1> %cmp.1, i32 0 + %cont.2 = extractelement <2 x i1> %cmp.1, i32 1 + %and = and i1 %cont.1, %cont.2 + br i1 %and, label %cond, label %exit + +cond: + %cmp.2 = icmp ult <2 x i32> %a.ext, %b + %cont.3 = extractelement <2 x i1> %cmp.1, i32 0 + %cont.4 = extractelement <2 x i1> %cmp.1, i32 1 + call void @use(i1 %cont.3) + call void @use(i1 %cont.4) + ret void + +exit: + ret void +} + +define void @zext_cmp_i8_to_i32(i8 %a, i32 %b) { +; CHECK-LABEL: @zext_cmp_i8_to_i32( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i8 [[A:%.*]], 0 +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i8 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 255 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[A_EXT]], [[B]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i8 %a, 0 + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i8 %a to i32 + %cmp.1 = icmp ugt i32 %b, 255 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp ult i32 %a.ext, %b + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + +define void @zext_cmp_i8_to_i32_add(i8 %a, i8 %b, i32 %c) { +; CHECK-LABEL: @zext_cmp_i8_to_i32_add( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND_1:%.*]] = icmp ugt i8 [[A:%.*]], 0 +; CHECK-NEXT: [[INIT_COND_2:%.*]] = icmp ugt i8 [[B:%.*]], 0 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[INIT_COND_1]], [[INIT_COND_2]] +; CHECK-NEXT: br i1 [[AND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[A]], [[B]] +; CHECK-NEXT: [[ADD_EXT:%.*]] = zext i8 [[ADD]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[C:%.*]], 255 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[ADD_EXT]], [[C]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond.1 = icmp ugt i8 %a, 0 + %init.cond.2 = icmp ugt i8 %b, 0 + %and = and i1 %init.cond.1, %init.cond.2 + br i1 %and, label %pre.cond, label %exit + +pre.cond: + %add = add nuw nsw i8 %a, %b + %add.ext = zext i8 %add to i32 + %cmp.1 = icmp ugt i32 %c, 255 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp ult i32 %add.ext, %c + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + +define void @zext_cmp_i8_to_i32_add_without_initial_check(i8 %a, i8 %b, i32 %c) { +; CHECK-LABEL: @zext_cmp_i8_to_i32_add_without_initial_check( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[ADD_EXT:%.*]] = zext i8 [[ADD]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[C:%.*]], 255 +; CHECK-NEXT: br i1 [[CMP_1]], label [[COND:%.*]], label [[EXIT:%.*]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i32 [[ADD_EXT]], [[C]] +; CHECK-NEXT: call void @use(i1 [[CMP_2]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %add = add nuw nsw i8 %a, %b + %add.ext = zext i8 %add to i32 + %cmp.1 = icmp ugt i32 %c, 255 + br i1 %cmp.1, label %cond, label %exit + +cond: + %cmp.2 = icmp ult i32 %add.ext, %c + call void @use(i1 %cmp.2) + ret void + +exit: + ret void +} + +define void @zext_multiple_uses(i8 %a, i32 %b, i32 %b2) { +; CHECK-LABEL: @zext_multiple_uses( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i8 [[A:%.*]], 0 +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i8 [[A]] to i32 +; CHECK-NEXT: [[A2_EXT:%.*]] = zext i8 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 255 +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ugt i32 [[B2:%.*]], 255 +; CHECK-NEXT: [[PRE_CMP:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: br i1 [[PRE_CMP]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_3:%.*]] = icmp ult i32 [[A_EXT]], [[B]] +; CHECK-NEXT: [[CMP_4:%.*]] = icmp ult i32 [[A2_EXT]], [[B2]] +; CHECK-NEXT: call void @use(i1 [[CMP_3]]) +; CHECK-NEXT: call void @use(i1 [[CMP_4]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i8 %a, 0 + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i8 %a to i32 + %a2.ext = zext i8 %a to i32 + %cmp.1 = icmp ugt i32 %b, 255 + %cmp.2 = icmp ugt i32 %b2, 255 + %pre.cmp = and i1 %cmp.1, %cmp.2 + br i1 %pre.cmp, label %cond, label %exit + +cond: + %cmp.3 = icmp ult i32 %a.ext, %b + %cmp.4 = icmp ult i32 %a2.ext, %b2 + call void @use(i1 %cmp.3) + call void @use(i1 %cmp.4) + ret void + +exit: + ret void +} + +define void @zext_operand_used_in_sext(i8 %a, i32 %b, i32 %b2) { +; CHECK-LABEL: @zext_operand_used_in_sext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[INIT_COND:%.*]] = icmp ugt i8 [[A:%.*]], 0 +; CHECK-NEXT: br i1 [[INIT_COND]], label [[PRE_COND:%.*]], label [[EXIT:%.*]] +; CHECK: pre.cond: +; CHECK-NEXT: [[A_EXT:%.*]] = zext i8 [[A]] to i32 +; CHECK-NEXT: [[A2_EXT:%.*]] = sext i8 [[A]] to i32 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ugt i32 [[B:%.*]], 255 +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ugt i32 [[B2:%.*]], 255 +; CHECK-NEXT: [[PRE_CMP:%.*]] = and i1 [[CMP_1]], [[CMP_2]] +; CHECK-NEXT: br i1 [[PRE_CMP]], label [[COND:%.*]], label [[EXIT]] +; CHECK: cond: +; CHECK-NEXT: [[CMP_3:%.*]] = icmp ult i32 [[A_EXT]], [[B]] +; CHECK-NEXT: [[CMP_4:%.*]] = icmp ult i32 [[A2_EXT]], [[B2]] +; CHECK-NEXT: call void @use(i1 [[CMP_3]]) +; CHECK-NEXT: call void @use(i1 [[CMP_4]]) +; CHECK-NEXT: ret void +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %init.cond = icmp ugt i8 %a, 0 + br i1 %init.cond, label %pre.cond, label %exit + +pre.cond: + %a.ext = zext i8 %a to i32 + %a2.ext = sext i8 %a to i32 + %cmp.1 = icmp ugt i32 %b, 255 + %cmp.2 = icmp ugt i32 %b2, 255 + %pre.cmp = and i1 %cmp.1, %cmp.2 + br i1 %pre.cmp, label %cond, label %exit + +cond: + %cmp.3 = icmp ult i32 %a.ext, %b + %cmp.4 = icmp ult i32 %a2.ext, %b2 + call void @use(i1 %cmp.3) + call void @use(i1 %cmp.4) + ret void + +exit: + ret void +}