mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Change ARM / Thumb2 addc / adde and subc / sube modeling to use physical
register dependency (rather than glue them together). This is general goodness as it gives scheduler more freedom. However it is motivated by a nasty bug in isel. When a i64 sub is expanded to subc + sube. libcall #1 \ \ subc \ / \ \ / \ \ / libcall #2 sube If the libcalls are not serialized (i.e. both have chains which are dag entry), legalizer can serialize them in arbitrary orders. If it's unlucky, it can force libcall #2 before libcall #1 in the above case. subc | libcall #2 | libcall #1 | sube However since subc and sube are "glued" together, this ends up being a cycle when the scheduler combine subc and sube as a single scheduling unit. The right solution is to fix LegalizeType too chains the libcalls together. However, LegalizeType is not processing nodes in order so that's harder than it should be. For now, the move to physical register dependency will do. rdar://10019576 llvm-svn: 138791
This commit is contained in:
parent
187be92001
commit
1eacb83316
@ -374,6 +374,13 @@ ARMBaseRegisterInfo::getPointerRegClass(unsigned Kind) const {
|
||||
return ARM::GPRRegisterClass;
|
||||
}
|
||||
|
||||
const TargetRegisterClass *
|
||||
ARMBaseRegisterInfo::getCrossCopyRegClass(const TargetRegisterClass *RC) const {
|
||||
if (RC == &ARM::CCRRegClass)
|
||||
return 0; // Can't copy CCR registers.
|
||||
return RC;
|
||||
}
|
||||
|
||||
unsigned
|
||||
ARMBaseRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
|
||||
MachineFunction &MF) const {
|
||||
|
@ -116,6 +116,8 @@ public:
|
||||
unsigned &NewSubIdx) const;
|
||||
|
||||
const TargetRegisterClass *getPointerRegClass(unsigned Kind = 0) const;
|
||||
const TargetRegisterClass*
|
||||
getCrossCopyRegClass(const TargetRegisterClass *RC) const;
|
||||
|
||||
const TargetRegisterClass*
|
||||
getLargestLegalSuperClass(const TargetRegisterClass *RC) const;
|
||||
|
@ -551,6 +551,14 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::SRL, MVT::i64, Custom);
|
||||
setOperationAction(ISD::SRA, MVT::i64, Custom);
|
||||
|
||||
if (!Subtarget->isThumb1Only()) {
|
||||
// FIXME: We should do this for Thumb1 as well.
|
||||
setOperationAction(ISD::ADDC, MVT::i32, Custom);
|
||||
setOperationAction(ISD::ADDE, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SUBC, MVT::i32, Custom);
|
||||
setOperationAction(ISD::SUBE, MVT::i32, Custom);
|
||||
}
|
||||
|
||||
// ARM does not have ROTL.
|
||||
setOperationAction(ISD::ROTL, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTTZ, MVT::i32, Custom);
|
||||
@ -813,6 +821,11 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
case ARMISD::SRA_FLAG: return "ARMISD::SRA_FLAG";
|
||||
case ARMISD::RRX: return "ARMISD::RRX";
|
||||
|
||||
case ARMISD::ADDC: return "ARMISD::ADDC";
|
||||
case ARMISD::ADDE: return "ARMISD::ADDE";
|
||||
case ARMISD::SUBC: return "ARMISD::SUBC";
|
||||
case ARMISD::SUBE: return "ARMISD::SUBE";
|
||||
|
||||
case ARMISD::VMOVRRD: return "ARMISD::VMOVRRD";
|
||||
case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR";
|
||||
|
||||
@ -4812,6 +4825,27 @@ static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG) {
|
||||
return N0;
|
||||
}
|
||||
|
||||
static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) {
|
||||
EVT VT = Op.getNode()->getValueType(0);
|
||||
SDVTList VTs = DAG.getVTList(VT, MVT::i32);
|
||||
|
||||
unsigned Opc;
|
||||
bool ExtraOp = false;
|
||||
switch (Op.getOpcode()) {
|
||||
default: assert(0 && "Invalid code");
|
||||
case ISD::ADDC: Opc = ARMISD::ADDC; break;
|
||||
case ISD::ADDE: Opc = ARMISD::ADDE; ExtraOp = true; break;
|
||||
case ISD::SUBC: Opc = ARMISD::SUBC; break;
|
||||
case ISD::SUBE: Opc = ARMISD::SUBE; ExtraOp = true; break;
|
||||
}
|
||||
|
||||
if (!ExtraOp)
|
||||
return DAG.getNode(Opc, Op->getDebugLoc(), VTs, Op.getOperand(0),
|
||||
Op.getOperand(1));
|
||||
return DAG.getNode(Opc, Op->getDebugLoc(), VTs, Op.getOperand(0),
|
||||
Op.getOperand(1), Op.getOperand(2));
|
||||
}
|
||||
|
||||
SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
default: llvm_unreachable("Don't know how to custom lower this!");
|
||||
@ -4859,6 +4893,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
case ISD::MUL: return LowerMUL(Op, DAG);
|
||||
case ISD::SDIV: return LowerSDIV(Op, DAG);
|
||||
case ISD::UDIV: return LowerUDIV(Op, DAG);
|
||||
case ISD::ADDC:
|
||||
case ISD::ADDE:
|
||||
case ISD::SUBC:
|
||||
case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);
|
||||
}
|
||||
return SDValue();
|
||||
}
|
||||
@ -5208,76 +5246,6 @@ MachineBasicBlock *OtherSucc(MachineBasicBlock *MBB, MachineBasicBlock *Succ) {
|
||||
llvm_unreachable("Expecting a BB with two successors!");
|
||||
}
|
||||
|
||||
// FIXME: This opcode table should obviously be expressed in the target
|
||||
// description. We probably just need a "machine opcode" value in the pseudo
|
||||
// instruction. But the ideal solution maybe to simply remove the "S" version
|
||||
// of the opcode altogether.
|
||||
struct AddSubFlagsOpcodePair {
|
||||
unsigned PseudoOpc;
|
||||
unsigned MachineOpc;
|
||||
};
|
||||
|
||||
static const AddSubFlagsOpcodePair AddSubFlagsOpcodeMap[] = {
|
||||
{ARM::ADCSri, ARM::ADCri},
|
||||
{ARM::ADCSrr, ARM::ADCrr},
|
||||
{ARM::ADCSrsi, ARM::ADCrsi},
|
||||
{ARM::ADCSrsr, ARM::ADCrsr},
|
||||
{ARM::SBCSri, ARM::SBCri},
|
||||
{ARM::SBCSrr, ARM::SBCrr},
|
||||
{ARM::SBCSrsi, ARM::SBCrsi},
|
||||
{ARM::SBCSrsr, ARM::SBCrsr},
|
||||
{ARM::RSBSri, ARM::RSBri},
|
||||
{ARM::RSBSrr, ARM::RSBrr},
|
||||
{ARM::RSBSrsi, ARM::RSBrsi},
|
||||
{ARM::RSBSrsr, ARM::RSBrsr},
|
||||
{ARM::RSCSri, ARM::RSCri},
|
||||
{ARM::RSCSrsi, ARM::RSCrsi},
|
||||
{ARM::RSCSrsr, ARM::RSCrsr},
|
||||
{ARM::t2ADCSri, ARM::t2ADCri},
|
||||
{ARM::t2ADCSrr, ARM::t2ADCrr},
|
||||
{ARM::t2ADCSrs, ARM::t2ADCrs},
|
||||
{ARM::t2SBCSri, ARM::t2SBCri},
|
||||
{ARM::t2SBCSrr, ARM::t2SBCrr},
|
||||
{ARM::t2SBCSrs, ARM::t2SBCrs},
|
||||
{ARM::t2RSBSri, ARM::t2RSBri},
|
||||
{ARM::t2RSBSrs, ARM::t2RSBrs},
|
||||
};
|
||||
|
||||
// Convert and Add or Subtract with Carry and Flags to a generic opcode with
|
||||
// CPSR<def> operand. e.g. ADCS (...) -> ADC (... CPSR<def>).
|
||||
//
|
||||
// FIXME: Somewhere we should assert that CPSR<def> is in the correct
|
||||
// position to be recognized by the target descrition as the 'S' bit.
|
||||
bool ARMTargetLowering::RemapAddSubWithFlags(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const {
|
||||
unsigned OldOpc = MI->getOpcode();
|
||||
unsigned NewOpc = 0;
|
||||
|
||||
// This is only called for instructions that need remapping, so iterating over
|
||||
// the tiny opcode table is not costly.
|
||||
static const int NPairs =
|
||||
sizeof(AddSubFlagsOpcodeMap) / sizeof(AddSubFlagsOpcodePair);
|
||||
for (const AddSubFlagsOpcodePair *Pair = &AddSubFlagsOpcodeMap[0],
|
||||
*End = &AddSubFlagsOpcodeMap[NPairs]; Pair != End; ++Pair) {
|
||||
if (OldOpc == Pair->PseudoOpc) {
|
||||
NewOpc = Pair->MachineOpc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!NewOpc)
|
||||
return false;
|
||||
|
||||
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
|
||||
DebugLoc dl = MI->getDebugLoc();
|
||||
MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(NewOpc));
|
||||
for (unsigned i = 0; i < MI->getNumOperands(); ++i)
|
||||
MIB.addOperand(MI->getOperand(i));
|
||||
AddDefaultPred(MIB);
|
||||
MIB.addReg(ARM::CPSR, RegState::Define); // S bit
|
||||
MI->eraseFromParent();
|
||||
return true;
|
||||
}
|
||||
|
||||
MachineBasicBlock *
|
||||
ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
MachineBasicBlock *BB) const {
|
||||
@ -5286,9 +5254,6 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
bool isThumb2 = Subtarget->isThumb2();
|
||||
switch (MI->getOpcode()) {
|
||||
default: {
|
||||
if (RemapAddSubWithFlags(MI, BB))
|
||||
return BB;
|
||||
|
||||
MI->dump();
|
||||
llvm_unreachable("Unexpected instr type to insert");
|
||||
}
|
||||
|
@ -71,6 +71,11 @@ namespace llvm {
|
||||
SRA_FLAG, // V,Flag = sra_flag X -> sra X, 1 + save carry out.
|
||||
RRX, // V = RRX X, Flag -> srl X, 1 + shift in carry flag.
|
||||
|
||||
ADDC, // Add with carry
|
||||
ADDE, // Add using carry
|
||||
SUBC, // Sub with carry
|
||||
SUBE, // Sub using carry
|
||||
|
||||
VMOVRRD, // double to two gprs.
|
||||
VMOVDRR, // Two gprs to double.
|
||||
|
||||
|
@ -70,6 +70,18 @@ def SDT_ARMTCRET : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
|
||||
def SDT_ARMBFI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
|
||||
SDTCisVT<2, i32>, SDTCisVT<3, i32>]>;
|
||||
|
||||
def SDTBinaryArithWithFlags : SDTypeProfile<2, 2,
|
||||
[SDTCisSameAs<0, 2>,
|
||||
SDTCisSameAs<0, 3>,
|
||||
SDTCisInt<0>, SDTCisVT<1, i32>]>;
|
||||
|
||||
// SDTBinaryArithWithFlagsInOut - RES1, CPSR = op LHS, RHS, CPSR
|
||||
def SDTBinaryArithWithFlagsInOut : SDTypeProfile<2, 3,
|
||||
[SDTCisSameAs<0, 2>,
|
||||
SDTCisSameAs<0, 3>,
|
||||
SDTCisInt<0>,
|
||||
SDTCisVT<1, i32>,
|
||||
SDTCisVT<4, i32>]>;
|
||||
// Node definitions.
|
||||
def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>;
|
||||
def ARMWrapperDYN : SDNode<"ARMISD::WrapperDYN", SDTIntUnaryOp>;
|
||||
@ -120,6 +132,12 @@ def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>;
|
||||
def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>;
|
||||
def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInGlue ]>;
|
||||
|
||||
def ARMaddc : SDNode<"ARMISD::ADDC", SDTBinaryArithWithFlags,
|
||||
[SDNPCommutative]>;
|
||||
def ARMsubc : SDNode<"ARMISD::SUBC", SDTBinaryArithWithFlags>;
|
||||
def ARMadde : SDNode<"ARMISD::ADDE", SDTBinaryArithWithFlagsInOut>;
|
||||
def ARMsube : SDNode<"ARMISD::SUBE", SDTBinaryArithWithFlagsInOut>;
|
||||
|
||||
def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>;
|
||||
def ARMeh_sjlj_setjmp: SDNode<"ARMISD::EH_SJLJ_SETJMP",
|
||||
SDT_ARMEH_SJLJ_Setjmp, [SDNPHasChain]>;
|
||||
@ -263,24 +281,11 @@ def imm0_65535 : Operand<i32>, ImmLeaf<i32, [{
|
||||
let ParserMatchClass = Imm0_65535AsmOperand;
|
||||
}
|
||||
|
||||
class BinOpWithFlagFrag<dag res> :
|
||||
PatFrag<(ops node:$LHS, node:$RHS, node:$FLAG), res>;
|
||||
class BinOpFrag<dag res> : PatFrag<(ops node:$LHS, node:$RHS), res>;
|
||||
class UnOpFrag <dag res> : PatFrag<(ops node:$Src), res>;
|
||||
|
||||
/// adde and sube predicates - True based on whether the carry flag output
|
||||
/// will be needed or not.
|
||||
def adde_dead_carry :
|
||||
PatFrag<(ops node:$LHS, node:$RHS), (adde node:$LHS, node:$RHS),
|
||||
[{return !N->hasAnyUseOfValue(1);}]>;
|
||||
def sube_dead_carry :
|
||||
PatFrag<(ops node:$LHS, node:$RHS), (sube node:$LHS, node:$RHS),
|
||||
[{return !N->hasAnyUseOfValue(1);}]>;
|
||||
def adde_live_carry :
|
||||
PatFrag<(ops node:$LHS, node:$RHS), (adde node:$LHS, node:$RHS),
|
||||
[{return N->hasAnyUseOfValue(1);}]>;
|
||||
def sube_live_carry :
|
||||
PatFrag<(ops node:$LHS, node:$RHS), (sube node:$LHS, node:$RHS),
|
||||
[{return N->hasAnyUseOfValue(1);}]>;
|
||||
|
||||
// An 'and' node with a single use.
|
||||
def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{
|
||||
return N->hasOneUse();
|
||||
@ -939,6 +944,161 @@ multiclass AsI1_bin_irs<bits<4> opcod, string opc,
|
||||
|
||||
}
|
||||
|
||||
/// AsI1_rbin_irs - Same as AsI1_bin_irs except the order of operands are
|
||||
/// reversed. The 'rr' form is only defined for the disassembler; for codegen
|
||||
/// it is equivalent to the AsI1_bin_irs counterpart.
|
||||
multiclass AsI1_rbin_irs<bits<4> opcod, string opc,
|
||||
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
||||
PatFrag opnode, string baseOpc, bit Commutable = 0> {
|
||||
// The register-immediate version is re-materializable. This is useful
|
||||
// in particular for taking the address of a local.
|
||||
let isReMaterializable = 1 in {
|
||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||
iii, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, (opnode so_imm:$imm, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
let Inst{25} = 1;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-0} = imm;
|
||||
}
|
||||
}
|
||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||
iir, opc, "\t$Rd, $Rn, $Rm",
|
||||
[/* pattern left blank */]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
let Inst{11-4} = 0b00000000;
|
||||
let Inst{25} = 0;
|
||||
let Inst{3-0} = Rm;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
}
|
||||
|
||||
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode so_reg_imm:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-5} = shift{11-5};
|
||||
let Inst{4} = 0;
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
|
||||
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode so_reg_reg:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
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};
|
||||
}
|
||||
|
||||
// Assembly aliases for optional destination operand when it's the same
|
||||
// as the source operand.
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $imm"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "ri")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_imm:$imm, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $Rm"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rr")) GPR:$Rdn, GPR:$Rdn,
|
||||
GPR:$Rm, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rsi")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_reg_imm:$shift, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rsr")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_reg_reg:$shift, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
|
||||
}
|
||||
|
||||
/// AsI1_rbin_s_is - Same as AsI1_rbin_s_is except sets 's' bit.
|
||||
let isCodeGenOnly = 1, Defs = [CPSR] in {
|
||||
multiclass AsI1_rbin_s_is<bits<4> opcod, string opc,
|
||||
InstrItinClass iii, InstrItinClass iir, InstrItinClass iis,
|
||||
PatFrag opnode, bit Commutable = 0> {
|
||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||
iii, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_imm:$imm, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
let Inst{25} = 1;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-0} = imm;
|
||||
}
|
||||
|
||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||
iir, opc, "\t$Rd, $Rn, $Rm",
|
||||
[/* pattern left blank */]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
let Inst{11-4} = 0b00000000;
|
||||
let Inst{25} = 0;
|
||||
let Inst{3-0} = Rm;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
}
|
||||
|
||||
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-5} = shift{11-5};
|
||||
let Inst{4} = 0;
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
|
||||
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_reg_reg:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
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};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// AI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the
|
||||
/// instruction modifies the CPSR register.
|
||||
let isCodeGenOnly = 1, Defs = [CPSR] in {
|
||||
@ -947,7 +1107,7 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
|
||||
PatFrag opnode, bit Commutable = 0> {
|
||||
def ri : AI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||
iii, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_imm:$imm))]> {
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_imm:$imm))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
@ -959,7 +1119,7 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
|
||||
}
|
||||
def rr : AI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||
iir, opc, "\t$Rd, $Rn, $Rm",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, GPR:$Rm))]> {
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
@ -974,7 +1134,7 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
|
||||
def rsi : AI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]> {
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_imm:$shift))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
@ -987,10 +1147,10 @@ multiclass AI1_bin_s_irs<bits<4> opcod, string opc,
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
|
||||
def rsr : AI1<opcod, (outs GPR:$Rd),
|
||||
def rsr : AI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm,
|
||||
iis, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]> {
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_reg:$shift))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
@ -1130,10 +1290,10 @@ class AI_exta_rrot_np<bits<8> opcod, string opc>
|
||||
/// AI1_adde_sube_irs - Define instructions and patterns for adde and sube.
|
||||
multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
string baseOpc, bit Commutable = 0> {
|
||||
let Uses = [CPSR] in {
|
||||
let Defs = [CPSR], Uses = [CPSR] in {
|
||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_imm:$imm))]>,
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_imm:$imm, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
@ -1145,7 +1305,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
}
|
||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
|
||||
DPFrm, IIC_iALUr, opc, "\t$Rd, $Rn, $Rm",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, GPR:$Rm))]>,
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
@ -1160,7 +1320,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rsi : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_imm:$shift),
|
||||
DPSoRegImmFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]>,
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_imm:$shift, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
@ -1175,7 +1335,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rsr : AsI1<opcod, (outs GPR:$Rd),
|
||||
(ins GPR:$Rn, so_reg_reg:$shift),
|
||||
DPSoRegRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]>,
|
||||
[(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_reg:$shift, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
@ -1190,6 +1350,7 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
}
|
||||
|
||||
// Assembly aliases for optional destination operand when it's the same
|
||||
// as the source operand.
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $imm"),
|
||||
@ -1214,25 +1375,88 @@ multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
Requires<[IsARM]>;
|
||||
}
|
||||
|
||||
// Carry setting variants
|
||||
// NOTE: CPSR def omitted because it will be handled by the custom inserter.
|
||||
let usesCustomInserter = 1 in {
|
||||
multiclass AI1_adde_sube_s_irs<PatFrag opnode, bit Commutable = 0> {
|
||||
def ri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
4, IIC_iALUi,
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_imm:$imm))]>;
|
||||
def rr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
|
||||
4, IIC_iALUr,
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, GPR:$Rm))]> {
|
||||
let isCommutable = Commutable;
|
||||
/// AI1_rsc_irs - Define instructions and patterns for rsc
|
||||
multiclass AI1_rsc_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
string baseOpc> {
|
||||
let Defs = [CPSR], Uses = [CPSR] in {
|
||||
def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_imm:$imm, GPR:$Rn, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
let Inst{25} = 1;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{11-0} = imm;
|
||||
}
|
||||
def rsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]>;
|
||||
def rsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]>;
|
||||
}
|
||||
def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
|
||||
DPFrm, IIC_iALUr, opc, "\t$Rd, $Rn, $Rm",
|
||||
[/* pattern left blank */]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
let Inst{11-4} = 0b00000000;
|
||||
let Inst{25} = 0;
|
||||
let Inst{3-0} = Rm;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
}
|
||||
def rsi : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
DPSoRegImmFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, GPR:$Rn, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-5} = shift{11-5};
|
||||
let Inst{4} = 0;
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
def rsr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
DPSoRegRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, CPSR, (opnode so_reg_reg:$shift, GPR:$Rn, CPSR))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
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};
|
||||
}
|
||||
}
|
||||
|
||||
// Assembly aliases for optional destination operand when it's the same
|
||||
// as the source operand.
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $imm"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "ri")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_imm:$imm, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $Rm"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rr")) GPR:$Rdn, GPR:$Rdn,
|
||||
GPR:$Rm, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rsi")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_reg_imm:$shift, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
def : InstAlias<!strconcat(opc, "${s}${p} $Rdn, $shift"),
|
||||
(!cast<Instruction>(!strconcat(baseOpc, "rsr")) GPR:$Rdn, GPR:$Rdn,
|
||||
so_reg_reg:$shift, pred:$p,
|
||||
cc_out:$s)>,
|
||||
Requires<[IsARM]>;
|
||||
}
|
||||
|
||||
let canFoldAsLoad = 1, isReMaterializable = 1 in {
|
||||
@ -2882,182 +3106,44 @@ defm SUB : AsI1_bin_irs<0b0010, "sub",
|
||||
// ADD and SUB with 's' bit set.
|
||||
defm ADDS : AI1_bin_s_irs<0b0100, "adds",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
||||
BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
|
||||
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
||||
defm SUBS : AI1_bin_s_irs<0b0010, "subs",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
||||
BinOpFrag<(subc node:$LHS, node:$RHS)>>;
|
||||
BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>;
|
||||
|
||||
defm ADC : AI1_adde_sube_irs<0b0101, "adc",
|
||||
BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>,
|
||||
BinOpWithFlagFrag<(ARMadde node:$LHS, node:$RHS, node:$FLAG)>,
|
||||
"ADC", 1>;
|
||||
defm SBC : AI1_adde_sube_irs<0b0110, "sbc",
|
||||
BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>,
|
||||
BinOpWithFlagFrag<(ARMsube node:$LHS, node:$RHS, node:$FLAG)>,
|
||||
"SBC">;
|
||||
|
||||
// ADC and SUBC with 's' bit set.
|
||||
let usesCustomInserter = 1 in {
|
||||
defm ADCS : AI1_adde_sube_s_irs<
|
||||
BinOpFrag<(adde_live_carry node:$LHS, node:$RHS)>, 1>;
|
||||
defm SBCS : AI1_adde_sube_s_irs<
|
||||
BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>;
|
||||
}
|
||||
defm RSB : AsI1_rbin_irs <0b0011, "rsb",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
||||
BinOpFrag<(sub node:$LHS, node:$RHS)>, "RSB">;
|
||||
defm RSBS : AsI1_rbin_s_is<0b0011, "rsb",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsr,
|
||||
BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>;
|
||||
|
||||
def RSBri : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
|
||||
IIC_iALUi, "rsb", "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, (sub so_imm:$imm, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
let Inst{25} = 1;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{11-0} = imm;
|
||||
}
|
||||
|
||||
def RSBrr : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm,
|
||||
IIC_iALUr, "rsb", "\t$Rd, $Rn, $Rm", []> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
let Inst{11-4} = 0b00000000;
|
||||
let Inst{25} = 0;
|
||||
let Inst{3-0} = Rm;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
}
|
||||
|
||||
def RSBrsi : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
DPSoRegImmFrm, IIC_iALUsr, "rsb", "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (sub so_reg_imm:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-5} = shift{11-5};
|
||||
let Inst{4} = 0;
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
|
||||
def RSBrsr : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
DPSoRegRegFrm, IIC_iALUsr, "rsb", "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (sub so_reg_reg:$shift, GPR:$Rn))]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
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};
|
||||
}
|
||||
|
||||
// RSB with 's' bit set.
|
||||
// NOTE: CPSR def omitted because it will be handled by the custom inserter.
|
||||
let usesCustomInserter = 1 in {
|
||||
def RSBSri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
4, IIC_iALUi,
|
||||
[(set GPR:$Rd, (subc so_imm:$imm, GPR:$Rn))]>;
|
||||
def RSBSrr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
|
||||
4, IIC_iALUr, []>;
|
||||
def RSBSrsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (subc so_reg_imm:$shift, GPR:$Rn))]>;
|
||||
def RSBSrsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (subc so_reg_reg:$shift, GPR:$Rn))]>;
|
||||
}
|
||||
|
||||
let Uses = [CPSR] in {
|
||||
def RSCri : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
DPFrm, IIC_iALUi, "rsc", "\t$Rd, $Rn, $imm",
|
||||
[(set GPR:$Rd, (sube_dead_carry so_imm:$imm, GPR:$Rn))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> imm;
|
||||
let Inst{25} = 1;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{11-0} = imm;
|
||||
}
|
||||
def RSCrr : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
|
||||
DPFrm, IIC_iALUr, "rsc", "\t$Rd, $Rn, $Rm", []> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<4> Rm;
|
||||
let Inst{11-4} = 0b00000000;
|
||||
let Inst{25} = 0;
|
||||
let Inst{3-0} = Rm;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{19-16} = Rn;
|
||||
}
|
||||
def RSCrsi : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
DPSoRegImmFrm, IIC_iALUsr, "rsc", "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (sube_dead_carry so_reg_imm:$shift, GPR:$Rn))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
let Inst{11-5} = shift{11-5};
|
||||
let Inst{4} = 0;
|
||||
let Inst{3-0} = shift{3-0};
|
||||
}
|
||||
def RSCrsr : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
DPSoRegRegFrm, IIC_iALUsr, "rsc", "\t$Rd, $Rn, $shift",
|
||||
[(set GPR:$Rd, (sube_dead_carry so_reg_reg:$shift, GPR:$Rn))]>,
|
||||
Requires<[IsARM]> {
|
||||
bits<4> Rd;
|
||||
bits<4> Rn;
|
||||
bits<12> shift;
|
||||
let Inst{25} = 0;
|
||||
let Inst{19-16} = Rn;
|
||||
let Inst{15-12} = Rd;
|
||||
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};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE: CPSR def omitted because it will be handled by the custom inserter.
|
||||
let usesCustomInserter = 1, Uses = [CPSR] in {
|
||||
def RSCSri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm),
|
||||
4, IIC_iALUi,
|
||||
[(set GPR:$Rd, (sube_dead_carry so_imm:$imm, GPR:$Rn))]>;
|
||||
def RSCSrsi : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (sube_dead_carry so_reg_imm:$shift, GPR:$Rn))]>;
|
||||
def RSCSrsr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift),
|
||||
4, IIC_iALUsr,
|
||||
[(set GPR:$Rd, (sube_dead_carry so_reg_reg:$shift, GPR:$Rn))]>;
|
||||
}
|
||||
defm RSC : AI1_rsc_irs<0b0111, "rsc",
|
||||
BinOpWithFlagFrag<(ARMsube node:$LHS, node:$RHS, node:$FLAG)>,
|
||||
"RSC">;
|
||||
|
||||
// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
|
||||
// The assume-no-carry-in form uses the negation of the input since add/sub
|
||||
// assume opposite meanings of the carry flag (i.e., carry == !borrow).
|
||||
// See the definition of AddWithCarry() in the ARM ARM A2.2.1 for the gory
|
||||
// details.
|
||||
def : ARMPat<(add GPR:$src, so_imm_neg:$imm),
|
||||
(SUBri GPR:$src, so_imm_neg:$imm)>;
|
||||
def : ARMPat<(addc GPR:$src, so_imm_neg:$imm),
|
||||
(SUBSri GPR:$src, so_imm_neg:$imm)>;
|
||||
def : ARMPat<(add GPR:$src, so_imm_neg:$imm),
|
||||
(SUBri GPR:$src, so_imm_neg:$imm)>;
|
||||
def : ARMPat<(ARMaddc GPR:$src, so_imm_neg:$imm),
|
||||
(SUBSri GPR:$src, so_imm_neg:$imm)>;
|
||||
|
||||
// The with-carry-in form matches bitwise not instead of the negation.
|
||||
// Effectively, the inverse interpretation of the carry flag already accounts
|
||||
// for part of the negation.
|
||||
def : ARMPat<(adde_dead_carry GPR:$src, so_imm_not:$imm),
|
||||
(SBCri GPR:$src, so_imm_not:$imm)>;
|
||||
def : ARMPat<(adde_live_carry GPR:$src, so_imm_not:$imm),
|
||||
(SBCSri GPR:$src, so_imm_not:$imm)>;
|
||||
def : ARMPat<(ARMadde GPR:$src, so_imm_not:$imm, CPSR),
|
||||
(SBCri GPR:$src, so_imm_not:$imm)>;
|
||||
|
||||
// Note: These are implemented in C++ code, because they have to generate
|
||||
// ADD/SUBrs instructions, which use a complex pattern that a xform function
|
||||
@ -4803,29 +4889,6 @@ def : InstAlias<"pkhtb${p} $Rd, $Rn, $Rm",
|
||||
def : ARMInstAlias<"push${p} $regs", (STMDB_UPD SP, pred:$p, reglist:$regs)>;
|
||||
def : ARMInstAlias<"pop${p} $regs", (LDMIA_UPD SP, pred:$p, reglist:$regs)>;
|
||||
|
||||
// RSB two-operand forms (optional explicit destination operand)
|
||||
def : ARMInstAlias<"rsb${s}${p} $Rdn, $imm",
|
||||
(RSBri GPR:$Rdn, GPR:$Rdn, so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsb${s}${p} $Rdn, $Rm",
|
||||
(RSBrr GPR:$Rdn, GPR:$Rdn, GPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsb${s}${p} $Rdn, $shift",
|
||||
(RSBrsi GPR:$Rdn, GPR:$Rdn, so_reg_imm:$shift, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsb${s}${p} $Rdn, $shift",
|
||||
(RSBrsr GPR:$Rdn, GPR:$Rdn, so_reg_reg:$shift, pred:$p,
|
||||
cc_out:$s)>;
|
||||
// RSC two-operand forms (optional explicit destination operand)
|
||||
def : ARMInstAlias<"rsc${s}${p} $Rdn, $imm",
|
||||
(RSCri GPR:$Rdn, GPR:$Rdn, so_imm:$imm, pred:$p, cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsc${s}${p} $Rdn, $Rm",
|
||||
(RSCrr GPR:$Rdn, GPR:$Rdn, GPR:$Rm, pred:$p, cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsc${s}${p} $Rdn, $shift",
|
||||
(RSCrsi GPR:$Rdn, GPR:$Rdn, so_reg_imm:$shift, pred:$p,
|
||||
cc_out:$s)>;
|
||||
def : ARMInstAlias<"rsc${s}${p} $Rdn, $shift",
|
||||
(RSCrsr GPR:$Rdn, GPR:$Rdn, so_reg_reg:$shift, pred:$p,
|
||||
cc_out:$s)>;
|
||||
|
||||
// SSAT/USAT optional shift operand.
|
||||
def : ARMInstAlias<"ssat${p} $Rd, $sat_imm, $Rn",
|
||||
(SSAT GPRnopc:$Rd, imm1_32:$sat_imm, GPRnopc:$Rn, 0, pred:$p)>;
|
||||
|
@ -582,7 +582,7 @@ multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
||||
def ri : T2TwoRegImm<
|
||||
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_imm:$imm), iii,
|
||||
!strconcat(opc, "s"), ".w\t$Rd, $Rn, $imm",
|
||||
[(set rGPR:$Rd, (opnode GPR:$Rn, t2_so_imm:$imm))]> {
|
||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_imm:$imm))]> {
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{25} = 0;
|
||||
let Inst{24-21} = opcod;
|
||||
@ -593,7 +593,7 @@ multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
||||
def rr : T2ThreeReg<
|
||||
(outs rGPR:$Rd), (ins GPR:$Rn, rGPR:$Rm), iir,
|
||||
!strconcat(opc, "s"), ".w\t$Rd, $Rn, $Rm",
|
||||
[(set rGPR:$Rd, (opnode GPR:$Rn, rGPR:$Rm))]> {
|
||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, rGPR:$Rm))]> {
|
||||
let isCommutable = Commutable;
|
||||
let Inst{31-27} = 0b11101;
|
||||
let Inst{26-25} = 0b01;
|
||||
@ -607,7 +607,7 @@ multiclass T2I_bin_s_irs<bits<4> opcod, string opc,
|
||||
def rs : T2TwoRegShiftedReg<
|
||||
(outs rGPR:$Rd), (ins GPR:$Rn, t2_so_reg:$ShiftedRm), iis,
|
||||
!strconcat(opc, "s"), ".w\t$Rd, $Rn, $ShiftedRm",
|
||||
[(set rGPR:$Rd, (opnode GPR:$Rn, t2_so_reg:$ShiftedRm))]> {
|
||||
[(set rGPR:$Rd, CPSR, (opnode GPR:$Rn, t2_so_reg:$ShiftedRm))]> {
|
||||
let Inst{31-27} = 0b11101;
|
||||
let Inst{26-25} = 0b01;
|
||||
let Inst{24-21} = opcod;
|
||||
@ -682,13 +682,13 @@ multiclass T2I_bin_ii12rs<bits<3> op23_21, string opc, PatFrag opnode,
|
||||
/// T2I_adde_sube_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns
|
||||
/// for a binary operation that produces a value and use the carry
|
||||
/// bit. It's not predicable.
|
||||
let Uses = [CPSR] in {
|
||||
let Defs = [CPSR], Uses = [CPSR] in {
|
||||
multiclass T2I_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
bit Commutable = 0> {
|
||||
// shifted imm
|
||||
def ri : T2sTwoRegImm<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm),
|
||||
IIC_iALUi, opc, "\t$Rd, $Rn, $imm",
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_imm:$imm))]>,
|
||||
[(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_imm:$imm, CPSR))]>,
|
||||
Requires<[IsThumb2]> {
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{25} = 0;
|
||||
@ -698,7 +698,7 @@ multiclass T2I_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
// register
|
||||
def rr : T2sThreeReg<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm), IIC_iALUr,
|
||||
opc, ".w\t$Rd, $Rn, $Rm",
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]>,
|
||||
[(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, rGPR:$Rm, CPSR))]>,
|
||||
Requires<[IsThumb2]> {
|
||||
let isCommutable = Commutable;
|
||||
let Inst{31-27} = 0b11101;
|
||||
@ -712,7 +712,7 @@ multiclass T2I_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
def rs : T2sTwoRegShiftedReg<
|
||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm),
|
||||
IIC_iALUsi, opc, ".w\t$Rd, $Rn, $ShiftedRm",
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm))]>,
|
||||
[(set rGPR:$Rd, CPSR, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm, CPSR))]>,
|
||||
Requires<[IsThumb2]> {
|
||||
let Inst{31-27} = 0b11101;
|
||||
let Inst{26-25} = 0b01;
|
||||
@ -721,28 +721,6 @@ multiclass T2I_adde_sube_irs<bits<4> opcod, string opc, PatFrag opnode,
|
||||
}
|
||||
}
|
||||
|
||||
// Carry setting variants
|
||||
// NOTE: CPSR def omitted because it will be handled by the custom inserter.
|
||||
let usesCustomInserter = 1 in {
|
||||
multiclass T2I_adde_sube_s_irs<PatFrag opnode, bit Commutable = 0> {
|
||||
// shifted imm
|
||||
def ri : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm),
|
||||
4, IIC_iALUi,
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_imm:$imm))]>;
|
||||
// register
|
||||
def rr : t2PseudoInst<(outs rGPR:$Rd), (ins rGPR:$Rn, rGPR:$Rm),
|
||||
4, IIC_iALUr,
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, rGPR:$Rm))]> {
|
||||
let isCommutable = Commutable;
|
||||
}
|
||||
// shifted register
|
||||
def rs : t2PseudoInst<
|
||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm),
|
||||
4, IIC_iALUsi,
|
||||
[(set rGPR:$Rd, (opnode rGPR:$Rn, t2_so_reg:$ShiftedRm))]>;
|
||||
}
|
||||
}
|
||||
|
||||
/// T2I_rbin_s_is - Same as T2I_rbin_irs except sets 's' bit and the register
|
||||
/// version is not needed since this is only for codegen.
|
||||
let isCodeGenOnly = 1, Defs = [CPSR] in {
|
||||
@ -751,7 +729,7 @@ multiclass T2I_rbin_s_is<bits<4> opcod, string opc, PatFrag opnode> {
|
||||
def ri : T2TwoRegImm<
|
||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_imm:$imm), IIC_iALUi,
|
||||
!strconcat(opc, "s"), ".w\t$Rd, $Rn, $imm",
|
||||
[(set rGPR:$Rd, (opnode t2_so_imm:$imm, rGPR:$Rn))]> {
|
||||
[(set rGPR:$Rd, CPSR, (opnode t2_so_imm:$imm, rGPR:$Rn))]> {
|
||||
let Inst{31-27} = 0b11110;
|
||||
let Inst{25} = 0;
|
||||
let Inst{24-21} = opcod;
|
||||
@ -762,7 +740,7 @@ multiclass T2I_rbin_s_is<bits<4> opcod, string opc, PatFrag opnode> {
|
||||
def rs : T2TwoRegShiftedReg<
|
||||
(outs rGPR:$Rd), (ins rGPR:$Rn, t2_so_reg:$ShiftedRm),
|
||||
IIC_iALUsi, !strconcat(opc, "s"), "\t$Rd, $Rn, $ShiftedRm",
|
||||
[(set rGPR:$Rd, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]> {
|
||||
[(set rGPR:$Rd, CPSR, (opnode t2_so_reg:$ShiftedRm, rGPR:$Rn))]> {
|
||||
let Inst{31-27} = 0b11101;
|
||||
let Inst{26-25} = 0b01;
|
||||
let Inst{24-21} = opcod;
|
||||
@ -1678,25 +1656,21 @@ defm t2SUB : T2I_bin_ii12rs<0b101, "sub",
|
||||
// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants.
|
||||
defm t2ADDS : T2I_bin_s_irs <0b1000, "add",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsi,
|
||||
BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
|
||||
BinOpFrag<(ARMaddc node:$LHS, node:$RHS)>, 1>;
|
||||
defm t2SUBS : T2I_bin_s_irs <0b1101, "sub",
|
||||
IIC_iALUi, IIC_iALUr, IIC_iALUsi,
|
||||
BinOpFrag<(subc node:$LHS, node:$RHS)>>;
|
||||
BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>;
|
||||
|
||||
defm t2ADC : T2I_adde_sube_irs<0b1010, "adc",
|
||||
BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>, 1>;
|
||||
BinOpWithFlagFrag<(ARMadde node:$LHS, node:$RHS, node:$FLAG)>, 1>;
|
||||
defm t2SBC : T2I_adde_sube_irs<0b1011, "sbc",
|
||||
BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>>;
|
||||
defm t2ADCS : T2I_adde_sube_s_irs<BinOpFrag<(adde_live_carry node:$LHS,
|
||||
node:$RHS)>, 1>;
|
||||
defm t2SBCS : T2I_adde_sube_s_irs<BinOpFrag<(sube_live_carry node:$LHS,
|
||||
node:$RHS)>>;
|
||||
BinOpWithFlagFrag<(ARMsube node:$LHS, node:$RHS, node:$FLAG)>>;
|
||||
|
||||
// RSB
|
||||
defm t2RSB : T2I_rbin_irs <0b1110, "rsb",
|
||||
BinOpFrag<(sub node:$LHS, node:$RHS)>>;
|
||||
defm t2RSBS : T2I_rbin_s_is <0b1110, "rsb",
|
||||
BinOpFrag<(subc node:$LHS, node:$RHS)>>;
|
||||
BinOpFrag<(ARMsubc node:$LHS, node:$RHS)>>;
|
||||
|
||||
// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
|
||||
// The assume-no-carry-in form uses the negation of the input since add/sub
|
||||
@ -1713,23 +1687,18 @@ def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm),
|
||||
def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm),
|
||||
(t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>;
|
||||
let AddedComplexity = 1 in
|
||||
def : T2Pat<(addc rGPR:$src, imm0_255_neg:$imm),
|
||||
def : T2Pat<(ARMaddc rGPR:$src, imm0_255_neg:$imm),
|
||||
(t2SUBSri rGPR:$src, imm0_255_neg:$imm)>;
|
||||
def : T2Pat<(addc rGPR:$src, t2_so_imm_neg:$imm),
|
||||
def : T2Pat<(ARMaddc rGPR:$src, t2_so_imm_neg:$imm),
|
||||
(t2SUBSri rGPR:$src, t2_so_imm_neg:$imm)>;
|
||||
// The with-carry-in form matches bitwise not instead of the negation.
|
||||
// Effectively, the inverse interpretation of the carry flag already accounts
|
||||
// for part of the negation.
|
||||
let AddedComplexity = 1 in
|
||||
def : T2Pat<(adde_dead_carry rGPR:$src, imm0_255_not:$imm),
|
||||
def : T2Pat<(ARMadde rGPR:$src, imm0_255_not:$imm, CPSR),
|
||||
(t2SBCri rGPR:$src, imm0_255_not:$imm)>;
|
||||
def : T2Pat<(adde_dead_carry rGPR:$src, t2_so_imm_not:$imm),
|
||||
def : T2Pat<(ARMadde rGPR:$src, t2_so_imm_not:$imm, CPSR),
|
||||
(t2SBCri rGPR:$src, t2_so_imm_not:$imm)>;
|
||||
let AddedComplexity = 1 in
|
||||
def : T2Pat<(adde_live_carry rGPR:$src, imm0_255_not:$imm),
|
||||
(t2SBCSri rGPR:$src, imm0_255_not:$imm)>;
|
||||
def : T2Pat<(adde_live_carry rGPR:$src, t2_so_imm_not:$imm),
|
||||
(t2SBCSri rGPR:$src, t2_so_imm_not:$imm)>;
|
||||
|
||||
// Select Bytes -- for disassembly only
|
||||
|
||||
|
@ -347,5 +347,6 @@ def QQQQPR : RegisterClass<"ARM", [v8i64], 256, (sequence "QQQQ%u", 0, 3)> {
|
||||
|
||||
// Condition code registers.
|
||||
def CCR : RegisterClass<"ARM", [i32], 32, (add CPSR)> {
|
||||
let CopyCost = -1; // Don't allow copying of status registers.
|
||||
let isAllocatable = 0;
|
||||
}
|
||||
|
45
test/CodeGen/ARM/2011-08-29-SchedCycle.ll
Normal file
45
test/CodeGen/ARM/2011-08-29-SchedCycle.ll
Normal file
@ -0,0 +1,45 @@
|
||||
; RUN: llc %s -mtriple=thumbv7-apple-darwin -mcpu=cortex-a8 -o -
|
||||
|
||||
; When a i64 sub is expanded to subc + sube.
|
||||
; libcall #1
|
||||
; \
|
||||
; \ subc
|
||||
; \ / \
|
||||
; \ / \
|
||||
; \ / libcall #2
|
||||
; sube
|
||||
;
|
||||
; If the libcalls are not serialized (i.e. both have chains which are dag
|
||||
; entry), legalizer can serialize them in arbitrary orders. If it's
|
||||
; unlucky, it can force libcall #2 before libcall #1 in the above case.
|
||||
;
|
||||
; subc
|
||||
; |
|
||||
; libcall #2
|
||||
; |
|
||||
; libcall #1
|
||||
; |
|
||||
; sube
|
||||
;
|
||||
; However since subc and sube are "glued" together, this ends up being a
|
||||
; cycle when the scheduler combine subc and sube as a single scheduling
|
||||
; unit.
|
||||
;
|
||||
; The right solution is to fix LegalizeType too chains the libcalls together.
|
||||
; However, LegalizeType is not processing nodes in order. The fix now is to
|
||||
; fix subc / sube (and addc / adde) to use physical register dependency instead.
|
||||
; rdar://10019576
|
||||
|
||||
define void @t() nounwind {
|
||||
entry:
|
||||
%tmp = load i64* undef, align 4
|
||||
%tmp5 = udiv i64 %tmp, 30
|
||||
%tmp13 = and i64 %tmp5, 64739244643450880
|
||||
%tmp16 = sub i64 0, %tmp13
|
||||
%tmp19 = and i64 %tmp16, 63
|
||||
%tmp20 = urem i64 %tmp19, 3
|
||||
%tmp22 = and i64 %tmp16, -272346829004752
|
||||
store i64 %tmp22, i64* undef, align 4
|
||||
store i64 %tmp20, i64* undef, align 4
|
||||
ret void
|
||||
}
|
@ -6,8 +6,8 @@ entry:
|
||||
; -- The loop following the load should only use a single add-literation
|
||||
; instruction.
|
||||
; CHECK: ldr.64
|
||||
; CHECK: adds r{{[0-9]+}}, #1
|
||||
; CHECK-NOT: adds r{{[0-9]+}}, #1
|
||||
; CHECK: adds r{{[0-9]+}}, r{{[0-9]+}}, #1
|
||||
; CHECK-NOT: adds r{{[0-9]+}}, r{{[0-9]+}}, #1
|
||||
; CHECK: subsections_via_symbols
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user