diff options
Diffstat (limited to 'lib/Target/ARM/ARMFastISel.cpp')
| -rw-r--r-- | lib/Target/ARM/ARMFastISel.cpp | 232 | 
1 files changed, 160 insertions, 72 deletions
diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index 26f48b3083168..3baf274b76b81 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -14,6 +14,7 @@  //===----------------------------------------------------------------------===//  #include "ARM.h" +#include "ARMAddressingModes.h"  #include "ARMBaseInstrInfo.h"  #include "ARMCallingConv.h"  #include "ARMRegisterInfo.h" @@ -26,6 +27,7 @@  #include "llvm/Instructions.h"  #include "llvm/IntrinsicInst.h"  #include "llvm/Module.h" +#include "llvm/Operator.h"  #include "llvm/CodeGen/Analysis.h"  #include "llvm/CodeGen/FastISel.h"  #include "llvm/CodeGen/FunctionLoweringInfo.h" @@ -115,6 +117,11 @@ class ARMFastISel : public FastISel {                                       const TargetRegisterClass *RC,                                       unsigned Op0, bool Op0IsKill,                                       unsigned Op1, bool Op1IsKill); +    virtual unsigned FastEmitInst_rrr(unsigned MachineInstOpcode, +                                      const TargetRegisterClass *RC, +                                      unsigned Op0, bool Op0IsKill, +                                      unsigned Op1, bool Op1IsKill, +                                      unsigned Op2, bool Op2IsKill);      virtual unsigned FastEmitInst_ri(unsigned MachineInstOpcode,                                       const TargetRegisterClass *RC,                                       unsigned Op0, bool Op0IsKill, @@ -123,14 +130,18 @@ class ARMFastISel : public FastISel {                                       const TargetRegisterClass *RC,                                       unsigned Op0, bool Op0IsKill,                                       const ConstantFP *FPImm); -    virtual unsigned FastEmitInst_i(unsigned MachineInstOpcode, -                                    const TargetRegisterClass *RC, -                                    uint64_t Imm);      virtual unsigned FastEmitInst_rri(unsigned MachineInstOpcode,                                        const TargetRegisterClass *RC,                                        unsigned Op0, bool Op0IsKill,                                        unsigned Op1, bool Op1IsKill,                                        uint64_t Imm); +    virtual unsigned FastEmitInst_i(unsigned MachineInstOpcode, +                                    const TargetRegisterClass *RC, +                                    uint64_t Imm); +    virtual unsigned FastEmitInst_ii(unsigned MachineInstOpcode, +                                     const TargetRegisterClass *RC, +                                     uint64_t Imm1, uint64_t Imm2); +      virtual unsigned FastEmitInst_extractsubreg(MVT RetVT,                                                  unsigned Op0, bool Op0IsKill,                                                  uint32_t Idx); @@ -193,6 +204,7 @@ class ARMFastISel : public FastISel {      // OptionalDef handling routines.    private: +    bool isARMNEONPred(const MachineInstr *MI);      bool DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR);      const MachineInstrBuilder &AddOptionalDefs(const MachineInstrBuilder &MIB);      void AddLoadStoreOperands(EVT VT, Address &Addr, @@ -221,6 +233,21 @@ bool ARMFastISel::DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR) {    return true;  } +bool ARMFastISel::isARMNEONPred(const MachineInstr *MI) { +  const TargetInstrDesc &TID = MI->getDesc(); + +  // If we're a thumb2 or not NEON function we were handled via isPredicable. +  if ((TID.TSFlags & ARMII::DomainMask) != ARMII::DomainNEON || +       AFI->isThumb2Function()) +    return false; + +  for (unsigned i = 0, e = TID.getNumOperands(); i != e; ++i) +    if (TID.OpInfo[i].isPredicate()) +      return true; + +  return false; +} +  // If the machine is predicable go ahead and add the predicate operands, if  // it needs default CC operands add those.  // TODO: If we want to support thumb1 then we'll need to deal with optional @@ -230,8 +257,10 @@ const MachineInstrBuilder &  ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) {    MachineInstr *MI = &*MIB; -  // Do we use a predicate? -  if (TII.isPredicable(MI)) +  // Do we use a predicate? or... +  // Are we NEON in ARM mode and have a predicate operand? If so, I know +  // we're not predicable but add it anyways. +  if (TII.isPredicable(MI) || isARMNEONPred(MI))      AddDefaultPred(MIB);    // Do we optionally set a predicate?  Preds is size > 0 iff the predicate @@ -296,6 +325,31 @@ unsigned ARMFastISel::FastEmitInst_rr(unsigned MachineInstOpcode,    return ResultReg;  } +unsigned ARMFastISel::FastEmitInst_rrr(unsigned MachineInstOpcode, +                                       const TargetRegisterClass *RC, +                                       unsigned Op0, bool Op0IsKill, +                                       unsigned Op1, bool Op1IsKill, +                                       unsigned Op2, bool Op2IsKill) { +  unsigned ResultReg = createResultReg(RC); +  const TargetInstrDesc &II = TII.get(MachineInstOpcode); + +  if (II.getNumDefs() >= 1) +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) +                   .addReg(Op0, Op0IsKill * RegState::Kill) +                   .addReg(Op1, Op1IsKill * RegState::Kill) +                   .addReg(Op2, Op2IsKill * RegState::Kill)); +  else { +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) +                   .addReg(Op0, Op0IsKill * RegState::Kill) +                   .addReg(Op1, Op1IsKill * RegState::Kill) +                   .addReg(Op2, Op2IsKill * RegState::Kill)); +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, +                           TII.get(TargetOpcode::COPY), ResultReg) +                   .addReg(II.ImplicitDefs[0])); +  } +  return ResultReg; +} +  unsigned ARMFastISel::FastEmitInst_ri(unsigned MachineInstOpcode,                                        const TargetRegisterClass *RC,                                        unsigned Op0, bool Op0IsKill, @@ -384,6 +438,26 @@ unsigned ARMFastISel::FastEmitInst_i(unsigned MachineInstOpcode,    return ResultReg;  } +unsigned ARMFastISel::FastEmitInst_ii(unsigned MachineInstOpcode, +                                      const TargetRegisterClass *RC, +                                      uint64_t Imm1, uint64_t Imm2) { +  unsigned ResultReg = createResultReg(RC); +  const TargetInstrDesc &II = TII.get(MachineInstOpcode); +   +  if (II.getNumDefs() >= 1) +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) +                    .addImm(Imm1).addImm(Imm2)); +  else { +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) +                    .addImm(Imm1).addImm(Imm2)); +    AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,  +                            TII.get(TargetOpcode::COPY), +                            ResultReg) +                    .addReg(II.ImplicitDefs[0])); +  } +  return ResultReg; +} +  unsigned ARMFastISel::FastEmitInst_extractsubreg(MVT RetVT,                                                   unsigned Op0, bool Op0IsKill,                                                   uint32_t Idx) { @@ -667,24 +741,29 @@ bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) {            TmpOffset += SL->getElementOffset(Idx);          } else {            uint64_t S = TD.getTypeAllocSize(GTI.getIndexedType()); -          SmallVector<const Value *, 4> Worklist; -          Worklist.push_back(Op); -          do { -            Op = Worklist.pop_back_val(); +          for (;;) {              if (const ConstantInt *CI = dyn_cast<ConstantInt>(Op)) {                // Constant-offset addressing.                TmpOffset += CI->getSExtValue() * S; -            } else if (isa<AddOperator>(Op) && -                       isa<ConstantInt>(cast<AddOperator>(Op)->getOperand(1))) { -              // An add with a constant operand. Fold the constant. +              break; +            } +            if (isa<AddOperator>(Op) && +                (!isa<Instruction>(Op) || +                 FuncInfo.MBBMap[cast<Instruction>(Op)->getParent()] +                 == FuncInfo.MBB) && +                isa<ConstantInt>(cast<AddOperator>(Op)->getOperand(1))) { +              // An add (in the same block) with a constant operand. Fold the +              // constant.                ConstantInt *CI = -                cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1)); +              cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));                TmpOffset += CI->getSExtValue() * S; -              // Add the other operand back to the work list. -              Worklist.push_back(cast<AddOperator>(Op)->getOperand(0)); -            } else -              goto unsupported_gep; -          } while (!Worklist.empty()); +              // Iterate on the other operand. +              Op = cast<AddOperator>(Op)->getOperand(0); +              continue; +            } +            // Unsupported +            goto unsupported_gep; +          }          }        } @@ -767,26 +846,9 @@ void ARMFastISel::ARMSimplifyAddress(Address &Addr, EVT VT) {    // Since the offset is too large for the load/store instruction    // get the reg+offset into a register.    if (needsLowering) { -    ARMCC::CondCodes Pred = ARMCC::AL; -    unsigned PredReg = 0; - -    TargetRegisterClass *RC = isThumb ? ARM::tGPRRegisterClass : -      ARM::GPRRegisterClass; -    unsigned BaseReg = createResultReg(RC); - -    if (!isThumb) -      emitARMRegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, -                              BaseReg, Addr.Base.Reg, Addr.Offset, -                              Pred, PredReg, -                              static_cast<const ARMBaseInstrInfo&>(TII)); -    else { -      assert(AFI->isThumb2Function()); -      emitT2RegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, -                             BaseReg, Addr.Base.Reg, Addr.Offset, Pred, PredReg, -                             static_cast<const ARMBaseInstrInfo&>(TII)); -    } +    Addr.Base.Reg = FastEmit_ri_(MVT::i32, ISD::ADD, Addr.Base.Reg, +                                 /*Op0IsKill*/false, Addr.Offset, MVT::i32);      Addr.Offset = 0; -    Addr.Base.Reg = BaseReg;    }  } @@ -797,7 +859,7 @@ void ARMFastISel::AddLoadStoreOperands(EVT VT, Address &Addr,    if (VT.getSimpleVT().SimpleTy == MVT::f32 ||        VT.getSimpleVT().SimpleTy == MVT::f64)      Addr.Offset /= 4; -     +    // Frame base works a bit differently. Handle it separately.    if (Addr.BaseType == Address::FrameIndexBase) {      int FI = Addr.Base.FI; @@ -819,7 +881,7 @@ void ARMFastISel::AddLoadStoreOperands(EVT VT, Address &Addr,    } else {      // Now add the rest of the operands.      MIB.addReg(Addr.Base.Reg); -   +      // ARM halfword load/stores need an additional operand.      if (!isThumb && VT.getSimpleVT().SimpleTy == MVT::i16) MIB.addReg(0); @@ -1007,18 +1069,16 @@ bool ARMFastISel::SelectBranch(const Instruction *I) {    // behavior.    // TODO: Factor this out.    if (const CmpInst *CI = dyn_cast<CmpInst>(BI->getCondition())) { -    if (CI->hasOneUse() && (CI->getParent() == I->getParent())) { -      MVT VT; -      const Type *Ty = CI->getOperand(0)->getType(); -      if (!isTypeLegal(Ty, VT)) -        return false; - +    MVT SourceVT; +    const Type *Ty = CI->getOperand(0)->getType(); +    if (CI->hasOneUse() && (CI->getParent() == I->getParent()) +        && isTypeLegal(Ty, SourceVT)) {        bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy());        if (isFloat && !Subtarget->hasVFP2())          return false;        unsigned CmpOpc; -      switch (VT.SimpleTy) { +      switch (SourceVT.SimpleTy) {          default: return false;          // TODO: Verify compares.          case MVT::f32: @@ -1033,7 +1093,14 @@ bool ARMFastISel::SelectBranch(const Instruction *I) {        }        // Get the compare predicate. -      ARMCC::CondCodes ARMPred = getComparePred(CI->getPredicate()); +      // Try to take advantage of fallthrough opportunities. +      CmpInst::Predicate Predicate = CI->getPredicate(); +      if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { +        std::swap(TBB, FBB); +        Predicate = CmpInst::getInversePredicate(Predicate); +      } + +      ARMCC::CondCodes ARMPred = getComparePred(Predicate);        // We may not handle every CC for now.        if (ARMPred == ARMCC::AL) return false; @@ -1061,19 +1128,55 @@ bool ARMFastISel::SelectBranch(const Instruction *I) {        FuncInfo.MBB->addSuccessor(TBB);        return true;      } +  } else if (TruncInst *TI = dyn_cast<TruncInst>(BI->getCondition())) { +    MVT SourceVT; +    if (TI->hasOneUse() && TI->getParent() == I->getParent() && +        (isTypeLegal(TI->getOperand(0)->getType(), SourceVT))) { +      unsigned TstOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; +      unsigned OpReg = getRegForValue(TI->getOperand(0)); +      AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, +                              TII.get(TstOpc)) +                      .addReg(OpReg).addImm(1)); + +      unsigned CCMode = ARMCC::NE; +      if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { +        std::swap(TBB, FBB); +        CCMode = ARMCC::EQ; +      } + +      unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; +      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) +      .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR); + +      FastEmitBranch(FBB, DL); +      FuncInfo.MBB->addSuccessor(TBB); +      return true; +    }    }    unsigned CmpReg = getRegForValue(BI->getCondition());    if (CmpReg == 0) return false; -  // Re-set the flags just in case. -  unsigned CmpOpc = isThumb ? ARM::t2CMPri : ARM::CMPri; -  AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) -                  .addReg(CmpReg).addImm(0)); +  // We've been divorced from our compare!  Our block was split, and +  // now our compare lives in a predecessor block.  We musn't +  // re-compare here, as the children of the compare aren't guaranteed +  // live across the block boundary (we *could* check for this). +  // Regardless, the compare has been done in the predecessor block, +  // and it left a value for us in a virtual register.  Ergo, we test +  // the one-bit value left in the virtual register. +  unsigned TstOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; +  AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TstOpc)) +                  .addReg(CmpReg).addImm(1)); + +  unsigned CCMode = ARMCC::NE; +  if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { +    std::swap(TBB, FBB); +    CCMode = ARMCC::EQ; +  }    unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc;    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) -                  .addMBB(TBB).addImm(ARMCC::NE).addReg(ARM::CPSR); +                  .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR);    FastEmitBranch(FBB, DL);    FuncInfo.MBB->addSuccessor(TBB);    return true; @@ -1636,17 +1739,9 @@ bool ARMFastISel::SelectRet(const Instruction *I) {  unsigned ARMFastISel::ARMSelectCallOp(const GlobalValue *GV) { -  // Depend our opcode for thumb on whether or not we're targeting an -  // externally callable function. For libcalls we'll just pass a NULL GV -  // in here. -  bool isExternal = false; -  if (!GV || GV->hasExternalLinkage()) isExternal = true; -      // Darwin needs the r9 versions of the opcodes.    bool isDarwin = Subtarget->isTargetDarwin(); -  if (isThumb && isExternal) { -    return isDarwin ? ARM::tBLXi_r9 : ARM::tBLXi; -  } else if (isThumb) { +  if (isThumb) {      return isDarwin ? ARM::tBLr9 : ARM::tBL;    } else  {      return isDarwin ? ARM::BLr9 : ARM::BL; @@ -1671,9 +1766,6 @@ bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) {    else if (!isTypeLegal(RetTy, RetVT))      return false; -  // For now we're using BLX etc on the assumption that we have v5t ops. -  if (!Subtarget->hasV5TOps()) return false; -    // TODO: For now if we have long calls specified we don't handle the call.    if (EnableARMLongCalls) return false; @@ -1711,7 +1803,7 @@ bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) {    if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes))      return false; -  // Issue the call, BLXr9 for darwin, BLX otherwise. This uses V5 ops. +  // Issue the call, BLr9 for darwin, BL otherwise.    // TODO: Turn this into the table of arm call ops.    MachineInstrBuilder MIB;    unsigned CallOpc = ARMSelectCallOp(NULL); @@ -1772,13 +1864,9 @@ bool ARMFastISel::SelectCall(const Instruction *I) {    else if (!isTypeLegal(RetTy, RetVT))      return false; -  // For now we're using BLX etc on the assumption that we have v5t ops. -  // TODO: Maybe? -  if (!Subtarget->hasV5TOps()) return false; -    // TODO: For now if we have long calls specified we don't handle the call.    if (EnableARMLongCalls) return false; -   +    // Set up the argument vectors.    SmallVector<Value*, 8> Args;    SmallVector<unsigned, 8> ArgRegs; @@ -1827,7 +1915,7 @@ bool ARMFastISel::SelectCall(const Instruction *I) {    if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes))      return false; -  // Issue the call, BLXr9 for darwin, BLX otherwise. This uses V5 ops. +  // Issue the call, BLr9 for darwin, BL otherwise.    // TODO: Turn this into the table of arm call ops.    MachineInstrBuilder MIB;    unsigned CallOpc = ARMSelectCallOp(GV); @@ -1842,7 +1930,7 @@ bool ARMFastISel::SelectCall(const Instruction *I) {      MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL,                           TII.get(CallOpc))            .addGlobalAddress(GV, 0, 0)); -   +    // Add implicit physical register uses to the call.    for (unsigned i = 0, e = RegArgs.size(); i != e; ++i)      MIB.addReg(RegArgs[i]);  | 
