[AArch64] Lower disjoint_or+not to eon. (#147279)
A disjoint OR can be transformed to an EOR.
We already lower EOR+NOT to EON, but not DisjointOR+NOT.
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 9ac2281..7ff8ca9 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -1140,6 +1140,19 @@
def vnot : PatFrag<(ops node:$in), (xor node:$in, immAllOnesV)>;
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();
+}]> {
+ let GISelPredicateCode = [{
+ return MI.getFlag(MachineInstr::Disjoint);
+ }];
+}
+
+def xor_like : PatFrags<(ops node:$lhs, node:$rhs),
+ [(xor node:$lhs, node:$rhs),
+ (or_disjoint node:$lhs, node:$rhs)]>;
+
def zanyext : PatFrags<(ops node:$op),
[(zext node:$op),
(anyext node:$op)]>;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 811877f..1f70890 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -3118,7 +3118,7 @@
defm BIC : LogicalReg<0b00, 1, "bic",
BinOpFrag<(and node:$LHS, (not node:$RHS))>, 3>;
defm EON : LogicalReg<0b10, 1, "eon",
- BinOpFrag<(not (xor node:$LHS, node:$RHS))>>;
+ BinOpFrag<(not (xor_like node:$LHS, node:$RHS))>>;
defm EOR : LogicalReg<0b10, 0, "eor", xor>;
defm ORN : LogicalReg<0b01, 1, "orn",
BinOpFrag<(or node:$LHS, (not node:$RHS))>>;
diff --git a/llvm/test/CodeGen/AArch64/eon.ll b/llvm/test/CodeGen/AArch64/eon.ll
index 3468a0f..8b31cbf 100644
--- a/llvm/test/CodeGen/AArch64/eon.ll
+++ b/llvm/test/CodeGen/AArch64/eon.ll
@@ -30,3 +30,24 @@
%shl2 = shl i64 %xor, %xor1
ret i64 %shl2
}
+
+; Check that eon is generated if the xor is a disjoint or.
+define i64 @disjoint_or(i64 %a, i64 %b) {
+; CHECK-LABEL: disjoint_or:
+; CHECK: eon
+; CHECK: ret
+ %or = or disjoint i64 %a, %b
+ %eon = xor i64 %or, -1
+ ret i64 %eon
+}
+
+; Check that eon is *not* generated if the or is not disjoint.
+define i64 @normal_or(i64 %a, i64 %b) {
+; CHECK-LABEL: normal_or:
+; CHECK: orr
+; CHECK: mvn
+; CHECK: ret
+ %or = or i64 %a, %b
+ %not = xor i64 %or, -1
+ ret i64 %not
+}
diff --git a/llvm/test/TableGen/GlobalISelEmitter/CustomPredicate.td b/llvm/test/TableGen/GlobalISelEmitter/CustomPredicate.td
index 56eaa4b..2dd9286 100644
--- a/llvm/test/TableGen/GlobalISelEmitter/CustomPredicate.td
+++ b/llvm/test/TableGen/GlobalISelEmitter/CustomPredicate.td
@@ -6,6 +6,7 @@
// CHECK-NEXT: enum {
// CHECK-NEXT: GICXXPred_MI_Predicate_and_or_pat = GICXXPred_Invalid + 1,
// CHECK-NEXT: GICXXPred_MI_Predicate_mul_pat,
+// CHECK-NEXT: GICXXPred_MI_Predicate_or_disjoint,
// CHECK-NEXT: GICXXPred_MI_Predicate_or_oneuse,
// CHECK-NEXT: GICXXPred_MI_Predicate_patfrags_test_pat,
// CHECK-NEXT: GICXXPred_MI_Predicate_sub3_pat,
diff --git a/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
index 23e22b8..6e5d7de 100644
--- a/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter/GlobalISelEmitter.td
@@ -156,6 +156,7 @@
// CHECK-LABEL: // PatFrag predicates.
// CHECK-NEXT: enum {
// CHECK-NEXT: GICXXPred_MI_Predicate_frag = GICXXPred_Invalid + 1,
+// CHECK-NEXT: GICXXPred_MI_Predicate_or_disjoint,
// CHECK-NEXT: };
// CHECK-LABEL: // PatFrag predicates.