Exemple #1
0
void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
                               MachineBasicBlock::iterator &MBBI, DebugLoc dl,
                               unsigned DestReg, unsigned BaseReg, int NumBytes,
                               ARMCC::CondCodes Pred, unsigned PredReg,
                               const ARMBaseInstrInfo &TII, unsigned MIFlags) {
  bool isSub = NumBytes < 0;
  if (isSub) NumBytes = -NumBytes;

  // If profitable, use a movw or movt to materialize the offset.
  // FIXME: Use the scavenger to grab a scratch register.
  if (DestReg != ARM::SP && DestReg != BaseReg &&
      NumBytes >= 4096 &&
      ARM_AM::getT2SOImmVal(NumBytes) == -1) {
    bool Fits = false;
    if (NumBytes < 65536) {
      // Use a movw to materialize the 16-bit constant.
      BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi16), DestReg)
        .addImm(NumBytes)
        .addImm((unsigned)Pred).addReg(PredReg).setMIFlags(MIFlags);
      Fits = true;
    } else if ((NumBytes & 0xffff) == 0) {
      // Use a movt to materialize the 32-bit constant.
      BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVTi16), DestReg)
        .addReg(DestReg)
        .addImm(NumBytes >> 16)
        .addImm((unsigned)Pred).addReg(PredReg).setMIFlags(MIFlags);
      Fits = true;
    }
static bool selectUnmergeValues(MachineInstrBuilder &MIB,
                                const ARMBaseInstrInfo &TII,
                                MachineRegisterInfo &MRI,
                                const TargetRegisterInfo &TRI,
                                const RegisterBankInfo &RBI) {
  assert(TII.getSubtarget().hasVFP2() && "Can't select unmerge without VFP");

  // We only support G_UNMERGE_VALUES as a way to break up one DPR into two
  // GPRs.
  unsigned VReg0 = MIB->getOperand(0).getReg();
  (void)VReg0;
  assert(MRI.getType(VReg0).getSizeInBits() == 32 &&
         RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::GPRRegBankID &&
         "Unsupported operand for G_UNMERGE_VALUES");
  unsigned VReg1 = MIB->getOperand(1).getReg();
  (void)VReg1;
  assert(MRI.getType(VReg1).getSizeInBits() == 32 &&
         RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID &&
         "Unsupported operand for G_UNMERGE_VALUES");
  unsigned VReg2 = MIB->getOperand(2).getReg();
  (void)VReg2;
  assert(MRI.getType(VReg2).getSizeInBits() == 64 &&
         RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::FPRRegBankID &&
         "Unsupported operand for G_UNMERGE_VALUES");

  MIB->setDesc(TII.get(ARM::VMOVRRD));
  MIB.add(predOps(ARMCC::AL));

  return true;
}
// FIXME: Make generic?
static unsigned GetFunctionSizeInBytes(const MachineFunction &MF,
                                       const ARMBaseInstrInfo &TII) {
  unsigned FnSize = 0;
  for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end();
       MBBI != E; ++MBBI) {
    const MachineBasicBlock &MBB = *MBBI;
    for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end();
         I != E; ++I)
      FnSize += TII.GetInstSizeInBytes(I);
  }
  return FnSize;
}
Exemple #4
0
bool Thumb1RegisterInfo::
rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
                  unsigned FrameReg, int &Offset,
                  const ARMBaseInstrInfo &TII) const {
  MachineInstr &MI = *II;
  MachineBasicBlock &MBB = *MI.getParent();
  DebugLoc dl = MI.getDebugLoc();
  MachineInstrBuilder MIB(*MBB.getParent(), &MI);
  unsigned Opcode = MI.getOpcode();
  const MCInstrDesc &Desc = MI.getDesc();
  unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);

  if (Opcode == ARM::tADDframe) {
    Offset += MI.getOperand(FrameRegIdx+1).getImm();
    unsigned DestReg = MI.getOperand(0).getReg();

    emitThumbRegPlusImmediate(MBB, II, dl, DestReg, FrameReg, Offset, TII,
                              *this);
    MBB.erase(II);
    return true;
  } else {
    if (AddrMode != ARMII::AddrModeT1_s)
      llvm_unreachable("Unsupported addressing mode!");

    unsigned ImmIdx = FrameRegIdx + 1;
    int InstrOffs = MI.getOperand(ImmIdx).getImm();
    unsigned NumBits = (FrameReg == ARM::SP) ? 8 : 5;
    unsigned Scale = 4;

    Offset += InstrOffs * Scale;
    assert((Offset & (Scale - 1)) == 0 && "Can't encode this offset!");

    // Common case: small offset, fits into instruction.
    MachineOperand &ImmOp = MI.getOperand(ImmIdx);
    int ImmedOffset = Offset / Scale;
    unsigned Mask = (1 << NumBits) - 1;

    if ((unsigned)Offset <= Mask * Scale) {
      // Replace the FrameIndex with the frame register (e.g., sp).
      MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
      ImmOp.ChangeToImmediate(ImmedOffset);

      // If we're using a register where sp was stored, convert the instruction
      // to the non-SP version.
      unsigned NewOpc = convertToNonSPOpcode(Opcode);
      if (NewOpc != Opcode && FrameReg != ARM::SP)
        MI.setDesc(TII.get(NewOpc));

      return true;
    }

    NumBits = 5;
    Mask = (1 << NumBits) - 1;

    // If this is a thumb spill / restore, we will be using a constpool load to
    // materialize the offset.
    if (Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi) {
      ImmOp.ChangeToImmediate(0);
    } else {
      // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
      ImmedOffset = ImmedOffset & Mask;
      ImmOp.ChangeToImmediate(ImmedOffset);
      Offset &= ~(Mask * Scale);
    }
  }

  return Offset == 0;
}
Exemple #5
0
bool Thumb1RegisterInfo::
rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
                  unsigned FrameReg, int &Offset,
                  const ARMBaseInstrInfo &TII) const {
  MachineInstr &MI = *II;
  MachineBasicBlock &MBB = *MI.getParent();
  DebugLoc dl = MI.getDebugLoc();
  MachineInstrBuilder MIB(*MBB.getParent(), &MI);
  unsigned Opcode = MI.getOpcode();
  const MCInstrDesc &Desc = MI.getDesc();
  unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);

  if (Opcode == ARM::tADDrSPi) {
    Offset += MI.getOperand(FrameRegIdx+1).getImm();

    // Can't use tADDrSPi if it's based off the frame pointer.
    unsigned NumBits = 0;
    unsigned Scale = 1;
    if (FrameReg != ARM::SP) {
      Opcode = ARM::tADDi3;
      NumBits = 3;
    } else {
      NumBits = 8;
      Scale = 4;
      assert((Offset & 3) == 0 &&
             "Thumb add/sub sp, #imm immediate must be multiple of 4!");
    }

    unsigned PredReg;
    if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) {
      // Turn it into a move.
      MI.setDesc(TII.get(ARM::tMOVr));
      MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
      // Remove offset
      MI.RemoveOperand(FrameRegIdx+1);
      return true;
    }

    // Common case: small offset, fits into instruction.
    unsigned Mask = (1 << NumBits) - 1;
    if (((Offset / Scale) & ~Mask) == 0) {
      // Replace the FrameIndex with sp / fp
      if (Opcode == ARM::tADDi3) {
        MI.setDesc(TII.get(Opcode));
        removeOperands(MI, FrameRegIdx);
        AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg)
                       .addImm(Offset / Scale));
      } else {
        MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
        MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset / Scale);
      }
      return true;
    }

    unsigned DestReg = MI.getOperand(0).getReg();
    unsigned Bytes = (Offset > 0) ? Offset : -Offset;
    unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, NumBits, Scale);
    // MI would expand into a large number of instructions. Don't try to
    // simplify the immediate.
    if (NumMIs > 2) {
      emitThumbRegPlusImmediate(MBB, II, dl, DestReg, FrameReg, Offset, TII,
                                *this);
      MBB.erase(II);
      return true;
    }

    if (Offset > 0) {
      // Translate r0 = add sp, imm to
      // r0 = add sp, 255*4
      // r0 = add r0, (imm - 255*4)
      if (Opcode == ARM::tADDi3) {
        MI.setDesc(TII.get(Opcode));
        removeOperands(MI, FrameRegIdx);
        AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask));
      } else {
        MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
        MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Mask);
      }
      Offset = (Offset - Mask * Scale);
      MachineBasicBlock::iterator NII = llvm::next(II);
      emitThumbRegPlusImmediate(MBB, NII, dl, DestReg, DestReg, Offset, TII,
                                *this);
    } else {
      // Translate r0 = add sp, -imm to
      // r0 = -imm (this is then translated into a series of instructions)
      // r0 = add r0, sp
      emitThumbConstant(MBB, II, DestReg, Offset, TII, *this, dl);

      MI.setDesc(TII.get(ARM::tADDhirr));
      MI.getOperand(FrameRegIdx).ChangeToRegister(DestReg, false, false, true);
      MI.getOperand(FrameRegIdx+1).ChangeToRegister(FrameReg, false);
    }
    return true;
  } else {
    if (AddrMode != ARMII::AddrModeT1_s)
      llvm_unreachable("Unsupported addressing mode!");

    unsigned ImmIdx = FrameRegIdx + 1;
    int InstrOffs = MI.getOperand(ImmIdx).getImm();
    unsigned NumBits = (FrameReg == ARM::SP) ? 8 : 5;
    unsigned Scale = 4;

    Offset += InstrOffs * Scale;
    assert((Offset & (Scale - 1)) == 0 && "Can't encode this offset!");

    // Common case: small offset, fits into instruction.
    MachineOperand &ImmOp = MI.getOperand(ImmIdx);
    int ImmedOffset = Offset / Scale;
    unsigned Mask = (1 << NumBits) - 1;

    if ((unsigned)Offset <= Mask * Scale) {
      // Replace the FrameIndex with the frame register (e.g., sp).
      MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
      ImmOp.ChangeToImmediate(ImmedOffset);

      // If we're using a register where sp was stored, convert the instruction
      // to the non-SP version.
      unsigned NewOpc = convertToNonSPOpcode(Opcode);
      if (NewOpc != Opcode && FrameReg != ARM::SP)
        MI.setDesc(TII.get(NewOpc));

      return true;
    }

    NumBits = 5;
    Mask = (1 << NumBits) - 1;

    // If this is a thumb spill / restore, we will be using a constpool load to
    // materialize the offset.
    if (Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi) {
      ImmOp.ChangeToImmediate(0);
    } else {
      // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
      ImmedOffset = ImmedOffset & Mask;
      ImmOp.ChangeToImmediate(ImmedOffset);
      Offset &= ~(Mask * Scale);
    }
  }

  return Offset == 0;
}