diff options
Diffstat (limited to 'lib/Target/ARM/ARMInstrInfo.td')
-rw-r--r-- | lib/Target/ARM/ARMInstrInfo.td | 137 |
1 files changed, 83 insertions, 54 deletions
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 8ffb5752c8..50ae826a38 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -128,6 +128,9 @@ def ARMBcci64 : SDNode<"ARMISD::BCC_i64", SDT_ARMBCC_i64, def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp, [SDNPOutGlue]>; +def ARMcmn : SDNode<"ARMISD::CMN", SDT_ARMCmp, + [SDNPOutGlue]>; + def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp, [SDNPOutGlue, SDNPCommutative]>; @@ -3842,49 +3845,85 @@ def : ARMPat<(ARMcmpZ GPR:$src, so_reg_imm:$rhs), def : ARMPat<(ARMcmpZ GPR:$src, so_reg_reg:$rhs), (CMPrsr GPR:$src, so_reg_reg:$rhs)>; -// FIXME: We have to be careful when using the CMN instruction and comparison -// with 0. One would expect these two pieces of code should give identical -// results: -// -// rsbs r1, r1, 0 -// cmp r0, r1 -// mov r0, #0 -// it ls -// mov r0, #1 -// -// and: -// -// cmn r0, r1 -// mov r0, #0 -// it ls -// mov r0, #1 -// -// However, the CMN gives the *opposite* result when r1 is 0. This is because -// the carry flag is set in the CMP case but not in the CMN case. In short, the -// CMP instruction doesn't perform a truncate of the (logical) NOT of 0 plus the -// value of r0 and the carry bit (because the "carry bit" parameter to -// AddWithCarry is defined as 1 in this case, the carry flag will always be set -// when r0 >= 0). The CMN instruction doesn't perform a NOT of 0 so there is -// never a "carry" when this AddWithCarry is performed (because the "carry bit" -// parameter to AddWithCarry is defined as 0). -// -// When x is 0 and unsigned: -// -// x = 0 -// ~x = 0xFFFF FFFF -// ~x + 1 = 0x1 0000 0000 -// (-x = 0) != (0x1 0000 0000 = ~x + 1) -// -// Therefore, we should disable CMN when comparing against zero, until we can -// limit when the CMN instruction is used (when we know that the RHS is not 0 or -// when it's a comparison which doesn't look at the 'carry' flag). -// -// (See the ARM docs for the "AddWithCarry" pseudo-code.) -// -// This is related to <rdar://problem/7569620>. -// -//defm CMN : AI1_cmp_irs<0b1011, "cmn", -// BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>; +// CMN register-integer +let isCompare = 1, Defs = [CPSR] in { +def CMNri : AI1<0b1011, (outs), (ins GPR:$Rn, so_imm:$imm), DPFrm, IIC_iCMPi, + "cmn", "\t$Rn, $imm", + [(ARMcmn GPR:$Rn, so_imm:$imm)]> { + bits<4> Rn; + bits<12> imm; + let Inst{25} = 1; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-0} = imm; + + let Unpredictable{15-12} = 0b1111; +} + +// CMN register-register/shift +def CMNzrr : AI1<0b1011, (outs), (ins GPR:$Rn, GPR:$Rm), DPFrm, IIC_iCMPr, + "cmn", "\t$Rn, $Rm", + [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))> + GPR:$Rn, GPR:$Rm)]> { + bits<4> Rn; + bits<4> Rm; + let isCommutable = 1; + let Inst{25} = 0; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rm; + + let Unpredictable{15-12} = 0b1111; +} + +def CMNzrsi : AI1<0b1011, (outs), + (ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, IIC_iCMPsr, + "cmn", "\t$Rn, $shift", + [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))> + GPR:$Rn, so_reg_imm:$shift)]> { + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-5} = shift{11-5}; + let Inst{4} = 0; + let Inst{3-0} = shift{3-0}; + + let Unpredictable{15-12} = 0b1111; +} + +def CMNzrsr : AI1<0b1011, (outs), + (ins GPRnopc:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, IIC_iCMPsr, + "cmn", "\t$Rn, $shift", + [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))> + GPRnopc:$Rn, so_reg_reg:$shift)]> { + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-8} = shift{11-8}; + let Inst{7} = 0; + let Inst{6-5} = shift{6-5}; + let Inst{4} = 1; + let Inst{3-0} = shift{3-0}; + + let Unpredictable{15-12} = 0b1111; +} + +} + +def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm), + (CMNri GPR:$src, so_imm_neg:$imm)>; + +def : ARMPat<(ARMcmpZ GPR:$src, so_imm_neg:$imm), + (CMNri GPR:$src, so_imm_neg:$imm)>; // Note that TST/TEQ don't set all the same flags that CMP does! defm TST : AI1_cmp_irs<0b1000, "tst", @@ -3894,16 +3933,6 @@ defm TEQ : AI1_cmp_irs<0b1001, "teq", IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr, BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>, 1>; -defm CMNz : AI1_cmp_irs<0b1011, "cmn", - IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr, - BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>; - -//def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm), -// (CMNri GPR:$src, so_imm_neg:$imm)>; - -def : ARMPat<(ARMcmpZ GPR:$src, so_imm_neg:$imm), - (CMNzri GPR:$src, so_imm_neg:$imm)>; - // Pseudo i64 compares for some floating point compares. let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, Defs = [CPSR] in { @@ -5052,7 +5081,7 @@ def : ARMInstAlias<"add${s}${p} $Rd, $imm", (SUBri GPR:$Rd, GPR:$Rd, so_imm_neg:$imm, pred:$p, cc_out:$s)>; // Same for CMP <--> CMN via so_imm_neg def : ARMInstAlias<"cmp${p} $Rd, $imm", - (CMNzri rGPR:$Rd, so_imm_neg:$imm, pred:$p)>; + (CMNri rGPR:$Rd, so_imm_neg:$imm, pred:$p)>; def : ARMInstAlias<"cmn${p} $Rd, $imm", (CMPri rGPR:$Rd, so_imm_neg:$imm, pred:$p)>; |