1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00

Re-enable the CMN instruction.

We turned off the CMN instruction because it had semantics which we weren't
getting correct. If we are comparing with an immediate, then it's okay to use
the CMN instruction.
<rdar://problem/7569620>

llvm-svn: 158302
This commit is contained in:
Bill Wendling 2012-06-11 08:07:26 +00:00
parent f350a319b9
commit 2320ff76d7
6 changed files with 166 additions and 69 deletions

View File

@ -1420,12 +1420,12 @@ bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value,
if (!UseImm) if (!UseImm)
CmpOpc = ARM::t2CMPrr; CmpOpc = ARM::t2CMPrr;
else else
CmpOpc = isNegativeImm ? ARM::t2CMNzri : ARM::t2CMPri; CmpOpc = isNegativeImm ? ARM::t2CMNri : ARM::t2CMPri;
} else { } else {
if (!UseImm) if (!UseImm)
CmpOpc = ARM::CMPrr; CmpOpc = ARM::CMPrr;
else else
CmpOpc = isNegativeImm ? ARM::CMNzri : ARM::CMPri; CmpOpc = isNegativeImm ? ARM::CMNri : ARM::CMPri;
} }
break; break;
} }

View File

@ -895,6 +895,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG";
case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD"; case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD";
case ARMISD::CMP: return "ARMISD::CMP"; case ARMISD::CMP: return "ARMISD::CMP";
case ARMISD::CMN: return "ARMISD::CMN";
case ARMISD::CMPZ: return "ARMISD::CMPZ"; case ARMISD::CMPZ: return "ARMISD::CMPZ";
case ARMISD::CMPFP: return "ARMISD::CMPFP"; case ARMISD::CMPFP: return "ARMISD::CMPFP";
case ARMISD::CMPFPw0: return "ARMISD::CMPFPw0"; case ARMISD::CMPFPw0: return "ARMISD::CMPFPw0";

View File

@ -56,6 +56,7 @@ namespace llvm {
PIC_ADD, // Add with a PC operand and a PIC label. PIC_ADD, // Add with a PC operand and a PIC label.
CMP, // ARM compare instructions. CMP, // ARM compare instructions.
CMN, // ARM CMN instructions.
CMPZ, // ARM compare that sets only Z flag. CMPZ, // ARM compare that sets only Z flag.
CMPFP, // ARM VFP compare instruction, sets FPSCR. CMPFP, // ARM VFP compare instruction, sets FPSCR.
CMPFPw0, // ARM VFP compare against zero instruction, sets FPSCR. CMPFPw0, // ARM VFP compare against zero instruction, sets FPSCR.

View File

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

View File

@ -2849,20 +2849,64 @@ def : T2Pat<(ARMcmpZ GPRnopc:$lhs, rGPR:$rhs),
def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_reg:$rhs), def : T2Pat<(ARMcmpZ GPRnopc:$lhs, t2_so_reg:$rhs),
(t2CMPrs GPRnopc:$lhs, t2_so_reg:$rhs)>; (t2CMPrs GPRnopc:$lhs, t2_so_reg:$rhs)>;
//FIXME: Disable CMN, as CCodes are backwards from compare expectations let isCompare = 1, Defs = [CPSR] in {
// Compare-to-zero still works out, just not the relationals // shifted imm
//defm t2CMN : T2I_cmp_irs<0b1000, "cmn", def t2CMNri : T2OneRegCmpImm<
// BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>; (outs), (ins GPRnopc:$Rn, t2_so_imm:$imm), IIC_iCMPi,
defm t2CMNz : T2I_cmp_irs<0b1000, "cmn", "cmn", ".w\t$Rn, $imm",
IIC_iCMPi, IIC_iCMPr, IIC_iCMPsi, [(ARMcmn GPRnopc:$Rn, (ineg t2_so_imm:$imm))]> {
BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>, let Inst{31-27} = 0b11110;
"t2CMNz">; let Inst{25} = 0;
let Inst{24-21} = 0b1000;
let Inst{20} = 1; // The S bit.
let Inst{15} = 0;
let Inst{11-8} = 0b1111; // Rd
}
// register
def t2CMNzrr : T2TwoRegCmp<
(outs), (ins GPRnopc:$Rn, rGPR:$Rm), IIC_iCMPr,
"cmn", ".w\t$Rn, $Rm",
[(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
GPRnopc:$Rn, rGPR:$Rm)]> {
let Inst{31-27} = 0b11101;
let Inst{26-25} = 0b01;
let Inst{24-21} = 0b1000;
let Inst{20} = 1; // The S bit.
let Inst{14-12} = 0b000; // imm3
let Inst{11-8} = 0b1111; // Rd
let Inst{7-6} = 0b00; // imm2
let Inst{5-4} = 0b00; // type
}
// shifted register
def t2CMNzrs : T2OneRegCmpShiftedReg<
(outs), (ins GPRnopc:$Rn, t2_so_reg:$ShiftedRm), IIC_iCMPsi,
"cmn", ".w\t$Rn, $ShiftedRm",
[(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
GPRnopc:$Rn, t2_so_reg:$ShiftedRm)]> {
let Inst{31-27} = 0b11101;
let Inst{26-25} = 0b01;
let Inst{24-21} = 0b1000;
let Inst{20} = 1; // The S bit.
let Inst{11-8} = 0b1111; // Rd
}
}
//def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm), // Assembler aliases w/o the ".w" suffix.
// (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>; // No alias here for 'rr' version as not all instantiations of this multiclass
// want one (CMP in particular, does not).
def : t2InstAlias<!strconcat("cmn", "${p}", " $Rn, $imm"),
(!cast<Instruction>(!strconcat("t2CMN", "ri")) GPRnopc:$Rn,
t2_so_imm:$imm, pred:$p)>;
def : t2InstAlias<!strconcat("cmn", "${p}", " $Rn, $shift"),
(!cast<Instruction>(!strconcat("t2CMNz", "rs")) GPRnopc:$Rn,
t2_so_reg:$shift,
pred:$p)>;
def : T2Pat<(ARMcmpZ GPRnopc:$src, t2_so_imm_neg:$imm), def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm),
(t2CMNzri GPRnopc:$src, t2_so_imm_neg:$imm)>; (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
def : T2Pat<(ARMcmpZ GPRnopc:$src, t2_so_imm_neg:$imm),
(t2CMNri GPRnopc:$src, t2_so_imm_neg:$imm)>;
defm t2TST : T2I_cmp_irs<0b0000, "tst", defm t2TST : T2I_cmp_irs<0b0000, "tst",
IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi, IIC_iTSTi, IIC_iTSTr, IIC_iTSTsi,
@ -4224,7 +4268,7 @@ def : t2InstAlias<"add${s}${p} $Rd, $imm",
pred:$p, cc_out:$s)>; pred:$p, cc_out:$s)>;
// Same for CMP <--> CMN via t2_so_imm_neg // Same for CMP <--> CMN via t2_so_imm_neg
def : t2InstAlias<"cmp${p} $Rd, $imm", def : t2InstAlias<"cmp${p} $Rd, $imm",
(t2CMNzri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>; (t2CMNri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>;
def : t2InstAlias<"cmn${p} $Rd, $imm", def : t2InstAlias<"cmn${p} $Rd, $imm",
(t2CMPri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>; (t2CMPri rGPR:$Rd, t2_so_imm_neg:$imm, pred:$p)>;

22
test/CodeGen/ARM/cmn.ll Normal file
View File

@ -0,0 +1,22 @@
; RUN: llc < %s -mtriple thumbv7-apple-ios | FileCheck %s
; <rdar://problem/7569620>
define i32 @compare_i_gt(i32 %a) {
entry:
; CHECK: compare_i_gt
; CHECK-NOT: mvn
; CHECK: cmn
%cmp = icmp sgt i32 %a, -78
%. = zext i1 %cmp to i32
ret i32 %.
}
define i32 @compare_r_eq(i32 %a, i32 %b) {
entry:
; CHECK: compare_r_eq
; CHECK: cmn
%sub = sub nsw i32 0, %b
%cmp = icmp eq i32 %a, %sub
%. = zext i1 %cmp to i32
ret i32 %.
}