[llvm-commits] [llvm] r138791 - in /llvm/trunk: lib/Target/ARM/ARMBaseRegisterInfo.cpp lib/Target/ARM/ARMBaseRegisterInfo.h lib/Target/ARM/ARMISelLowering.cpp lib/Target/ARM/ARMISelLowering.h lib/Target/ARM/ARMInstrInfo.td lib/Target/ARM/ARMInstrThumb2.td lib/Target/ARM/ARMRegisterInfo.td test/CodeGen/ARM/2011-08-29-SchedCycle.ll test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll

Evan Cheng evan.cheng at apple.com
Tue Aug 30 10:34:11 PDT 2011


The patch is incomplete. I'm working on a follow up now.

Evan

On Aug 29, 2011, at 6:34 PM, Evan Cheng wrote:

> Author: evancheng
> Date: Mon Aug 29 20:34:54 2011
> New Revision: 138791
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=138791&view=rev
> Log:
> 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
> 
> Added:
>    llvm/trunk/test/CodeGen/ARM/2011-08-29-SchedCycle.ll
> Modified:
>    llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.cpp
>    llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.h
>    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
>    llvm/trunk/lib/Target/ARM/ARMISelLowering.h
>    llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
>    llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
>    llvm/trunk/lib/Target/ARM/ARMRegisterInfo.td
>    llvm/trunk/test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.cpp?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.cpp Mon Aug 29 20:34:54 2011
> @@ -374,6 +374,13 @@
>   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 {
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.h?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.h (original)
> +++ llvm/trunk/lib/Target/ARM/ARMBaseRegisterInfo.h Mon Aug 29 20:34:54 2011
> @@ -116,6 +116,8 @@
>                                        unsigned &NewSubIdx) const;
> 
>   const TargetRegisterClass *getPointerRegClass(unsigned Kind = 0) const;
> +  const TargetRegisterClass*
> +  getCrossCopyRegClass(const TargetRegisterClass *RC) const;
> 
>   const TargetRegisterClass*
>   getLargestLegalSuperClass(const TargetRegisterClass *RC) const;
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Mon Aug 29 20:34:54 2011
> @@ -551,6 +551,14 @@
>   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 @@
>   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 @@
>   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 @@
>   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 @@
>   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 @@
>   bool isThumb2 = Subtarget->isThumb2();
>   switch (MI->getOpcode()) {
>   default: {
> -    if (RemapAddSubWithFlags(MI, BB))
> -      return BB;
> -
>     MI->dump();
>     llvm_unreachable("Unexpected instr type to insert");
>   }
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.h?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMISelLowering.h (original)
> +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.h Mon Aug 29 20:34:54 2011
> @@ -71,6 +71,11 @@
>       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.
> 
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Mon Aug 29 20:34:54 2011
> @@ -70,6 +70,18 @@
> 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 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 @@
>   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 @@
> 
> }
> 
> +/// 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 @@
>                          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 @@
>   }
>   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 @@
>   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 @@
>     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 @@
> /// 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 @@
>   }
>   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 @@
>   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 @@
>   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 @@
>     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 @@
>      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 @@
> // 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) >>;
> -}
> -
> -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};
> -}
> -}
> -
> +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)>>;
> 
> -// 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 : 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)>;
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Mon Aug 29 20:34:54 2011
> @@ -582,7 +582,7 @@
>    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 @@
>    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 @@
>    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 @@
> /// 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 @@
>    // 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 @@
>    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 @@
> }
> }
> 
> -// 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 @@
>    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 @@
>    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 @@
> // 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, 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
> 
> 
> Modified: llvm/trunk/lib/Target/ARM/ARMRegisterInfo.td
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMRegisterInfo.td?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMRegisterInfo.td (original)
> +++ llvm/trunk/lib/Target/ARM/ARMRegisterInfo.td Mon Aug 29 20:34:54 2011
> @@ -347,5 +347,6 @@
> 
> // Condition code registers.
> def CCR : RegisterClass<"ARM", [i32], 32, (add CPSR)> {
> +  let CopyCost = -1;  // Don't allow copying of status registers.
>   let isAllocatable = 0;
> }
> 
> Added: llvm/trunk/test/CodeGen/ARM/2011-08-29-SchedCycle.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2011-08-29-SchedCycle.ll?rev=138791&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/2011-08-29-SchedCycle.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/2011-08-29-SchedCycle.ll Mon Aug 29 20:34:54 2011
> @@ -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
> +}
> 
> Modified: llvm/trunk/test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll?rev=138791&r1=138790&r2=138791&view=diff
> ==============================================================================
> --- llvm/trunk/test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll (original)
> +++ llvm/trunk/test/CodeGen/Thumb2/2009-12-01-LoopIVUsers.ll Mon Aug 29 20:34:54 2011
> @@ -6,8 +6,8 @@
> ; -- 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
> 
> 
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list