[DAG] Use value tracking to detect or_disjoint patterns and add a add_like pattern matcher (#187478)

Extend the generic or_disjoint pattern to call haveNoCommonBitsSet, this
allows us to remove the similar x86 or_is_add pattern, use or_disjoint
directly and merge some add/or_is_add matching patterns to use a
add_like wrapper pattern instead
This commit is contained in:
Simon Pilgrim 2026-03-19 15:37:43 +00:00 committed by GitHub
parent 4199bb1a81
commit d049eef4b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 35 additions and 42 deletions

View File

@ -1310,13 +1310,18 @@ def ineg : PatFrag<(ops node:$in), (sub 0, node:$in)>;
def or_disjoint : PatFrag<(ops node:$lhs, node:$rhs),
(or node:$lhs, node:$rhs), [{
return N->getFlags().hasDisjoint();
return N->getFlags().hasDisjoint() ||
CurDAG->haveNoCommonBitsSet(N->getOperand(0), N->getOperand(1));
}]> {
let GISelPredicateCode = [{
return MI.getFlag(MachineInstr::Disjoint);
}];
}
def add_like : PatFrags<(ops node:$lhs, node:$rhs),
[(add node:$lhs, node:$rhs),
(or_disjoint node:$lhs, node:$rhs)]>;
def xor_like : PatFrags<(ops node:$lhs, node:$rhs),
[(xor node:$lhs, node:$rhs),
(or_disjoint node:$lhs, node:$rhs)]>;

View File

@ -1539,33 +1539,33 @@ let isConvertibleToThreeAddress = 1, isPseudo = 1,
let isCommutable = 1 in {
def ADD8rr_DB : I<0, Pseudo, (outs GR8:$dst), (ins GR8:$src1, GR8:$src2),
"", // orb/addb REG, REG
[(set GR8:$dst, (or_is_add GR8:$src1, GR8:$src2))]>;
[(set GR8:$dst, (or_disjoint GR8:$src1, GR8:$src2))]>;
def ADD16rr_DB : I<0, Pseudo, (outs GR16:$dst), (ins GR16:$src1, GR16:$src2),
"", // orw/addw REG, REG
[(set GR16:$dst, (or_is_add GR16:$src1, GR16:$src2))]>;
[(set GR16:$dst, (or_disjoint GR16:$src1, GR16:$src2))]>;
def ADD32rr_DB : I<0, Pseudo, (outs GR32:$dst), (ins GR32:$src1, GR32:$src2),
"", // orl/addl REG, REG
[(set GR32:$dst, (or_is_add GR32:$src1, GR32:$src2))]>;
[(set GR32:$dst, (or_disjoint GR32:$src1, GR32:$src2))]>;
def ADD64rr_DB : I<0, Pseudo, (outs GR64:$dst), (ins GR64:$src1, GR64:$src2),
"", // orq/addq REG, REG
[(set GR64:$dst, (or_is_add GR64:$src1, GR64:$src2))]>;
[(set GR64:$dst, (or_disjoint GR64:$src1, GR64:$src2))]>;
} // isCommutable
def ADD8ri_DB : I<0, Pseudo,
(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2),
"", // orb/addb REG, imm8
[(set GR8:$dst, (or_is_add GR8:$src1, imm:$src2))]>;
[(set GR8:$dst, (or_disjoint GR8:$src1, imm:$src2))]>;
def ADD16ri_DB : I<0, Pseudo, (outs GR16:$dst), (ins GR16:$src1, i16imm:$src2),
"", // orw/addw REG, imm
[(set GR16:$dst, (or_is_add GR16:$src1, imm:$src2))]>;
[(set GR16:$dst, (or_disjoint GR16:$src1, imm:$src2))]>;
def ADD32ri_DB : I<0, Pseudo, (outs GR32:$dst), (ins GR32:$src1, i32imm:$src2),
"", // orl/addl REG, imm
[(set GR32:$dst, (or_is_add GR32:$src1, imm:$src2))]>;
[(set GR32:$dst, (or_disjoint GR32:$src1, imm:$src2))]>;
def ADD64ri32_DB : I<0, Pseudo,
(outs GR64:$dst), (ins GR64:$src1, i64i32imm:$src2),
"", // orq/addq REG, imm
[(set GR64:$dst, (or_is_add GR64:$src1,
i64immSExt32:$src2))]>;
[(set GR64:$dst, (or_disjoint GR64:$src1,
i64immSExt32:$src2))]>;
}
} // AddedComplexity, SchedRW
@ -2230,9 +2230,9 @@ multiclass EFLAGSDefiningPats<string suffix, Predicate PredNDD, Predicate PredND
// Increment/Decrement reg.
// Do not make INC/DEC if it is slow
let Predicates = [UseIncDec, PredNDD] in {
def : Pat<(add GR8:$src, 1), (!cast<Instruction>(INC8r#suffix) GR8:$src)>;
def : Pat<(add GR16:$src, 1), (!cast<Instruction>(INC16r#suffix) GR16:$src)>;
def : Pat<(add GR32:$src, 1), (!cast<Instruction>(INC32r#suffix) GR32:$src)>;
def : Pat<(add_like GR8:$src, 1), (!cast<Instruction>(INC8r#suffix) GR8:$src)>;
def : Pat<(add_like GR16:$src, 1), (!cast<Instruction>(INC16r#suffix) GR16:$src)>;
def : Pat<(add_like GR32:$src, 1), (!cast<Instruction>(INC32r#suffix) GR32:$src)>;
def : Pat<(add GR8:$src, -1), (!cast<Instruction>(DEC8r#suffix) GR8:$src)>;
def : Pat<(add GR16:$src, -1), (!cast<Instruction>(DEC16r#suffix) GR16:$src)>;
def : Pat<(add GR32:$src, -1), (!cast<Instruction>(DEC32r#suffix) GR32:$src)>;
@ -2243,18 +2243,13 @@ multiclass EFLAGSDefiningPats<string suffix, Predicate PredNDD, Predicate PredND
def : Pat<(X86sub_flag_nocf GR8:$src, -1), (!cast<Instruction>(INC8r#suffix) GR8:$src)>;
def : Pat<(X86sub_flag_nocf GR16:$src, -1), (!cast<Instruction>(INC16r#suffix) GR16:$src)>;
def : Pat<(X86sub_flag_nocf GR32:$src, -1), (!cast<Instruction>(INC32r#suffix) GR32:$src)>;
def : Pat<(or_is_add GR8:$src, 1), (!cast<Instruction>(INC8r#suffix) GR8:$src)>;
def : Pat<(or_is_add GR16:$src, 1), (!cast<Instruction>(INC16r#suffix) GR16:$src)>;
def : Pat<(or_is_add GR32:$src, 1), (!cast<Instruction>(INC32r#suffix) GR32:$src)>;
}
let Predicates = [UseIncDec, PredNDDI] in {
def : Pat<(add GR64:$src, 1), (!cast<Instruction>(INC64r#suffix) GR64:$src)>;
def : Pat<(add_like GR64:$src, 1), (!cast<Instruction>(INC64r#suffix) GR64:$src)>;
def : Pat<(add GR64:$src, -1), (!cast<Instruction>(DEC64r#suffix) GR64:$src)>;
def : Pat<(X86add_flag_nocf GR64:$src, -1), (!cast<Instruction>(DEC64r#suffix) GR64:$src)>;
def : Pat<(X86sub_flag_nocf GR64:$src, -1), (!cast<Instruction>(INC64r#suffix) GR64:$src)>;
def : Pat<(or_is_add GR64:$src, 1), (!cast<Instruction>(INC64r#suffix) GR64:$src)>;
}
}

View File

@ -850,16 +850,6 @@ def def32 : PatLeaf<(i32 GR32:$src), [{
(!N->getOperand(0).isUndef() && !isa<ConstantSDNode>(N->getOperand(0))));
}]>;
// Treat an 'or' node is as an 'add' if the or'ed bits are known to be zero.
def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
return (~Known0.Zero & ~Known1.Zero) == 0;
}]>;
def shiftMask8 : PatFrag<(ops node:$lhs), (and node:$lhs, imm), [{
return isUnneededShiftMask(N, 3);
}]>;

View File

@ -191,11 +191,12 @@ define i32 @not_a_masked_merge4(i32 %a0, i32 %a1, i32 %a2) {
define i32 @masked_merge_no_transform0(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
; NOBMI-LABEL: masked_merge_no_transform0:
; NOBMI: # %bb.0:
; NOBMI-NEXT: movl %edi, %eax
; NOBMI-NEXT: # kill: def $esi killed $esi def $rsi
; NOBMI-NEXT: # kill: def $edi killed $edi def $rdi
; NOBMI-NEXT: andl %edi, %esi
; NOBMI-NEXT: notl %eax
; NOBMI-NEXT: andl %edx, %eax
; NOBMI-NEXT: orl %esi, %eax
; NOBMI-NEXT: notl %edi
; NOBMI-NEXT: andl %edx, %edi
; NOBMI-NEXT: leal (%rdi,%rsi), %eax
; NOBMI-NEXT: movl %esi, (%rcx)
; NOBMI-NEXT: retq
;
@ -218,11 +219,12 @@ define i32 @masked_merge_no_transform0(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
define i32 @masked_merge_no_transform1(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
; NOBMI-LABEL: masked_merge_no_transform1:
; NOBMI: # %bb.0:
; NOBMI-NEXT: movl %edx, %eax
; NOBMI-NEXT: # kill: def $edx killed $edx def $rdx
; NOBMI-NEXT: # kill: def $esi killed $esi def $rsi
; NOBMI-NEXT: andl %edi, %esi
; NOBMI-NEXT: notl %edi
; NOBMI-NEXT: andl %edi, %eax
; NOBMI-NEXT: orl %esi, %eax
; NOBMI-NEXT: andl %edi, %edx
; NOBMI-NEXT: leal (%rdx,%rsi), %eax
; NOBMI-NEXT: movl %edi, (%rcx)
; NOBMI-NEXT: retq
;
@ -246,20 +248,21 @@ define i32 @masked_merge_no_transform1(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
define i32 @masked_merge_no_transform2(i32 %a0, i32 %a1, i32 %a2, ptr %p1) {
; NOBMI-LABEL: masked_merge_no_transform2:
; NOBMI: # %bb.0:
; NOBMI-NEXT: movl %esi, %eax
; NOBMI-NEXT: andl %edi, %eax
; NOBMI-NEXT: # kill: def $esi killed $esi def $rsi
; NOBMI-NEXT: # kill: def $edi killed $edi def $rdi
; NOBMI-NEXT: andl %edi, %esi
; NOBMI-NEXT: notl %edi
; NOBMI-NEXT: andl %edx, %edi
; NOBMI-NEXT: orl %edi, %eax
; NOBMI-NEXT: leal (%rsi,%rdi), %eax
; NOBMI-NEXT: movl %edi, (%rcx)
; NOBMI-NEXT: retq
;
; BMI-LABEL: masked_merge_no_transform2:
; BMI: # %bb.0:
; BMI-NEXT: movl %esi, %eax
; BMI-NEXT: andl %edi, %eax
; BMI-NEXT: # kill: def $esi killed $esi def $rsi
; BMI-NEXT: andl %edi, %esi
; BMI-NEXT: andnl %edx, %edi, %edx
; BMI-NEXT: orl %edx, %eax
; BMI-NEXT: leal (%rsi,%rdx), %eax
; BMI-NEXT: movl %edx, (%rcx)
; BMI-NEXT: retq
%and0 = and i32 %a0, %a1