summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2014-04-22 12:45:42 +0000
committerTim Northover <tnorthover@apple.com>2014-04-22 12:45:42 +0000
commit8b36f98fd5e701b902b2981a324ed014e80fd121 (patch)
tree0ca784f307a9ab5fe7d9ec1533879b77ac3d7ff1 /lib
parentc499ecd1d18a75b0ba30c9a7aaecaadd2f782d5d (diff)
downloadllvm-8b36f98fd5e701b902b2981a324ed014e80fd121.tar.gz
llvm-8b36f98fd5e701b902b2981a324ed014e80fd121.tar.bz2
llvm-8b36f98fd5e701b902b2981a324ed014e80fd121.tar.xz
AArch64/ARM64: make use of ANDS and BICS instructions for comparisons.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206888 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Target/ARM64/ARM64ExpandPseudoInsts.cpp8
-rw-r--r--lib/Target/ARM64/ARM64ISelLowering.cpp31
-rw-r--r--lib/Target/ARM64/ARM64InstrFormats.td12
-rw-r--r--lib/Target/ARM64/ARM64InstrInfo.td8
4 files changed, 42 insertions, 17 deletions
diff --git a/lib/Target/ARM64/ARM64ExpandPseudoInsts.cpp b/lib/Target/ARM64/ARM64ExpandPseudoInsts.cpp
index e082baf8ae..7928c7e586 100644
--- a/lib/Target/ARM64/ARM64ExpandPseudoInsts.cpp
+++ b/lib/Target/ARM64/ARM64ExpandPseudoInsts.cpp
@@ -580,6 +580,10 @@ bool ARM64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
case ARM64::ANDXrr:
case ARM64::BICWrr:
case ARM64::BICXrr:
+ case ARM64::ANDSWrr:
+ case ARM64::ANDSXrr:
+ case ARM64::BICSWrr:
+ case ARM64::BICSXrr:
case ARM64::EONWrr:
case ARM64::EONXrr:
case ARM64::EORWrr:
@@ -604,6 +608,10 @@ bool ARM64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
case ARM64::ANDXrr: Opcode = ARM64::ANDXrs; break;
case ARM64::BICWrr: Opcode = ARM64::BICWrs; break;
case ARM64::BICXrr: Opcode = ARM64::BICXrs; break;
+ case ARM64::ANDSWrr: Opcode = ARM64::ANDSWrs; break;
+ case ARM64::ANDSXrr: Opcode = ARM64::ANDSXrs; break;
+ case ARM64::BICSWrr: Opcode = ARM64::BICSWrs; break;
+ case ARM64::BICSXrr: Opcode = ARM64::BICSXrs; break;
case ARM64::EONWrr: Opcode = ARM64::EONWrs; break;
case ARM64::EONXrr: Opcode = ARM64::EONXrs; break;
case ARM64::EORWrr: Opcode = ARM64::EORWrs; break;
diff --git a/lib/Target/ARM64/ARM64ISelLowering.cpp b/lib/Target/ARM64/ARM64ISelLowering.cpp
index 5aa3a3652d..9ff9567ac2 100644
--- a/lib/Target/ARM64/ARM64ISelLowering.cpp
+++ b/lib/Target/ARM64/ARM64ISelLowering.cpp
@@ -918,23 +918,32 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
// SUBS means that it's possible to get CSE with subtract operations.
// A later phase can perform the optimization of setting the destination
// register to WZR/XZR if it ends up being unused.
-
- // We'd like to combine a (CMP op1, (sub 0, op2) into a CMN instruction on the
- // grounds that "op1 - (-op2) == op1 + op2". However, the C and V flags can be
- // set differently by this operation. It comes down to whether "SInt(~op2)+1
- // == SInt(~op2+1)" (and the same for UInt). If they are then everything is
- // fine. If not then the optimization is wrong. Thus general comparisons are
- // only valid if op2 != 0.
-
- // So, finally, the only LLVM-native comparisons that don't mention C and V
- // are SETEQ and SETNE. They're the only ones we can safely use CMN for in the
- // absence of information about op2.
unsigned Opcode = ARM64ISD::SUBS;
+
if (RHS.getOpcode() == ISD::SUB && isa<ConstantSDNode>(RHS.getOperand(0)) &&
cast<ConstantSDNode>(RHS.getOperand(0))->getZExtValue() == 0 &&
(CC == ISD::SETEQ || CC == ISD::SETNE)) {
+ // We'd like to combine a (CMP op1, (sub 0, op2) into a CMN instruction on
+ // the grounds that "op1 - (-op2) == op1 + op2". However, the C and V flags
+ // can be set differently by this operation. It comes down to whether
+ // "SInt(~op2)+1 == SInt(~op2+1)" (and the same for UInt). If they are then
+ // everything is fine. If not then the optimization is wrong. Thus general
+ // comparisons are only valid if op2 != 0.
+
+ // So, finally, the only LLVM-native comparisons that don't mention C and V
+ // are SETEQ and SETNE. They're the only ones we can safely use CMN for in
+ // the absence of information about op2.
Opcode = ARM64ISD::ADDS;
RHS = RHS.getOperand(1);
+ } else if (LHS.getOpcode() == ISD::AND && isa<ConstantSDNode>(RHS) &&
+ cast<ConstantSDNode>(RHS)->getZExtValue() == 0 &&
+ !isUnsignedIntSetCC(CC)) {
+ // Similarly, (CMP (and X, Y), 0) can be implemented with a TST
+ // (a.k.a. ANDS) except that the flags are only guaranteed to work for one
+ // of the signed comparisons.
+ Opcode = ARM64ISD::ANDS;
+ RHS = LHS.getOperand(1);
+ LHS = LHS.getOperand(0);
}
return DAG.getNode(Opcode, dl, DAG.getVTList(VT, MVT::i32), LHS, RHS)
diff --git a/lib/Target/ARM64/ARM64InstrFormats.td b/lib/Target/ARM64/ARM64InstrFormats.td
index 696b15fbf3..e6239fcbc5 100644
--- a/lib/Target/ARM64/ARM64InstrFormats.td
+++ b/lib/Target/ARM64/ARM64InstrFormats.td
@@ -1798,12 +1798,18 @@ multiclass LogicalReg<bits<2> opc, bit N, string mnemonic,
}
// Split from LogicalReg to allow setting CPSR Defs
-multiclass LogicalRegS<bits<2> opc, bit N, string mnemonic> {
+multiclass LogicalRegS<bits<2> opc, bit N, string mnemonic,
+ SDPatternOperator OpNode = null_frag> {
let Defs = [CPSR], mayLoad = 0, mayStore = 0, hasSideEffects = 0 in {
- def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic, []>{
+ def Wrr : BaseLogicalRegPseudo<GPR32, OpNode>;
+ def Xrr : BaseLogicalRegPseudo<GPR64, OpNode>;
+
+ def Wrs : BaseLogicalSReg<opc, N, GPR32, logical_shifted_reg32, mnemonic,
+ [(set GPR32:$Rd, (OpNode GPR32:$Rn, logical_shifted_reg32:$Rm))]> {
let Inst{31} = 0;
}
- def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic, []>{
+ def Xrs : BaseLogicalSReg<opc, N, GPR64, logical_shifted_reg64, mnemonic,
+ [(set GPR64:$Rd, (OpNode GPR64:$Rn, logical_shifted_reg64:$Rm))]> {
let Inst{31} = 1;
}
} // Defs = [CPSR]
diff --git a/lib/Target/ARM64/ARM64InstrInfo.td b/lib/Target/ARM64/ARM64InstrInfo.td
index 1d894eff14..9cfb38f48f 100644
--- a/lib/Target/ARM64/ARM64InstrInfo.td
+++ b/lib/Target/ARM64/ARM64InstrInfo.td
@@ -125,7 +125,8 @@ def ARM64sbc : SDNode<"ARM64ISD::SBC", SDTBinaryArithWithFlagsIn>;
def ARM64add_flag : SDNode<"ARM64ISD::ADDS", SDTBinaryArithWithFlagsOut,
[SDNPCommutative]>;
def ARM64sub_flag : SDNode<"ARM64ISD::SUBS", SDTBinaryArithWithFlagsOut>;
-def ARM64and_flag : SDNode<"ARM64ISD::ANDS", SDTBinaryArithWithFlagsOut>;
+def ARM64and_flag : SDNode<"ARM64ISD::ANDS", SDTBinaryArithWithFlagsOut,
+ [SDNPCommutative]>;
def ARM64adc_flag : SDNode<"ARM64ISD::ADCS", SDTBinaryArithWithFlagsInOut>;
def ARM64sbc_flag : SDNode<"ARM64ISD::SBCS", SDTBinaryArithWithFlagsInOut>;
@@ -619,8 +620,9 @@ def : InstAlias<"mov $dst, $imm", (ORRXri GPR64sp:$dst, XZR,
// (register)
-defm ANDS : LogicalRegS<0b11, 0, "ands">;
-defm BICS : LogicalRegS<0b11, 1, "bics">;
+defm ANDS : LogicalRegS<0b11, 0, "ands", ARM64and_flag>;
+defm BICS : LogicalRegS<0b11, 1, "bics",
+ BinOpFrag<(ARM64and_flag node:$LHS, (not node:$RHS))>>;
defm AND : LogicalReg<0b00, 0, "and", and>;
defm BIC : LogicalReg<0b00, 1, "bic",
BinOpFrag<(and node:$LHS, (not node:$RHS))>>;