From 097925aab9cac3c381fd94e2e03733fdaf21f897 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 25 Aug 2021 20:39:33 +0100 Subject: [PATCH] [ConstraintElimination] Add test cases with @llvm.assume. --- .../Transforms/ConstraintElimination/assumes.ll | 272 +++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 llvm/test/Transforms/ConstraintElimination/assumes.ll diff --git a/llvm/test/Transforms/ConstraintElimination/assumes.ll b/llvm/test/Transforms/ConstraintElimination/assumes.ll new file mode 100644 index 0000000..37a1d3f --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/assumes.ll @@ -0,0 +1,272 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -constraint-elimination -S %s | FileCheck %s + +declare void @llvm.assume(i1) + +declare void @may_unwind() + +declare void @use(i1) + +define i1 @assume_dominates(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_dominates( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: ret i1 [[RES_2]] +; CHECK: else: +; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]] +; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] +; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] +; CHECK-NEXT: ret i1 [[RES_4]] +; + %add.1 = add nsw nuw i8 %a, 1 + %cmp.1 = icmp ule i8 %add.1, %b + call void @llvm.assume(i1 %cmp.1) + br i1 %c, label %then, label %else + +then: + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + ret i1 %res.2 + +else: + %t.3 = icmp ule i8 %add.1, %b + %t.4 = icmp ule i8 %a, %b + %res.3 = xor i1 %t.3, %t.4 + %add.2.1 = add nsw nuw i8 %a, 2 + %c.2 = icmp ule i8 %add.2.1, %b + %res.4 = xor i1 %res.3, %c.2 + ret i1 %res.4 +} + +define i1 @assume_same_bb(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: ret i1 [[RES_2]] +; CHECK: else: +; CHECK-NEXT: [[T_3:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_4:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_3:%.*]] = xor i1 [[T_3]], [[T_4]] +; CHECK-NEXT: [[ADD_2_1:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[ADD_2_1]], [[B]] +; CHECK-NEXT: [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_2]] +; CHECK-NEXT: ret i1 [[RES_4]] +; + %add.1 = add nsw nuw i8 %a, 1 + %cmp.1 = icmp ule i8 %add.1, %b + br i1 %c, label %then, label %else + +then: + call void @llvm.assume(i1 %cmp.1) + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + ret i1 %res.2 + +else: + %t.3 = icmp ule i8 %add.1, %b + %t.4 = icmp ule i8 %a, %b + %res.3 = xor i1 %t.3, %t.4 + %add.2.1 = add nsw nuw i8 %a, 2 + %c.2 = icmp ule i8 %add.2.1, %b + %res.4 = xor i1 %res.3, %c.2 + ret i1 %res.4 +} + + +define i1 @assume_same_bb2(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb2( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 [[RES_2]] +; + %add.1 = add nsw nuw i8 %a, 1 + %cmp.1 = icmp ule i8 %add.1, %b + call void @llvm.assume(i1 %cmp.1) + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + br label %exit + +exit: + ret i1 %res.2 +} + + +; TODO: Keep track of position of assume and may unwinding calls, simplify +; conditions if possible. +define i1 @assume_same_bb_after_may_exiting_call(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb_after_may_exiting_call( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: call void @may_unwind() +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 [[RES_2]] +; + %add.1 = add nsw nuw i8 %a, 1 + %cmp.1 = icmp ule i8 %add.1, %b + call void @may_unwind() + call void @llvm.assume(i1 %cmp.1) + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + br label %exit + +exit: + ret i1 %res.2 +} + +; TODO: Keep track of position of assume and may unwinding calls, simplify +; conditions if possible. +define i1 @assume_same_bb_before_may_exiting_call(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb_before_may_exiting_call( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: call void @may_unwind() +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 [[RES_2]] +; + %add.1 = add nsw nuw i8 %a, 1 + %cmp.1 = icmp ule i8 %add.1, %b + call void @llvm.assume(i1 %cmp.1) + call void @may_unwind() + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + br label %exit + +exit: + ret i1 %res.2 +} + +define i1 @assume_same_bb_after_condition(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb_after_condition( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[T_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: [[T_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]] +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 [[RES_2]] +; + %add.1 = add nsw nuw i8 %a, 1 + %t.1 = icmp ule i8 %add.1, %b + %t.2 = icmp ule i8 %a, %b + %res.1 = xor i1 %t.1, %t.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.1 = icmp ule i8 %add.2, %b + %res.2 = xor i1 %res.1, %c.1 + %cmp.1 = icmp ule i8 %add.1, %b + call void @llvm.assume(i1 %cmp.1) + br label %exit + +exit: + ret i1 %res.2 +} + +; The function may exit before the assume if @may_unwind unwinds. Conditions +; before the call cannot be simplified. +define i1 @assume_same_bb_after_condition_may_unwind_between(i8 %a, i8 %b, i1 %c) { +; CHECK-LABEL: @assume_same_bb_after_condition_may_unwind_between( +; CHECK-NEXT: [[ADD_1:%.*]] = add nuw nsw i8 [[A:%.*]], 1 +; CHECK-NEXT: [[C_1:%.*]] = icmp ule i8 [[ADD_1]], [[B:%.*]] +; CHECK-NEXT: call void @use(i1 [[C_1]]) +; CHECK-NEXT: [[C_2:%.*]] = icmp ule i8 [[A]], [[B]] +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: [[RES_1:%.*]] = xor i1 [[C_1]], [[C_2]] +; CHECK-NEXT: [[ADD_2:%.*]] = add nuw nsw i8 [[A]], 2 +; CHECK-NEXT: [[C_3:%.*]] = icmp ule i8 [[ADD_2]], [[B]] +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_3]] +; CHECK-NEXT: [[CMP_1:%.*]] = icmp ule i8 [[ADD_1]], [[B]] +; CHECK-NEXT: call void @may_unwind() +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_1]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 [[RES_2]] +; + %add.1 = add nsw nuw i8 %a, 1 + %c.1 = icmp ule i8 %add.1, %b + call void @use(i1 %c.1) + %c.2 = icmp ule i8 %a, %b + call void @use(i1 %c.2) + %res.1 = xor i1 %c.1, %c.2 + %add.2 = add nsw nuw i8 %a, 2 + %c.3 = icmp ule i8 %add.2, %b + call void @use(i1 %c.3) + %res.2 = xor i1 %res.1, %c.3 + %cmp.1 = icmp ule i8 %add.1, %b + call void @may_unwind() + call void @llvm.assume(i1 %cmp.1) + br label %exit + +exit: + ret i1 %res.2 +} -- 2.7.4