mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-11-04 05:17:07 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@110292 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			1472 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1472 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file contains a printer that converts from our internal representation
 | 
						|
// of machine-dependent LLVM code to GAS-format ARM assembly language.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#define DEBUG_TYPE "asm-printer"
 | 
						|
#include "ARM.h"
 | 
						|
#include "ARMBuildAttrs.h"
 | 
						|
#include "ARMAddressingModes.h"
 | 
						|
#include "ARMConstantPoolValue.h"
 | 
						|
#include "AsmPrinter/ARMInstPrinter.h"
 | 
						|
#include "ARMMachineFunctionInfo.h"
 | 
						|
#include "ARMMCInstLower.h"
 | 
						|
#include "ARMTargetMachine.h"
 | 
						|
#include "llvm/Analysis/DebugInfo.h"
 | 
						|
#include "llvm/Constants.h"
 | 
						|
#include "llvm/Module.h"
 | 
						|
#include "llvm/Type.h"
 | 
						|
#include "llvm/Assembly/Writer.h"
 | 
						|
#include "llvm/CodeGen/AsmPrinter.h"
 | 
						|
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
 | 
						|
#include "llvm/CodeGen/MachineFunctionPass.h"
 | 
						|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
 | 
						|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 | 
						|
#include "llvm/MC/MCAsmInfo.h"
 | 
						|
#include "llvm/MC/MCContext.h"
 | 
						|
#include "llvm/MC/MCExpr.h"
 | 
						|
#include "llvm/MC/MCInst.h"
 | 
						|
#include "llvm/MC/MCSectionMachO.h"
 | 
						|
#include "llvm/MC/MCStreamer.h"
 | 
						|
#include "llvm/MC/MCSymbol.h"
 | 
						|
#include "llvm/Target/Mangler.h"
 | 
						|
#include "llvm/Target/TargetData.h"
 | 
						|
#include "llvm/Target/TargetMachine.h"
 | 
						|
#include "llvm/Target/TargetOptions.h"
 | 
						|
#include "llvm/Target/TargetRegistry.h"
 | 
						|
#include "llvm/ADT/SmallPtrSet.h"
 | 
						|
#include "llvm/ADT/SmallString.h"
 | 
						|
#include "llvm/ADT/StringExtras.h"
 | 
						|
#include "llvm/Support/CommandLine.h"
 | 
						|
#include "llvm/Support/Debug.h"
 | 
						|
#include "llvm/Support/ErrorHandling.h"
 | 
						|
#include "llvm/Support/raw_ostream.h"
 | 
						|
#include <cctype>
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
static cl::opt<bool>
 | 
						|
EnableMCInst("enable-arm-mcinst-printer", cl::Hidden,
 | 
						|
            cl::desc("enable experimental asmprinter gunk in the arm backend"));
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
  namespace ARM {
 | 
						|
    enum DW_ISA {
 | 
						|
      DW_ISA_ARM_thumb = 1,
 | 
						|
      DW_ISA_ARM_arm = 2
 | 
						|
    };
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
  class ARMAsmPrinter : public AsmPrinter {
 | 
						|
 | 
						|
    /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
 | 
						|
    /// make the right decision when printing asm code for different targets.
 | 
						|
    const ARMSubtarget *Subtarget;
 | 
						|
 | 
						|
    /// AFI - Keep a pointer to ARMFunctionInfo for the current
 | 
						|
    /// MachineFunction.
 | 
						|
    ARMFunctionInfo *AFI;
 | 
						|
 | 
						|
    /// MCP - Keep a pointer to constantpool entries of the current
 | 
						|
    /// MachineFunction.
 | 
						|
    const MachineConstantPool *MCP;
 | 
						|
 | 
						|
  public:
 | 
						|
    explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
 | 
						|
      : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) {
 | 
						|
      Subtarget = &TM.getSubtarget<ARMSubtarget>();
 | 
						|
    }
 | 
						|
 | 
						|
    virtual const char *getPassName() const {
 | 
						|
      return "ARM Assembly Printer";
 | 
						|
    }
 | 
						|
    
 | 
						|
    void printInstructionThroughMCStreamer(const MachineInstr *MI);
 | 
						|
    
 | 
						|
 | 
						|
    void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
 | 
						|
                      const char *Modifier = 0);
 | 
						|
    void printSOImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
 | 
						|
    void printSOImm2PartOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                raw_ostream &O);
 | 
						|
    void printSORegOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                           raw_ostream &O);
 | 
						|
    void printAddrMode2Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printAddrMode3Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printAddrMode4Operand(const MachineInstr *MI, int OpNum,raw_ostream &O,
 | 
						|
                               const char *Modifier = 0);
 | 
						|
    void printAddrMode5Operand(const MachineInstr *MI, int OpNum,raw_ostream &O,
 | 
						|
                               const char *Modifier = 0);
 | 
						|
    void printAddrMode6Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printAddrMode6OffsetOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printAddrModePCOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                raw_ostream &O,
 | 
						|
                                const char *Modifier = 0);
 | 
						|
    void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNum,
 | 
						|
                                         raw_ostream &O);
 | 
						|
 | 
						|
    void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                raw_ostream &O);
 | 
						|
    void printThumbITMask(const MachineInstr *MI, int OpNum, raw_ostream &O);
 | 
						|
    void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                      raw_ostream &O,
 | 
						|
                                      unsigned Scale);
 | 
						|
    void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
 | 
						|
    void printT2SOOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
 | 
						|
    void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
    void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                    raw_ostream &O);
 | 
						|
    void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum,
 | 
						|
                                      raw_ostream &O);
 | 
						|
    void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                          raw_ostream &O);
 | 
						|
    void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                            raw_ostream &O) {}
 | 
						|
    void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O);
 | 
						|
 | 
						|
    void printCPSOptionOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O) {}
 | 
						|
    void printMSRMaskOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                             raw_ostream &O) {}
 | 
						|
    void printNegZeroOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                             raw_ostream &O) {}
 | 
						|
    void printPredicateOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                        raw_ostream &O);
 | 
						|
    void printSBitModifierOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                  raw_ostream &O);
 | 
						|
    void printPCLabel(const MachineInstr *MI, int OpNum,
 | 
						|
                      raw_ostream &O);
 | 
						|
    void printRegisterList(const MachineInstr *MI, int OpNum,
 | 
						|
                           raw_ostream &O);
 | 
						|
    void printCPInstOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                            raw_ostream &O,
 | 
						|
                            const char *Modifier);
 | 
						|
    void printJTBlockOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                             raw_ostream &O);
 | 
						|
    void printJT2BlockOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                              raw_ostream &O);
 | 
						|
    void printTBAddrMode(const MachineInstr *MI, int OpNum,
 | 
						|
                         raw_ostream &O);
 | 
						|
    void printNoHashImmediate(const MachineInstr *MI, int OpNum,
 | 
						|
                              raw_ostream &O);
 | 
						|
    void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                               raw_ostream &O);
 | 
						|
    void printNEONModImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                raw_ostream &O);
 | 
						|
 | 
						|
    virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
 | 
						|
                                 unsigned AsmVariant, const char *ExtraCode,
 | 
						|
                                 raw_ostream &O);
 | 
						|
    virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
 | 
						|
                                       unsigned AsmVariant,
 | 
						|
                                       const char *ExtraCode, raw_ostream &O);
 | 
						|
 | 
						|
    void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen
 | 
						|
    static const char *getRegisterName(unsigned RegNo);
 | 
						|
 | 
						|
    virtual void EmitInstruction(const MachineInstr *MI);
 | 
						|
    bool runOnMachineFunction(MachineFunction &F);
 | 
						|
    
 | 
						|
    virtual void EmitConstantPool() {} // we emit constant pools customly!
 | 
						|
    virtual void EmitFunctionEntryLabel();
 | 
						|
    void EmitStartOfAsmFile(Module &M);
 | 
						|
    void EmitEndOfAsmFile(Module &M);
 | 
						|
 | 
						|
    MachineLocation getDebugValueLocation(const MachineInstr *MI) const {
 | 
						|
      MachineLocation Location;
 | 
						|
      assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
 | 
						|
      // Frame address.  Currently handles register +- offset only.
 | 
						|
      if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm())
 | 
						|
        Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
 | 
						|
      else {
 | 
						|
        DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n");
 | 
						|
      }
 | 
						|
      return Location;
 | 
						|
    }
 | 
						|
 | 
						|
    virtual unsigned getISAEncoding() {
 | 
						|
      // ARM/Darwin adds ISA to the DWARF info for each function.
 | 
						|
      if (!Subtarget->isTargetDarwin())
 | 
						|
        return 0;
 | 
						|
      return Subtarget->isThumb() ?
 | 
						|
        llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm;
 | 
						|
    }
 | 
						|
 | 
						|
    MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2,
 | 
						|
                                          const MachineBasicBlock *MBB) const;
 | 
						|
    MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const;
 | 
						|
 | 
						|
    /// EmitMachineConstantPoolValue - Print a machine constantpool value to
 | 
						|
    /// the .s file.
 | 
						|
    virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
 | 
						|
      SmallString<128> Str;
 | 
						|
      raw_svector_ostream OS(Str);
 | 
						|
      EmitMachineConstantPoolValue(MCPV, OS);
 | 
						|
      OutStreamer.EmitRawText(OS.str());
 | 
						|
    }
 | 
						|
    
 | 
						|
    void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
      switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) {
 | 
						|
      case 1: O << MAI->getData8bitsDirective(0); break;
 | 
						|
      case 2: O << MAI->getData16bitsDirective(0); break;
 | 
						|
      case 4: O << MAI->getData32bitsDirective(0); break;
 | 
						|
      default: assert(0 && "Unknown CPV size");
 | 
						|
      }
 | 
						|
 | 
						|
      ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV);
 | 
						|
 | 
						|
      if (ACPV->isLSDA()) {
 | 
						|
        O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber();
 | 
						|
      } else if (ACPV->isBlockAddress()) {
 | 
						|
        O << *GetBlockAddressSymbol(ACPV->getBlockAddress());
 | 
						|
      } else if (ACPV->isGlobalValue()) {
 | 
						|
        const GlobalValue *GV = ACPV->getGV();
 | 
						|
        bool isIndirect = Subtarget->isTargetDarwin() &&
 | 
						|
          Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel());
 | 
						|
        if (!isIndirect)
 | 
						|
          O << *Mang->getSymbol(GV);
 | 
						|
        else {
 | 
						|
          // FIXME: Remove this when Darwin transition to @GOT like syntax.
 | 
						|
          MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
 | 
						|
          O << *Sym;
 | 
						|
          
 | 
						|
          MachineModuleInfoMachO &MMIMachO =
 | 
						|
            MMI->getObjFileInfo<MachineModuleInfoMachO>();
 | 
						|
          MachineModuleInfoImpl::StubValueTy &StubSym =
 | 
						|
            GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) :
 | 
						|
                                        MMIMachO.getGVStubEntry(Sym);
 | 
						|
          if (StubSym.getPointer() == 0)
 | 
						|
            StubSym = MachineModuleInfoImpl::
 | 
						|
              StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage());
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
 | 
						|
        O << *GetExternalSymbolSymbol(ACPV->getSymbol());
 | 
						|
      }
 | 
						|
 | 
						|
      if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")";
 | 
						|
      if (ACPV->getPCAdjustment() != 0) {
 | 
						|
        O << "-(" << MAI->getPrivateGlobalPrefix() << "PC"
 | 
						|
          << getFunctionNumber() << "_"  << ACPV->getLabelId()
 | 
						|
          << "+" << (unsigned)ACPV->getPCAdjustment();
 | 
						|
         if (ACPV->mustAddCurrentAddress())
 | 
						|
           O << "-.";
 | 
						|
         O << ')';
 | 
						|
      }
 | 
						|
    }
 | 
						|
  };
 | 
						|
} // end of anonymous namespace
 | 
						|
 | 
						|
#include "ARMGenAsmWriter.inc"
 | 
						|
 | 
						|
void ARMAsmPrinter::EmitFunctionEntryLabel() {
 | 
						|
  if (AFI->isThumbFunction()) {
 | 
						|
    OutStreamer.EmitRawText(StringRef("\t.code\t16"));
 | 
						|
    if (!Subtarget->isTargetDarwin())
 | 
						|
      OutStreamer.EmitRawText(StringRef("\t.thumb_func"));
 | 
						|
    else {
 | 
						|
      // This needs to emit to a temporary string to get properly quoted
 | 
						|
      // MCSymbols when they have spaces in them.
 | 
						|
      SmallString<128> Tmp;
 | 
						|
      raw_svector_ostream OS(Tmp);
 | 
						|
      OS << "\t.thumb_func\t" << *CurrentFnSym;
 | 
						|
      OutStreamer.EmitRawText(OS.str());
 | 
						|
    }
 | 
						|
  }
 | 
						|
  
 | 
						|
  OutStreamer.EmitLabel(CurrentFnSym);
 | 
						|
}
 | 
						|
 | 
						|
/// runOnMachineFunction - This uses the printInstruction()
 | 
						|
/// method to print assembly for each instruction.
 | 
						|
///
 | 
						|
bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
 | 
						|
  AFI = MF.getInfo<ARMFunctionInfo>();
 | 
						|
  MCP = MF.getConstantPool();
 | 
						|
 | 
						|
  return AsmPrinter::runOnMachineFunction(MF);
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                 raw_ostream &O, const char *Modifier) {
 | 
						|
  const MachineOperand &MO = MI->getOperand(OpNum);
 | 
						|
  unsigned TF = MO.getTargetFlags();
 | 
						|
 | 
						|
  switch (MO.getType()) {
 | 
						|
  default:
 | 
						|
    assert(0 && "<unknown operand type>");
 | 
						|
  case MachineOperand::MO_Register: {
 | 
						|
    unsigned Reg = MO.getReg();
 | 
						|
    assert(TargetRegisterInfo::isPhysicalRegister(Reg));
 | 
						|
    if (Modifier && strcmp(Modifier, "dregpair") == 0) {
 | 
						|
      unsigned DRegLo = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_0);
 | 
						|
      unsigned DRegHi = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_1);
 | 
						|
      O << '{'
 | 
						|
        << getRegisterName(DRegLo) << ", " << getRegisterName(DRegHi)
 | 
						|
        << '}';
 | 
						|
    } else if (Modifier && strcmp(Modifier, "lane") == 0) {
 | 
						|
      unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
 | 
						|
      unsigned DReg =
 | 
						|
        TM.getRegisterInfo()->getMatchingSuperReg(Reg,
 | 
						|
          RegNum & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass);
 | 
						|
      O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']';
 | 
						|
    } else {
 | 
						|
      assert(!MO.getSubReg() && "Subregs should be eliminated!");
 | 
						|
      O << getRegisterName(Reg);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case MachineOperand::MO_Immediate: {
 | 
						|
    int64_t Imm = MO.getImm();
 | 
						|
    O << '#';
 | 
						|
    if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
 | 
						|
        (TF & ARMII::MO_LO16))
 | 
						|
      O << ":lower16:";
 | 
						|
    else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
 | 
						|
             (TF & ARMII::MO_HI16))
 | 
						|
      O << ":upper16:";
 | 
						|
    O << Imm;
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case MachineOperand::MO_MachineBasicBlock:
 | 
						|
    O << *MO.getMBB()->getSymbol();
 | 
						|
    return;
 | 
						|
  case MachineOperand::MO_GlobalAddress: {
 | 
						|
    bool isCallOp = Modifier && !strcmp(Modifier, "call");
 | 
						|
    const GlobalValue *GV = MO.getGlobal();
 | 
						|
 | 
						|
    if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
 | 
						|
        (TF & ARMII::MO_LO16))
 | 
						|
      O << ":lower16:";
 | 
						|
    else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
 | 
						|
             (TF & ARMII::MO_HI16))
 | 
						|
      O << ":upper16:";
 | 
						|
    O << *Mang->getSymbol(GV);
 | 
						|
 | 
						|
    printOffset(MO.getOffset(), O);
 | 
						|
 | 
						|
    if (isCallOp && Subtarget->isTargetELF() &&
 | 
						|
        TM.getRelocationModel() == Reloc::PIC_)
 | 
						|
      O << "(PLT)";
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case MachineOperand::MO_ExternalSymbol: {
 | 
						|
    bool isCallOp = Modifier && !strcmp(Modifier, "call");
 | 
						|
    O << *GetExternalSymbolSymbol(MO.getSymbolName());
 | 
						|
    
 | 
						|
    if (isCallOp && Subtarget->isTargetELF() &&
 | 
						|
        TM.getRelocationModel() == Reloc::PIC_)
 | 
						|
      O << "(PLT)";
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  case MachineOperand::MO_ConstantPoolIndex:
 | 
						|
    O << *GetCPISymbol(MO.getIndex());
 | 
						|
    break;
 | 
						|
  case MachineOperand::MO_JumpTableIndex:
 | 
						|
    O << *GetJTISymbol(MO.getIndex());
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm,
 | 
						|
                       const MCAsmInfo *MAI) {
 | 
						|
  // Break it up into two parts that make up a shifter immediate.
 | 
						|
  V = ARM_AM::getSOImmVal(V);
 | 
						|
  assert(V != -1 && "Not a valid so_imm value!");
 | 
						|
 | 
						|
  unsigned Imm = ARM_AM::getSOImmValImm(V);
 | 
						|
  unsigned Rot = ARM_AM::getSOImmValRot(V);
 | 
						|
 | 
						|
  // Print low-level immediate formation info, per
 | 
						|
  // A5.1.3: "Data-processing operands - Immediate".
 | 
						|
  if (Rot) {
 | 
						|
    O << "#" << Imm << ", " << Rot;
 | 
						|
    // Pretty printed version.
 | 
						|
    if (VerboseAsm) {
 | 
						|
      O << "\t" << MAI->getCommentString() << ' ';
 | 
						|
      O << (int)ARM_AM::rotr32(Imm, Rot);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    O << "#" << Imm;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit
 | 
						|
/// immediate in bits 0-7.
 | 
						|
void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
  const MachineOperand &MO = MI->getOperand(OpNum);
 | 
						|
  assert(MO.isImm() && "Not a valid so_imm value!");
 | 
						|
  printSOImm(O, MO.getImm(), isVerbose(), MAI);
 | 
						|
}
 | 
						|
 | 
						|
/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov'
 | 
						|
/// followed by an 'orr' to materialize.
 | 
						|
void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  const MachineOperand &MO = MI->getOperand(OpNum);
 | 
						|
  assert(MO.isImm() && "Not a valid so_imm value!");
 | 
						|
  unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm());
 | 
						|
  unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm());
 | 
						|
  printSOImm(O, V1, isVerbose(), MAI);
 | 
						|
  O << "\n\torr";
 | 
						|
  printPredicateOperand(MI, 2, O);
 | 
						|
  O << "\t";
 | 
						|
  printOperand(MI, 0, O);
 | 
						|
  O << ", ";
 | 
						|
  printOperand(MI, 0, O);
 | 
						|
  O << ", ";
 | 
						|
  printSOImm(O, V2, isVerbose(), MAI);
 | 
						|
}
 | 
						|
 | 
						|
// so_reg is a 4-operand unit corresponding to register forms of the A5.1
 | 
						|
// "Addressing Mode 1 - Data-processing operands" forms.  This includes:
 | 
						|
//    REG 0   0           - e.g. R5
 | 
						|
//    REG REG 0,SH_OPC    - e.g. R5, ROR R3
 | 
						|
//    REG 0   IMM,SH_OPC  - e.g. R5, LSL #3
 | 
						|
void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  const MachineOperand &MO3 = MI->getOperand(Op+2);
 | 
						|
 | 
						|
  O << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  // Print the shift opc.
 | 
						|
  ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm());
 | 
						|
  O << ", " << ARM_AM::getShiftOpcStr(ShOpc);
 | 
						|
  if (MO2.getReg()) {
 | 
						|
    O << ' ' << getRegisterName(MO2.getReg());
 | 
						|
    assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);
 | 
						|
  } else if (ShOpc != ARM_AM::rrx) {
 | 
						|
    O << " #" << ARM_AM::getSORegOffset(MO3.getImm());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  const MachineOperand &MO3 = MI->getOperand(Op+2);
 | 
						|
 | 
						|
  if (!MO1.isReg()) {   // FIXME: This is for CP entries, but isn't right.
 | 
						|
    printOperand(MI, Op, O);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  if (!MO2.getReg()) {
 | 
						|
    if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0.
 | 
						|
      O << ", #"
 | 
						|
        << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
 | 
						|
        << ARM_AM::getAM2Offset(MO3.getImm());
 | 
						|
    O << "]";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << ", "
 | 
						|
    << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
 | 
						|
    << getRegisterName(MO2.getReg());
 | 
						|
 | 
						|
  if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
 | 
						|
    O << ", "
 | 
						|
      << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm()))
 | 
						|
      << " #" << ShImm;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op,
 | 
						|
                                                raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
 | 
						|
  if (!MO1.getReg()) {
 | 
						|
    unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm());
 | 
						|
    O << "#"
 | 
						|
      << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
 | 
						|
      << ImmOffs;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
 | 
						|
    << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
 | 
						|
    O << ", "
 | 
						|
      << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm()))
 | 
						|
      << " #" << ShImm;
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  const MachineOperand &MO3 = MI->getOperand(Op+2);
 | 
						|
 | 
						|
  assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  if (MO2.getReg()) {
 | 
						|
    O << ", "
 | 
						|
      << (char)ARM_AM::getAM3Op(MO3.getImm())
 | 
						|
      << getRegisterName(MO2.getReg())
 | 
						|
      << "]";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm()))
 | 
						|
    O << ", #"
 | 
						|
      << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
 | 
						|
      << ImmOffs;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op,
 | 
						|
                                                raw_ostream &O){
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
 | 
						|
  if (MO1.getReg()) {
 | 
						|
    O << (char)ARM_AM::getAM3Op(MO2.getImm())
 | 
						|
      << getRegisterName(MO1.getReg());
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm());
 | 
						|
  O << "#"
 | 
						|
    << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm()))
 | 
						|
    << ImmOffs;
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op,
 | 
						|
                                          raw_ostream &O,
 | 
						|
                                          const char *Modifier) {
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
 | 
						|
  if (Modifier && strcmp(Modifier, "submode") == 0) {
 | 
						|
    O << ARM_AM::getAMSubModeStr(Mode);
 | 
						|
  } else if (Modifier && strcmp(Modifier, "wide") == 0) {
 | 
						|
    ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm());
 | 
						|
    if (Mode == ARM_AM::ia)
 | 
						|
      O << ".w";
 | 
						|
  } else {
 | 
						|
    printOperand(MI, Op, O);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op,
 | 
						|
                                          raw_ostream &O,
 | 
						|
                                          const char *Modifier) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
 | 
						|
  if (!MO1.isReg()) {   // FIXME: This is for CP entries, but isn't right.
 | 
						|
    printOperand(MI, Op, O);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
 | 
						|
 | 
						|
  if (Modifier && strcmp(Modifier, "submode") == 0) {
 | 
						|
    ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm());
 | 
						|
    O << ARM_AM::getAMSubModeStr(Mode);
 | 
						|
    return;
 | 
						|
  } else if (Modifier && strcmp(Modifier, "base") == 0) {
 | 
						|
    // Used for FSTM{D|S} and LSTM{D|S} operations.
 | 
						|
    O << getRegisterName(MO1.getReg());
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) {
 | 
						|
    O << ", #"
 | 
						|
      << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm()))
 | 
						|
      << ImmOffs*4;
 | 
						|
  }
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
  if (MO2.getImm()) {
 | 
						|
    // FIXME: Both darwin as and GNU as violate ARM docs here.
 | 
						|
    O << ", :" << (MO2.getImm() << 3);
 | 
						|
  }
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrMode6OffsetOperand(const MachineInstr *MI, int Op,
 | 
						|
                                                raw_ostream &O){
 | 
						|
  const MachineOperand &MO = MI->getOperand(Op);
 | 
						|
  if (MO.getReg() == 0)
 | 
						|
    O << "!";
 | 
						|
  else
 | 
						|
    O << ", " << getRegisterName(MO.getReg());
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O,
 | 
						|
                                           const char *Modifier) {
 | 
						|
  if (Modifier && strcmp(Modifier, "label") == 0) {
 | 
						|
    printPCLabel(MI, Op+1, O);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg()));
 | 
						|
  O << "[pc, " << getRegisterName(MO1.getReg()) << "]";
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op,
 | 
						|
                                              raw_ostream &O) {
 | 
						|
  const MachineOperand &MO = MI->getOperand(Op);
 | 
						|
  uint32_t v = ~MO.getImm();
 | 
						|
  int32_t lsb = CountTrailingZeros_32(v);
 | 
						|
  int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb;
 | 
						|
  assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!");
 | 
						|
  O << "#" << lsb << ", #" << width;
 | 
						|
}
 | 
						|
 | 
						|
//===--------------------------------------------------------------------===//
 | 
						|
 | 
						|
void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  O << "#" <<  MI->getOperand(Op).getImm() * 4;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op,
 | 
						|
                                raw_ostream &O) {
 | 
						|
  // (3 - the number of trailing zeros) is the number of then / else.
 | 
						|
  unsigned Mask = MI->getOperand(Op).getImm();
 | 
						|
  unsigned CondBit0 = Mask >> 4 & 1;
 | 
						|
  unsigned NumTZ = CountTrailingZeros_32(Mask);
 | 
						|
  assert(NumTZ <= 3 && "Invalid IT mask!");
 | 
						|
  for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) {
 | 
						|
    bool T = ((Mask >> Pos) & 1) == CondBit0;
 | 
						|
    if (T)
 | 
						|
      O << 't';
 | 
						|
    else
 | 
						|
      O << 'e';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
  O << ", " << getRegisterName(MO2.getReg()) << "]";
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op,
 | 
						|
                                            raw_ostream &O,
 | 
						|
                                            unsigned Scale) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  const MachineOperand &MO3 = MI->getOperand(Op+2);
 | 
						|
 | 
						|
  if (!MO1.isReg()) {   // FIXME: This is for CP entries, but isn't right.
 | 
						|
    printOperand(MI, Op, O);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
  if (MO3.getReg())
 | 
						|
    O << ", " << getRegisterName(MO3.getReg());
 | 
						|
  else if (unsigned ImmOffs = MO2.getImm())
 | 
						|
    O << ", #" << ImmOffs * Scale;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  printThumbAddrModeRI5Operand(MI, Op, O, 1);
 | 
						|
}
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  printThumbAddrModeRI5Operand(MI, Op, O, 2);
 | 
						|
}
 | 
						|
void
 | 
						|
ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  printThumbAddrModeRI5Operand(MI, Op, O, 4);
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op,
 | 
						|
                                                raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(Op);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(Op+1);
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
  if (unsigned ImmOffs = MO2.getImm())
 | 
						|
    O << ", #" << ImmOffs*4;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
//===--------------------------------------------------------------------===//
 | 
						|
 | 
						|
// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2
 | 
						|
// register with shift forms.
 | 
						|
// REG 0   0           - e.g. R5
 | 
						|
// REG IMM, SH_OPC     - e.g. R5, LSL #3
 | 
						|
void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                     raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1);
 | 
						|
 | 
						|
  unsigned Reg = MO1.getReg();
 | 
						|
  assert(TargetRegisterInfo::isPhysicalRegister(Reg));
 | 
						|
  O << getRegisterName(Reg);
 | 
						|
 | 
						|
  // Print the shift opc.
 | 
						|
  assert(MO2.isImm() && "Not a valid t2_so_reg value!");
 | 
						|
  ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO2.getImm());
 | 
						|
  O << ", " << ARM_AM::getShiftOpcStr(ShOpc);
 | 
						|
  if (ShOpc != ARM_AM::rrx)
 | 
						|
    O << " #" << ARM_AM::getSORegOffset(MO2.getImm());
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI,
 | 
						|
                                                int OpNum,
 | 
						|
                                                raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1);
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  unsigned OffImm = MO2.getImm();
 | 
						|
  if (OffImm)  // Don't print +0.
 | 
						|
    O << ", #" << OffImm;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI,
 | 
						|
                                               int OpNum,
 | 
						|
                                               raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1);
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  int32_t OffImm = (int32_t)MO2.getImm();
 | 
						|
  // Don't print +0.
 | 
						|
  if (OffImm < 0)
 | 
						|
    O << ", #-" << -OffImm;
 | 
						|
  else if (OffImm > 0)
 | 
						|
    O << ", #" << OffImm;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI,
 | 
						|
                                                 int OpNum,
 | 
						|
                                                 raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1);
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  int32_t OffImm = (int32_t)MO2.getImm() / 4;
 | 
						|
  // Don't print +0.
 | 
						|
  if (OffImm < 0)
 | 
						|
    O << ", #-" << -OffImm * 4;
 | 
						|
  else if (OffImm > 0)
 | 
						|
    O << ", #" << OffImm * 4;
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI,
 | 
						|
                                                     int OpNum,
 | 
						|
                                                     raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  int32_t OffImm = (int32_t)MO1.getImm();
 | 
						|
  // Don't print +0.
 | 
						|
  if (OffImm < 0)
 | 
						|
    O << "#-" << -OffImm;
 | 
						|
  else if (OffImm > 0)
 | 
						|
    O << "#" << OffImm;
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
 | 
						|
                                                int OpNum,
 | 
						|
                                                raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1);
 | 
						|
  const MachineOperand &MO3 = MI->getOperand(OpNum+2);
 | 
						|
 | 
						|
  O << "[" << getRegisterName(MO1.getReg());
 | 
						|
 | 
						|
  assert(MO2.getReg() && "Invalid so_reg load / store address!");
 | 
						|
  O << ", " << getRegisterName(MO2.getReg());
 | 
						|
 | 
						|
  unsigned ShAmt = MO3.getImm();
 | 
						|
  if (ShAmt) {
 | 
						|
    assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!");
 | 
						|
    O << ", lsl #" << ShAmt;
 | 
						|
  }
 | 
						|
  O << "]";
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//===--------------------------------------------------------------------===//
 | 
						|
 | 
						|
void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
 | 
						|
  if (CC != ARMCC::AL)
 | 
						|
    O << ARMCondCodeToString(CC);
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printMandatoryPredicateOperand(const MachineInstr *MI,
 | 
						|
                                                   int OpNum,
 | 
						|
                                                   raw_ostream &O) {
 | 
						|
  ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm();
 | 
						|
  O << ARMCondCodeToString(CC);
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                             raw_ostream &O){
 | 
						|
  unsigned Reg = MI->getOperand(OpNum).getReg();
 | 
						|
  if (Reg) {
 | 
						|
    assert(Reg == ARM::CPSR && "Expect ARM CPSR register!");
 | 
						|
    O << 's';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum,
 | 
						|
                                 raw_ostream &O) {
 | 
						|
  int Id = (int)MI->getOperand(OpNum).getImm();
 | 
						|
  O << MAI->getPrivateGlobalPrefix()
 | 
						|
    << "PC" << getFunctionNumber() << "_" << Id;
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum,
 | 
						|
                                      raw_ostream &O) {
 | 
						|
  O << "{";
 | 
						|
  for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) {
 | 
						|
    if (MI->getOperand(i).isImplicit())
 | 
						|
      continue;
 | 
						|
    if ((int)i != OpNum) O << ", ";
 | 
						|
    printOperand(MI, i, O);
 | 
						|
  }
 | 
						|
  O << "}";
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                       raw_ostream &O, const char *Modifier) {
 | 
						|
  assert(Modifier && "This operand only works with a modifier!");
 | 
						|
  // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the
 | 
						|
  // data itself.
 | 
						|
  if (!strcmp(Modifier, "label")) {
 | 
						|
    unsigned ID = MI->getOperand(OpNum).getImm();
 | 
						|
    OutStreamer.EmitLabel(GetCPISymbol(ID));
 | 
						|
  } else {
 | 
						|
    assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE");
 | 
						|
    unsigned CPI = MI->getOperand(OpNum).getIndex();
 | 
						|
 | 
						|
    const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI];
 | 
						|
 | 
						|
    if (MCPE.isMachineConstantPoolEntry()) {
 | 
						|
      EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
 | 
						|
    } else {
 | 
						|
      EmitGlobalConstant(MCPE.Val.ConstVal);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
MCSymbol *ARMAsmPrinter::
 | 
						|
GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2,
 | 
						|
                            const MachineBasicBlock *MBB) const {
 | 
						|
  SmallString<60> Name;
 | 
						|
  raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix()
 | 
						|
    << getFunctionNumber() << '_' << uid << '_' << uid2
 | 
						|
    << "_set_" << MBB->getNumber();
 | 
						|
  return OutContext.GetOrCreateSymbol(Name.str());
 | 
						|
}
 | 
						|
 | 
						|
MCSymbol *ARMAsmPrinter::
 | 
						|
GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const {
 | 
						|
  SmallString<60> Name;
 | 
						|
  raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "JTI"
 | 
						|
    << getFunctionNumber() << '_' << uid << '_' << uid2;
 | 
						|
  return OutContext.GetOrCreateSymbol(Name.str());
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                        raw_ostream &O) {
 | 
						|
  assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!");
 | 
						|
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
 | 
						|
  
 | 
						|
  unsigned JTI = MO1.getIndex();
 | 
						|
  MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
 | 
						|
  // Can't use EmitLabel until instprinter happens, label comes out in the wrong
 | 
						|
  // order.
 | 
						|
  O << "\n" << *JTISymbol << ":\n";
 | 
						|
 | 
						|
  const char *JTEntryDirective = MAI->getData32bitsDirective();
 | 
						|
 | 
						|
  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
 | 
						|
  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
 | 
						|
  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
 | 
						|
  bool UseSet= MAI->hasSetDirective() && TM.getRelocationModel() == Reloc::PIC_;
 | 
						|
  SmallPtrSet<MachineBasicBlock*, 8> JTSets;
 | 
						|
  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
 | 
						|
    MachineBasicBlock *MBB = JTBBs[i];
 | 
						|
    bool isNew = JTSets.insert(MBB);
 | 
						|
 | 
						|
    if (UseSet && isNew) {
 | 
						|
      O << "\t.set\t"
 | 
						|
        << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ','
 | 
						|
        << *MBB->getSymbol() << '-' << *JTISymbol << '\n';
 | 
						|
    }
 | 
						|
 | 
						|
    O << JTEntryDirective << ' ';
 | 
						|
    if (UseSet)
 | 
						|
      O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB);
 | 
						|
    else if (TM.getRelocationModel() == Reloc::PIC_)
 | 
						|
      O << *MBB->getSymbol() << '-' << *JTISymbol;
 | 
						|
    else
 | 
						|
      O << *MBB->getSymbol();
 | 
						|
 | 
						|
    if (i != e-1)
 | 
						|
      O << '\n';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                         raw_ostream &O) {
 | 
						|
  const MachineOperand &MO1 = MI->getOperand(OpNum);
 | 
						|
  const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
 | 
						|
  unsigned JTI = MO1.getIndex();
 | 
						|
  
 | 
						|
  MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
 | 
						|
  
 | 
						|
  // Can't use EmitLabel until instprinter happens, label comes out in the wrong
 | 
						|
  // order.
 | 
						|
  O << "\n" << *JTISymbol << ":\n";
 | 
						|
 | 
						|
  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
 | 
						|
  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
 | 
						|
  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
 | 
						|
  bool ByteOffset = false, HalfWordOffset = false;
 | 
						|
  if (MI->getOpcode() == ARM::t2TBB)
 | 
						|
    ByteOffset = true;
 | 
						|
  else if (MI->getOpcode() == ARM::t2TBH)
 | 
						|
    HalfWordOffset = true;
 | 
						|
 | 
						|
  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
 | 
						|
    MachineBasicBlock *MBB = JTBBs[i];
 | 
						|
    if (ByteOffset)
 | 
						|
      O << MAI->getData8bitsDirective();
 | 
						|
    else if (HalfWordOffset)
 | 
						|
      O << MAI->getData16bitsDirective();
 | 
						|
    
 | 
						|
    if (ByteOffset || HalfWordOffset)
 | 
						|
      O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2";
 | 
						|
    else
 | 
						|
      O << "\tb.w " << *MBB->getSymbol();
 | 
						|
 | 
						|
    if (i != e-1)
 | 
						|
      O << '\n';
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum,
 | 
						|
                                    raw_ostream &O) {
 | 
						|
  O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg());
 | 
						|
  if (MI->getOpcode() == ARM::t2TBH)
 | 
						|
    O << ", lsl #1";
 | 
						|
  O << ']';
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum,
 | 
						|
                                         raw_ostream &O) {
 | 
						|
  O << MI->getOperand(OpNum).getImm();
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  const ConstantFP *FP = MI->getOperand(OpNum).getFPImm();
 | 
						|
  O << '#' << FP->getValueAPF().convertToFloat();
 | 
						|
  if (isVerbose()) {
 | 
						|
    O << "\t\t" << MAI->getCommentString() << ' ';
 | 
						|
    WriteAsOperand(O, FP, /*PrintType=*/false);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  const ConstantFP *FP = MI->getOperand(OpNum).getFPImm();
 | 
						|
  O << '#' << FP->getValueAPF().convertToDouble();
 | 
						|
  if (isVerbose()) {
 | 
						|
    O << "\t\t" << MAI->getCommentString() << ' ';
 | 
						|
    WriteAsOperand(O, FP, /*PrintType=*/false);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::printNEONModImmOperand(const MachineInstr *MI, int OpNum,
 | 
						|
                                           raw_ostream &O) {
 | 
						|
  unsigned EncodedImm = MI->getOperand(OpNum).getImm();
 | 
						|
  unsigned EltBits;
 | 
						|
  uint64_t Val = ARM_AM::decodeNEONModImm(EncodedImm, EltBits);
 | 
						|
  O << "#0x" << utohexstr(Val);
 | 
						|
}
 | 
						|
 | 
						|
bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
 | 
						|
                                    unsigned AsmVariant, const char *ExtraCode,
 | 
						|
                                    raw_ostream &O) {
 | 
						|
  // Does this asm operand have a single letter operand modifier?
 | 
						|
  if (ExtraCode && ExtraCode[0]) {
 | 
						|
    if (ExtraCode[1] != 0) return true; // Unknown modifier.
 | 
						|
 | 
						|
    switch (ExtraCode[0]) {
 | 
						|
    default: return true;  // Unknown modifier.
 | 
						|
    case 'a': // Print as a memory address.
 | 
						|
      if (MI->getOperand(OpNum).isReg()) {
 | 
						|
        O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]";
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      // Fallthrough
 | 
						|
    case 'c': // Don't print "#" before an immediate operand.
 | 
						|
      if (!MI->getOperand(OpNum).isImm())
 | 
						|
        return true;
 | 
						|
      printNoHashImmediate(MI, OpNum, O);
 | 
						|
      return false;
 | 
						|
    case 'P': // Print a VFP double precision register.
 | 
						|
    case 'q': // Print a NEON quad precision register.
 | 
						|
      printOperand(MI, OpNum, O);
 | 
						|
      return false;
 | 
						|
    case 'Q':
 | 
						|
    case 'R':
 | 
						|
    case 'H':
 | 
						|
      report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!");
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  printOperand(MI, OpNum, O);
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
 | 
						|
                                          unsigned OpNum, unsigned AsmVariant,
 | 
						|
                                          const char *ExtraCode,
 | 
						|
                                          raw_ostream &O) {
 | 
						|
  if (ExtraCode && ExtraCode[0])
 | 
						|
    return true; // Unknown modifier.
 | 
						|
 | 
						|
  const MachineOperand &MO = MI->getOperand(OpNum);
 | 
						|
  assert(MO.isReg() && "unexpected inline asm memory operand");
 | 
						|
  O << "[" << getRegisterName(MO.getReg()) << "]";
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
 | 
						|
  if (EnableMCInst) {
 | 
						|
    printInstructionThroughMCStreamer(MI);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (MI->getOpcode() == ARM::CONSTPOOL_ENTRY)
 | 
						|
    EmitAlignment(2);
 | 
						|
  
 | 
						|
  SmallString<128> Str;
 | 
						|
  raw_svector_ostream OS(Str);
 | 
						|
  if (MI->getOpcode() == ARM::DBG_VALUE) {
 | 
						|
    unsigned NOps = MI->getNumOperands();
 | 
						|
    assert(NOps==4);
 | 
						|
    OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
 | 
						|
    // cast away const; DIetc do not take const operands for some reason.
 | 
						|
    DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps-1).getMetadata()));
 | 
						|
    OS << V.getName();
 | 
						|
    OS << " <- ";
 | 
						|
    // Frame address.  Currently handles register +- offset only.
 | 
						|
    assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
 | 
						|
    OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS);
 | 
						|
    OS << ']';
 | 
						|
    OS << "+";
 | 
						|
    printOperand(MI, NOps-2, OS);
 | 
						|
    OutStreamer.EmitRawText(OS.str());
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  printInstruction(MI, OS);
 | 
						|
  OutStreamer.EmitRawText(OS.str());
 | 
						|
  
 | 
						|
  // Make sure the instruction that follows TBB is 2-byte aligned.
 | 
						|
  // FIXME: Constant island pass should insert an "ALIGN" instruction instead.
 | 
						|
  if (MI->getOpcode() == ARM::t2TBB)
 | 
						|
    EmitAlignment(1);
 | 
						|
}
 | 
						|
 | 
						|
void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) {
 | 
						|
  if (Subtarget->isTargetDarwin()) {
 | 
						|
    Reloc::Model RelocM = TM.getRelocationModel();
 | 
						|
    if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) {
 | 
						|
      // Declare all the text sections up front (before the DWARF sections
 | 
						|
      // emitted by AsmPrinter::doInitialization) so the assembler will keep
 | 
						|
      // them together at the beginning of the object file.  This helps
 | 
						|
      // avoid out-of-range branches that are due a fundamental limitation of
 | 
						|
      // the way symbol offsets are encoded with the current Darwin ARM
 | 
						|
      // relocations.
 | 
						|
      const TargetLoweringObjectFileMachO &TLOFMacho = 
 | 
						|
        static_cast<const TargetLoweringObjectFileMachO &>(
 | 
						|
          getObjFileLowering());
 | 
						|
      OutStreamer.SwitchSection(TLOFMacho.getTextSection());
 | 
						|
      OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection());
 | 
						|
      OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection());
 | 
						|
      if (RelocM == Reloc::DynamicNoPIC) {
 | 
						|
        const MCSection *sect =
 | 
						|
          OutContext.getMachOSection("__TEXT", "__symbol_stub4",
 | 
						|
                                     MCSectionMachO::S_SYMBOL_STUBS,
 | 
						|
                                     12, SectionKind::getText());
 | 
						|
        OutStreamer.SwitchSection(sect);
 | 
						|
      } else {
 | 
						|
        const MCSection *sect =
 | 
						|
          OutContext.getMachOSection("__TEXT", "__picsymbolstub4",
 | 
						|
                                     MCSectionMachO::S_SYMBOL_STUBS,
 | 
						|
                                     16, SectionKind::getText());
 | 
						|
        OutStreamer.SwitchSection(sect);
 | 
						|
      }
 | 
						|
      const MCSection *StaticInitSect =
 | 
						|
        OutContext.getMachOSection("__TEXT", "__StaticInit",
 | 
						|
                                   MCSectionMachO::S_REGULAR |
 | 
						|
                                   MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
 | 
						|
                                   SectionKind::getText());
 | 
						|
      OutStreamer.SwitchSection(StaticInitSect);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Use unified assembler syntax.
 | 
						|
  OutStreamer.EmitRawText(StringRef("\t.syntax unified"));
 | 
						|
 | 
						|
  // Emit ARM Build Attributes
 | 
						|
  if (Subtarget->isTargetELF()) {
 | 
						|
    // CPU Type
 | 
						|
    std::string CPUString = Subtarget->getCPUString();
 | 
						|
    if (CPUString != "generic")
 | 
						|
      OutStreamer.EmitRawText("\t.cpu " + Twine(CPUString));
 | 
						|
 | 
						|
    // FIXME: Emit FPU type
 | 
						|
    if (Subtarget->hasVFP2())
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::VFP_arch) + ", 2");
 | 
						|
 | 
						|
    // Signal various FP modes.
 | 
						|
    if (!UnsafeFPMath) {
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_FP_denormal) + ", 1");
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_FP_exceptions) + ", 1");
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (NoInfsFPMath && NoNaNsFPMath)
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 1");
 | 
						|
    else
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 3");
 | 
						|
 | 
						|
    // 8-bytes alignment stuff.
 | 
						|
    OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                            Twine(ARMBuildAttrs::ABI_align8_needed) + ", 1");
 | 
						|
    OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                            Twine(ARMBuildAttrs::ABI_align8_preserved) + ", 1");
 | 
						|
 | 
						|
    // Hard float.  Use both S and D registers and conform to AAPCS-VFP.
 | 
						|
    if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) {
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_HardFP_use) + ", 3");
 | 
						|
      OutStreamer.EmitRawText("\t.eabi_attribute " +
 | 
						|
                              Twine(ARMBuildAttrs::ABI_VFP_args) + ", 1");
 | 
						|
    }
 | 
						|
    // FIXME: Should we signal R9 usage?
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
 | 
						|
  if (Subtarget->isTargetDarwin()) {
 | 
						|
    // All darwin targets use mach-o.
 | 
						|
    const TargetLoweringObjectFileMachO &TLOFMacho =
 | 
						|
      static_cast<const TargetLoweringObjectFileMachO &>(getObjFileLowering());
 | 
						|
    MachineModuleInfoMachO &MMIMacho =
 | 
						|
      MMI->getObjFileInfo<MachineModuleInfoMachO>();
 | 
						|
 | 
						|
    // Output non-lazy-pointers for external and common global variables.
 | 
						|
    MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
 | 
						|
 | 
						|
    if (!Stubs.empty()) {
 | 
						|
      // Switch with ".non_lazy_symbol_pointer" directive.
 | 
						|
      OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
 | 
						|
      EmitAlignment(2);
 | 
						|
      for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
 | 
						|
        // L_foo$stub:
 | 
						|
        OutStreamer.EmitLabel(Stubs[i].first);
 | 
						|
        //   .indirect_symbol _foo
 | 
						|
        MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second;
 | 
						|
        OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol);
 | 
						|
 | 
						|
        if (MCSym.getInt())
 | 
						|
          // External to current translation unit.
 | 
						|
          OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/);
 | 
						|
        else
 | 
						|
          // Internal to current translation unit.
 | 
						|
          //
 | 
						|
          // When we place the LSDA into the TEXT section, the type info pointers
 | 
						|
          // need to be indirect and pc-rel. We accomplish this by using NLPs.
 | 
						|
          // However, sometimes the types are local to the file. So we need to
 | 
						|
          // fill in the value for the NLP in those cases.
 | 
						|
          OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(),
 | 
						|
                                                        OutContext),
 | 
						|
                                4/*size*/, 0/*addrspace*/);
 | 
						|
      }
 | 
						|
 | 
						|
      Stubs.clear();
 | 
						|
      OutStreamer.AddBlankLine();
 | 
						|
    }
 | 
						|
 | 
						|
    Stubs = MMIMacho.GetHiddenGVStubList();
 | 
						|
    if (!Stubs.empty()) {
 | 
						|
      OutStreamer.SwitchSection(getObjFileLowering().getDataSection());
 | 
						|
      EmitAlignment(2);
 | 
						|
      for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
 | 
						|
        // L_foo$stub:
 | 
						|
        OutStreamer.EmitLabel(Stubs[i].first);
 | 
						|
        //   .long _foo
 | 
						|
        OutStreamer.EmitValue(MCSymbolRefExpr::
 | 
						|
                              Create(Stubs[i].second.getPointer(),
 | 
						|
                                     OutContext),
 | 
						|
                              4/*size*/, 0/*addrspace*/);
 | 
						|
      }
 | 
						|
 | 
						|
      Stubs.clear();
 | 
						|
      OutStreamer.AddBlankLine();
 | 
						|
    }
 | 
						|
 | 
						|
    // Funny Darwin hack: This flag tells the linker that no global symbols
 | 
						|
    // contain code that falls through to other global symbols (e.g. the obvious
 | 
						|
    // implementation of multiple entry points).  If this doesn't occur, the
 | 
						|
    // linker can safely perform dead code stripping.  Since LLVM never
 | 
						|
    // generates code that does this, it is always safe to set.
 | 
						|
    OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) {
 | 
						|
  ARMMCInstLower MCInstLowering(OutContext, *Mang, *this);
 | 
						|
  switch (MI->getOpcode()) {
 | 
						|
  case ARM::t2MOVi32imm:
 | 
						|
    assert(0 && "Should be lowered by thumb2it pass");
 | 
						|
  default: break;
 | 
						|
  case ARM::PICADD: { // FIXME: Remove asm string from td file.
 | 
						|
    // This is a pseudo op for a label + instruction sequence, which looks like:
 | 
						|
    // LPC0:
 | 
						|
    //     add r0, pc, r0
 | 
						|
    // This adds the address of LPC0 to r0.
 | 
						|
    
 | 
						|
    // Emit the label.
 | 
						|
    // FIXME: MOVE TO SHARED PLACE.
 | 
						|
    unsigned Id = (unsigned)MI->getOperand(2).getImm();
 | 
						|
    const char *Prefix = MAI->getPrivateGlobalPrefix();
 | 
						|
    MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix)
 | 
						|
                         + "PC" + Twine(getFunctionNumber()) + "_" + Twine(Id));
 | 
						|
    OutStreamer.EmitLabel(Label);
 | 
						|
    
 | 
						|
    
 | 
						|
    // Form and emit tha dd.
 | 
						|
    MCInst AddInst;
 | 
						|
    AddInst.setOpcode(ARM::ADDrr);
 | 
						|
    AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
 | 
						|
    AddInst.addOperand(MCOperand::CreateReg(ARM::PC));
 | 
						|
    AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
 | 
						|
    OutStreamer.EmitInstruction(AddInst);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file.
 | 
						|
    /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool
 | 
						|
    /// in the function.  The first operand is the ID# for this instruction, the
 | 
						|
    /// second is the index into the MachineConstantPool that this is, the third
 | 
						|
    /// is the size in bytes of this constant pool entry.
 | 
						|
    unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
 | 
						|
    unsigned CPIdx   = (unsigned)MI->getOperand(1).getIndex();
 | 
						|
 | 
						|
    EmitAlignment(2);
 | 
						|
    OutStreamer.EmitLabel(GetCPISymbol(LabelId));
 | 
						|
 | 
						|
    const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
 | 
						|
    if (MCPE.isMachineConstantPoolEntry())
 | 
						|
      EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
 | 
						|
    else
 | 
						|
      EmitGlobalConstant(MCPE.Val.ConstVal);
 | 
						|
    
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file.
 | 
						|
    // This is a hack that lowers as a two instruction sequence.
 | 
						|
    unsigned DstReg = MI->getOperand(0).getReg();
 | 
						|
    unsigned ImmVal = (unsigned)MI->getOperand(1).getImm();
 | 
						|
 | 
						|
    unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal);
 | 
						|
    unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal);
 | 
						|
    
 | 
						|
    {
 | 
						|
      MCInst TmpInst;
 | 
						|
      TmpInst.setOpcode(ARM::MOVi);
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1));
 | 
						|
      
 | 
						|
      // Predicate.
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
 | 
						|
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(0));          // cc_out
 | 
						|
      OutStreamer.EmitInstruction(TmpInst);
 | 
						|
    }
 | 
						|
 | 
						|
    {
 | 
						|
      MCInst TmpInst;
 | 
						|
      TmpInst.setOpcode(ARM::ORRri);
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));     // dstreg
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));     // inreg
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm
 | 
						|
      // Predicate.
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
 | 
						|
      
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(0));          // cc_out
 | 
						|
      OutStreamer.EmitInstruction(TmpInst);
 | 
						|
    }
 | 
						|
    return; 
 | 
						|
  }
 | 
						|
  case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file.
 | 
						|
    // This is a hack that lowers as a two instruction sequence.
 | 
						|
    unsigned DstReg = MI->getOperand(0).getReg();
 | 
						|
    const MachineOperand &MO = MI->getOperand(1);
 | 
						|
    MCOperand V1, V2;
 | 
						|
    if (MO.isImm()) {
 | 
						|
      unsigned ImmVal = (unsigned)MI->getOperand(1).getImm();
 | 
						|
      V1 = MCOperand::CreateImm(ImmVal & 65535);
 | 
						|
      V2 = MCOperand::CreateImm(ImmVal >> 16);
 | 
						|
    } else if (MO.isGlobal()) {
 | 
						|
      MCSymbol *Symbol = MCInstLowering.GetGlobalAddressSymbol(MO);
 | 
						|
      const MCSymbolRefExpr *SymRef1 =
 | 
						|
        MCSymbolRefExpr::Create(Symbol,
 | 
						|
                                MCSymbolRefExpr::VK_ARM_LO16, OutContext);
 | 
						|
      const MCSymbolRefExpr *SymRef2 =
 | 
						|
        MCSymbolRefExpr::Create(Symbol,
 | 
						|
                                MCSymbolRefExpr::VK_ARM_HI16, OutContext);
 | 
						|
      V1 = MCOperand::CreateExpr(SymRef1);
 | 
						|
      V2 = MCOperand::CreateExpr(SymRef2);
 | 
						|
    } else {
 | 
						|
      MI->dump();
 | 
						|
      llvm_unreachable("cannot handle this operand");
 | 
						|
    }
 | 
						|
 | 
						|
    {
 | 
						|
      MCInst TmpInst;
 | 
						|
      TmpInst.setOpcode(ARM::MOVi16);
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));         // dstreg
 | 
						|
      TmpInst.addOperand(V1); // lower16(imm)
 | 
						|
      
 | 
						|
      // Predicate.
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
 | 
						|
      
 | 
						|
      OutStreamer.EmitInstruction(TmpInst);
 | 
						|
    }
 | 
						|
    
 | 
						|
    {
 | 
						|
      MCInst TmpInst;
 | 
						|
      TmpInst.setOpcode(ARM::MOVTi16);
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));         // dstreg
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(DstReg));         // srcreg
 | 
						|
      TmpInst.addOperand(V2);   // upper16(imm)
 | 
						|
      
 | 
						|
      // Predicate.
 | 
						|
      TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm()));
 | 
						|
      TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg()));
 | 
						|
      
 | 
						|
      OutStreamer.EmitInstruction(TmpInst);
 | 
						|
    }
 | 
						|
    
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  }
 | 
						|
      
 | 
						|
  MCInst TmpInst;
 | 
						|
  MCInstLowering.Lower(MI, TmpInst);
 | 
						|
  OutStreamer.EmitInstruction(TmpInst);
 | 
						|
}
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// Target Registry Stuff
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
static MCInstPrinter *createARMMCInstPrinter(const Target &T,
 | 
						|
                                             unsigned SyntaxVariant,
 | 
						|
                                             const MCAsmInfo &MAI) {
 | 
						|
  if (SyntaxVariant == 0)
 | 
						|
    return new ARMInstPrinter(MAI, false);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
// Force static initialization.
 | 
						|
extern "C" void LLVMInitializeARMAsmPrinter() {
 | 
						|
  RegisterAsmPrinter<ARMAsmPrinter> X(TheARMTarget);
 | 
						|
  RegisterAsmPrinter<ARMAsmPrinter> Y(TheThumbTarget);
 | 
						|
 | 
						|
  TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter);
 | 
						|
  TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter);
 | 
						|
}
 | 
						|
 |