return replaceOperand(BI, 0, X);
}
- // br (X && !Y), T, F --> br ((X && Y) || !X), F, T
+ // Canonicalize logical-and-with-invert as logical-or-with-invert.
+ // This is done by inverting the condition and swapping successors:
+ // br (X && !Y), T, F --> br !(X && !Y), F, T --> br (!X || Y), F, T
Value *Y;
if (isa<SelectInst>(Cond) &&
- match(Cond, m_OneUse(m_LogicalAnd(m_Value(X), m_Not(m_Value(Y)))))) {
- Value *AndOr = Builder.CreateSelect(X, Y, Builder.getTrue());
+ match(Cond,
+ m_OneUse(m_LogicalAnd(m_Value(X), m_OneUse(m_Not(m_Value(Y))))))) {
+ Value *NotX = Builder.CreateNot(X, "not." + X->getName());
+ Value *Or = Builder.CreateLogicalOr(NotX, Y);
BI.swapSuccessors();
- return replaceOperand(BI, 0, AndOr);
+ return replaceOperand(BI, 0, Or);
}
// If the condition is irrelevant, remove the use so that other
ret i32 3
}
+; negative test
+
define i32 @logical_and_not_use1(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_and_not_use1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
; CHECK-NEXT: call void @use(i1 [[NOTY]])
-; CHECK-NEXT: [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
-; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[Y]]
-; CHECK-NEXT: br i1 [[TMP0]], label [[F:%.*]], label [[T:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[NOTY]], i1 false
+; CHECK-NEXT: br i1 [[AND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f: