mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[InstCombine] add DeMorgan folds for logical ops in select form
We canonicalized to these select patterns (poison-safe logic) with D101191, so we need to reduce 'not' ops when possible as we would with 'and'/'or' instructions. This is shown in a secondary example in: https://llvm.org/PR50389 https://alive2.llvm.org/ce/z/BvsESh
This commit is contained in:
parent
b4782a5249
commit
224787dbb2
@ -2705,6 +2705,19 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
|
||||
return SelectInst::Create(FalseVal, One, TrueVal);
|
||||
|
||||
Value *A, *B;
|
||||
|
||||
// DeMorgan in select form: !a && !b --> !(a || b)
|
||||
// select !a, !b, false --> not (select a, true, b)
|
||||
if (match(&SI, m_LogicalAnd(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
|
||||
(CondVal->hasOneUse() || TrueVal->hasOneUse()))
|
||||
return BinaryOperator::CreateNot(Builder.CreateSelect(A, One, B));
|
||||
|
||||
// DeMorgan in select form: !a || !b --> !(a && b)
|
||||
// select !a, true, !b --> not (select a, b, false)
|
||||
if (match(&SI, m_LogicalOr(m_Not(m_Value(A)), m_Not(m_Value(B)))) &&
|
||||
(CondVal->hasOneUse() || FalseVal->hasOneUse()))
|
||||
return BinaryOperator::CreateNot(Builder.CreateSelect(A, B, Zero));
|
||||
|
||||
// select (select a, true, b), true, b -> select a, true, b
|
||||
if (match(CondVal, m_Select(m_Value(A), m_One(), m_Value(B))) &&
|
||||
match(TrueVal, m_One()) && match(FalseVal, m_Specific(B)))
|
||||
|
@ -179,6 +179,8 @@ define i1 @logical_and_noundef_b(i1 %a, i1 noundef %b) {
|
||||
ret i1 %res
|
||||
}
|
||||
|
||||
; (!x && !y) || x --> x || !y
|
||||
|
||||
define i1 @not_not_true(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_not_true(
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
@ -191,11 +193,12 @@ define i1 @not_not_true(i1 %x, i1 %y) {
|
||||
ret i1 %r
|
||||
}
|
||||
|
||||
; (!x && !y) --> !(x || y)
|
||||
|
||||
define i1 @not_not_false(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_not_false(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
@ -204,11 +207,12 @@ define i1 @not_not_false(i1 %x, i1 %y) {
|
||||
ret i1 %r
|
||||
}
|
||||
|
||||
; (!x || !y) --> !(x && y)
|
||||
|
||||
define i1 @not_true_not(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_true_not(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
@ -217,6 +221,8 @@ define i1 @not_true_not(i1 %x, i1 %y) {
|
||||
ret i1 %r
|
||||
}
|
||||
|
||||
; (!!x && !y) --> x && !y
|
||||
|
||||
define i1 @not_false_not(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_false_not(
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
@ -248,8 +254,8 @@ define i1 @not_not_false_use1(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_not_false_use1(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: call void @use(i1 [[NOTX]])
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X]], i1 true, i1 [[Y:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
@ -263,8 +269,8 @@ define i1 @not_true_not_use1(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_true_not_use1(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: call void @use(i1 [[NOTX]])
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X]], i1 [[Y:%.*]], i1 false
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
@ -305,10 +311,10 @@ define i1 @not_not_true_use2(i1 %x, i1 %y) {
|
||||
|
||||
define i1 @not_not_false_use2(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_not_false_use2(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: call void @use(i1 [[NOTY]])
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 [[NOTY]], i1 false
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y]]
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
@ -320,10 +326,10 @@ define i1 @not_not_false_use2(i1 %x, i1 %y) {
|
||||
|
||||
define i1 @not_true_not_use2(i1 %x, i1 %y) {
|
||||
; CHECK-LABEL: @not_true_not_use2(
|
||||
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
|
||||
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
|
||||
; CHECK-NEXT: call void @use(i1 [[NOTY]])
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[NOTX]], i1 true, i1 [[NOTY]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y]], i1 false
|
||||
; CHECK-NEXT: [[R:%.*]] = xor i1 [[TMP1]], true
|
||||
; CHECK-NEXT: ret i1 [[R]]
|
||||
;
|
||||
%notx = xor i1 %x, true
|
||||
|
Loading…
Reference in New Issue
Block a user