diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 267eb319a5616..7980348a999e0 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1605,6 +1605,30 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn, unsigned NumOut, SmallVectorImpl &DFSInStack) { addFactImpl(Pred, A, B, NumIn, NumOut, DFSInStack, false); + + Value *LHS; + Value *RHS; + if (match(A, m_Or(m_Value(LHS), m_Value(RHS)))) { + // (LHS | RHS >= 0) => LHS >= 0 && RHS >= 0 + // (LHS | RHS > -1) => LHS >= 0 && RHS >= 0 + if ((match(B, m_Zero()) && Pred == CmpInst::ICMP_SGE) || + (match(B, m_AllOnes()) && Pred == CmpInst::ICMP_SGT)) { + addFact(CmpInst::ICMP_SGE, LHS, ConstantInt::get(LHS->getType(), 0), + NumIn, NumOut, DFSInStack); + addFact(CmpInst::ICMP_SGE, RHS, ConstantInt::get(RHS->getType(), 0), + NumIn, NumOut, DFSInStack); + } + } else if (match(A, m_And(m_Value(LHS), m_Value(RHS)))) { + // (LHS & RHS < 0) => LHS < 0 && RHS < 0 + // (LHS & RHS <= -1) => LHS < 0 && RHS < 0 + if ((match(B, m_Zero()) && Pred == CmpInst::ICMP_SLT) || + (match(B, m_AllOnes()) && Pred == CmpInst::ICMP_SLE)) { + addFact(CmpInst::ICMP_SLT, LHS, ConstantInt::get(LHS->getType(), 0), + NumIn, NumOut, DFSInStack); + addFact(CmpInst::ICMP_SLT, RHS, ConstantInt::get(RHS->getType(), 0), + NumIn, NumOut, DFSInStack); + } + } // If the Pred is eq/ne, also add the fact to signed system. if (CmpInst::isEquality(Pred)) addFactImpl(Pred, A, B, NumIn, NumOut, DFSInStack, true); diff --git a/llvm/test/Transforms/ConstraintElimination/and.ll b/llvm/test/Transforms/ConstraintElimination/and.ll index f9824df3975e9..03d98c0396326 100644 --- a/llvm/test/Transforms/ConstraintElimination/and.ll +++ b/llvm/test/Transforms/ConstraintElimination/and.ll @@ -603,3 +603,208 @@ exit: ret i1 %r.10 } + +define void @test_decompose_bitwise_and(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_and( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = icmp slt i4 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[AND]], label [[BB1:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %y, %x + %c.1= icmp slt i4 %and.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 < 0 + %t.1 = icmp slt i4 %x, 0 + %t.2 = icmp slt i4 %y, 0 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + ret void + +end: + ret void +} + +define void @test_decompose_bitwise_and2(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_and2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[AND_NOT:%.*]] = icmp sgt i4 [[TMP0]], -1 +; CHECK-NEXT: br i1 [[AND_NOT]], label [[END:%.*]], label [[THEN:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %x, %y + %c.1 = icmp sgt i4 %and.1, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 > -1 + ret void + +end: + ; fact: %and.1 <= -1 + %t.1 = icmp slt i4 %x, 0 + %t.2 = icmp slt i4 %y, 0 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + ret void +} + +define void @test_decompose_nested_bitwise_and(i4 %x, i4 %y, i4 %z, i4 %w) { +; CHECK-LABEL: @test_decompose_nested_bitwise_and( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[TMP0]], [[Z:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[TMP1]], [[W:%.*]] +; CHECK-NEXT: [[AND:%.*]] = icmp slt i4 [[TMP2]], 0 +; CHECK-NEXT: br i1 [[AND]], label [[BB1:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %y, %x + %and.2 = and i4 %and.1, %z + %and.3 = and i4 %and.2, %w + %c.1= icmp slt i4 %and.3, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.3 < 0 + %t.1 = icmp slt i4 %x, 0 + %t.2 = icmp slt i4 %y, 0 + %t.3 = icmp slt i4 %z, 0 + %t.4 = icmp slt i4 %w, 0 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + call void @use(i1 %t.3) + call void @use(i1 %t.4) + ret void + +end: + ret void +} + +define void @test_decompose_nested_bitwise_and2(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_nested_bitwise_and2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = and i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[TMP0]], [[Z:%.*]] +; CHECK-NEXT: [[AND_2_NOT:%.*]] = icmp sgt i4 [[TMP1]], -1 +; CHECK-NEXT: br i1 [[AND_2_NOT]], label [[F:%.*]], label [[T:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %x, %y + %and.2 = and i4 %and.1, %z + %c.1 = icmp sgt i4 %and.2, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.2 > -1 + ret void + +end: + ; fact: %and.2 <= -1 same as %and.2 < 0 + %t.1 = icmp slt i4 %x, 0 + %t.2 = icmp slt i4 %y, 0 + %t.3 = icmp slt i4 %z, 0 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + call void @use(i1 %t.3) + ret void +} + +define void @test_decompose_bitwise_and_negative(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_and_negative( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i4 [[AND_1]], 0 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: [[C_2:%.*]] = icmp sgt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp sgt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %y, %x + %c.1= icmp slt i4 %and.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 < 0 + ret void + +end: + ; fact: %and.1 >= 0 + ; %c.2, %c.3 should only be replaced in the bitwise OR case + %c.2 = icmp sgt i4 %x, 0 + %c.3 = icmp sgt i4 %y, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ret void +} + +define void @test_decompose_bitwise_and_negative_2(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_and_negative_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i4 [[AND_1]], -1 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: [[C_2:%.*]] = icmp sgt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp sgt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %x, %y + %c.1 = icmp sgt i4 %and.1, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 > -1 + ; %c.1, %c.2 should only be replaced in the bitwise OR case + %c.2 = icmp sgt i4 %x, 0 + %c.3 = icmp sgt i4 %y, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ret void + +end: + ; fact: %and.1 <= -1 + ret void +} diff --git a/llvm/test/Transforms/ConstraintElimination/mixed-and-or.ll b/llvm/test/Transforms/ConstraintElimination/mixed-and-or.ll new file mode 100644 index 0000000000000..4c847077d3be4 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/mixed-and-or.ll @@ -0,0 +1,162 @@ +; 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 @test_decompose_mixed_bitwise_and_or(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_mixed_bitwise_and_or( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[AND_1]], [[Z:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i4 [[OR_1]], -1 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: [[C_2:%.*]] = icmp sgt i4 [[X]], -1 +; CHECK-NEXT: [[C_3:%.*]] = icmp sgt i4 [[Y]], -1 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %y, %x + %or.1 = or i4 %and.1, %z + %c.1= icmp sgt i4 %or.1, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.1 > -1 => %and.1 >= 0 && %z >= 0 + ; %and.1 >= 0 => %x >= 0 || %y >= 0 (constraint system doesn't support logical OR) + %c.2 = icmp sgt i4 %x, -1 + %c.3 = icmp sgt i4 %y, -1 + %t.1 = icmp sgt i4 %z, -1 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ; only %t.1 can be replaced + call void @use(i1 %t.1) + ret void + +end: + ret void +} + +define void @test_decompose_mixed_bitwise_and_or2(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_mixed_bitwise_and_or2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[AND_1]], [[Z:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i4 [[OR_1]], 0 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: [[C_2:%.*]] = icmp sgt i4 [[X]], -1 +; CHECK-NEXT: [[C_3:%.*]] = icmp sgt i4 [[Y]], -1 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %and.1 = and i4 %y, %x + %or.1 = or i4 %and.1, %z + %c.1 = icmp slt i4 %or.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.1 < 0 + ret void + +end: + ; fact: %or.1 >= 0 => %and.1 >= 0 && %z >= 0 + ; %and.1 >= 0 => %x >= 0 || %y >= 0 (constraint system doesn't support logical OR) + %c.2 = icmp sgt i4 %x, -1 + %c.3 = icmp sgt i4 %y, -1 + %t.1 = icmp sgt i4 %z, -1 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ; only %t.1 can be replaced + call void @use(i1 %t.1) + ret void +} + +define void @test_decompose_mixed_bitwise_and_or3(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_mixed_bitwise_and_or3( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[OR_1]], [[Z:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i4 [[AND_1]], 0 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: [[C_2:%.*]] = icmp slt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp slt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %y, %x + %and.1 = and i4 %or.1, %z + %c.1= icmp slt i4 %and.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 < 0 => %or.1 < 0 && %z < 0 + ; %or.1 < 0 => %x < 0 || %y < 0 (constraint system doesn't support logical OR) + %c.2 = icmp slt i4 %x, 0 + %c.3 = icmp slt i4 %y, 0 + %t.1 = icmp slt i4 %z, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ; only %t.1 can be replaced + call void @use(i1 %t.1) + ret void + +end: + ret void +} + +define void @test_decompose_mixed_bitwise_and_or4(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_mixed_bitwise_and_or4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[AND_1:%.*]] = and i4 [[OR_1]], [[Z:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i4 [[AND_1]], -1 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: [[C_2:%.*]] = icmp slt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp slt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %y, %x + %and.1 = and i4 %or.1, %z + %c.1 = icmp sgt i4 %and.1, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %and.1 > -1 + ret void + +end: + ; fact: %and.1 <= -1 => %or.1 < 0 && %z < 0 + ; %or.1 < 0 => %x < 0 || %y < 0 (constraint system doesn't support logical OR) + %c.2 = icmp slt i4 %x, 0 + %c.3 = icmp slt i4 %y, 0 + %t.1 = icmp slt i4 %z, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ; only %t.1 can be replaced + call void @use(i1 %t.1) + ret void +} diff --git a/llvm/test/Transforms/ConstraintElimination/or.ll b/llvm/test/Transforms/ConstraintElimination/or.ll index b401d6f181369..51abf034bd62c 100644 --- a/llvm/test/Transforms/ConstraintElimination/or.ll +++ b/llvm/test/Transforms/ConstraintElimination/or.ll @@ -808,3 +808,206 @@ end: ; preds = %entry ret void } + +define void @test_decompose_bitwise_or(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_or( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = or i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[OR_NOT:%.*]] = icmp sgt i4 [[TMP0]], -1 +; CHECK-NEXT: br i1 [[OR_NOT]], label [[END:%.*]], label [[THEN:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %x, %y + %c.1 = icmp sgt i4 %or.1, -1 + br i1 %c.1, label %then, label %end + +then: + %t.1 = icmp sgt i4 %x, -1 + %t.2 = icmp sgt i4 %y, -1 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + ret void + +end: + ret void +} + +define void @test_decompose_bitwise_or2(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_or2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = or i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[OR:%.*]] = icmp slt i4 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[OR]], label [[BB1:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %y, %x + %c.1 = icmp slt i4 %or.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.1 < 0 + ret void + +end: + ; fact: %or.1 >= 0 + %t.1 = icmp sgt i4 %x, -1 + %t.2 = icmp sgt i4 %y, -1 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + ret void +} + +define void @test_decompose_nested_bitwise_or(i4 %x, i4 %y, i4 %z) { +; CHECK-LABEL: @test_decompose_nested_bitwise_or( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = or i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i4 [[TMP0]], [[Z:%.*]] +; CHECK-NEXT: [[OR_2_NOT:%.*]] = icmp sgt i4 [[TMP1]], -1 +; CHECK-NEXT: br i1 [[OR_2_NOT]], label [[F:%.*]], label [[T:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %x, %y + %or.2 = or i4 %or.1, %z + %c.1 = icmp sgt i4 %or.2, -1 + br i1 %c.1, label %then, label %end + +then: ; preds = %entry + %t.1 = icmp sgt i4 %x, -1 + %t.2 = icmp sgt i4 %y, -1 + %t.3 = icmp sgt i4 %z, -1 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + call void @use(i1 %t.3) + ret void + +end: ; preds = %entry + ret void +} + +define void @test_decompose_nested_bitwise_or2(i4 %x, i4 %y, i4 %z, i4 %w) { +; CHECK-LABEL: @test_decompose_nested_bitwise_or2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = or i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i4 [[TMP0]], [[Z:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i4 [[TMP1]], [[W:%.*]] +; CHECK-NEXT: [[OR:%.*]] = icmp slt i4 [[TMP2]], 0 +; CHECK-NEXT: br i1 [[OR]], label [[BB1:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: call void @use(i1 true) +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %y, %x + %or.2 = or i4 %or.1, %z + %or.3 = or i4 %or.2, %w + %c.1 = icmp slt i4 %or.3, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.3 < 0 + ret void + +end: + ; fact: %or.3 >= 0 same as %or.3 > -1 + %t.1 = icmp sgt i4 %x, -1 + %t.2 = icmp sgt i4 %y, -1 + %t.3 = icmp sgt i4 %z, -1 + %t.4 = icmp sgt i4 %w, -1 + call void @use(i1 %t.1) + call void @use(i1 %t.2) + call void @use(i1 %t.3) + call void @use(i1 %t.4) + ret void +} + +define void @test_decompose_bitwise_or_negative(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_or_negative( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i4 [[OR_1]], -1 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: [[C_2:%.*]] = icmp slt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp slt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %x, %y + %c.1 = icmp sgt i4 %or.1, -1 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.1 > -1 + ret void + +end: + ; fact: %or.1 <= -1 + ; %c.2, %c.3 should only be replaced in the bitwise AND case + %c.2 = icmp slt i4 %x, 0 + %c.3 = icmp slt i4 %y, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ret void +} + +define void @test_decompose_bitwise_or_negative2(i4 %x, i4 %y) { +; CHECK-LABEL: @test_decompose_bitwise_or_negative2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[OR_1:%.*]] = or i4 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[C_1:%.*]] = icmp slt i4 [[OR_1]], 0 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[END:%.*]] +; CHECK: then: +; CHECK-NEXT: [[C_2:%.*]] = icmp slt i4 [[X]], 0 +; CHECK-NEXT: [[C_3:%.*]] = icmp slt i4 [[Y]], 0 +; CHECK-NEXT: call void @use(i1 [[C_2]]) +; CHECK-NEXT: call void @use(i1 [[C_3]]) +; CHECK-NEXT: ret void +; CHECK: end: +; CHECK-NEXT: ret void +; +entry: + %or.1 = or i4 %y, %x + %c.1 = icmp slt i4 %or.1, 0 + br i1 %c.1, label %then, label %end + +then: + ; fact: %or.1 < 0 + ; %c.2, %c.3 should only be replaced in the bitwise AND case + %c.2 = icmp slt i4 %x, 0 + %c.3 = icmp slt i4 %y, 0 + call void @use(i1 %c.2) + call void @use(i1 %c.3) + ret void + +end: + ; fact: %or.1 >= 0 + ret void +}