Home | History | Annotate | Download | only in CellSPU
      1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -----===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file contains a printer that converts from our internal representation
     11 // of machine-dependent LLVM code to Cell SPU assembly language. This printer
     12 // is the output mechanism used by `llc'.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #define DEBUG_TYPE "asmprinter"
     17 #include "SPU.h"
     18 #include "SPUTargetMachine.h"
     19 #include "llvm/Constants.h"
     20 #include "llvm/DerivedTypes.h"
     21 #include "llvm/Module.h"
     22 #include "llvm/CodeGen/AsmPrinter.h"
     23 #include "llvm/CodeGen/MachineModuleInfo.h"
     24 #include "llvm/MC/MCStreamer.h"
     25 #include "llvm/MC/MCAsmInfo.h"
     26 #include "llvm/MC/MCSymbol.h"
     27 #include "llvm/Target/Mangler.h"
     28 #include "llvm/Target/TargetLoweringObjectFile.h"
     29 #include "llvm/Target/TargetInstrInfo.h"
     30 #include "llvm/Target/TargetOptions.h"
     31 #include "llvm/Target/TargetRegisterInfo.h"
     32 #include "llvm/ADT/SmallString.h"
     33 #include "llvm/ADT/StringExtras.h"
     34 #include "llvm/Support/ErrorHandling.h"
     35 #include "llvm/Support/TargetRegistry.h"
     36 #include "llvm/Support/raw_ostream.h"
     37 using namespace llvm;
     38 
     39 namespace {
     40   class SPUAsmPrinter : public AsmPrinter {
     41   public:
     42     explicit SPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) :
     43       AsmPrinter(TM, Streamer) {}
     44 
     45     virtual const char *getPassName() const {
     46       return "STI CBEA SPU Assembly Printer";
     47     }
     48 
     49     /// printInstruction - This method is automatically generated by tablegen
     50     /// from the instruction set description.
     51     void printInstruction(const MachineInstr *MI, raw_ostream &OS);
     52     static const char *getRegisterName(unsigned RegNo);
     53 
     54 
     55     void EmitInstruction(const MachineInstr *MI) {
     56       SmallString<128> Str;
     57       raw_svector_ostream OS(Str);
     58       printInstruction(MI, OS);
     59       OutStreamer.EmitRawText(OS.str());
     60     }
     61     void printOp(const MachineOperand &MO, raw_ostream &OS);
     62 
     63     void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
     64       const MachineOperand &MO = MI->getOperand(OpNo);
     65       if (MO.isReg()) {
     66         O << getRegisterName(MO.getReg());
     67       } else if (MO.isImm()) {
     68         O << MO.getImm();
     69       } else {
     70         printOp(MO, O);
     71       }
     72     }
     73 
     74     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
     75                          unsigned AsmVariant, const char *ExtraCode,
     76                          raw_ostream &O);
     77     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
     78                                unsigned AsmVariant, const char *ExtraCode,
     79                                raw_ostream &O);
     80 
     81 
     82     void
     83     printU7ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
     84     {
     85       unsigned int value = MI->getOperand(OpNo).getImm();
     86       assert(value < (1 << 8) && "Invalid u7 argument");
     87       O << value;
     88     }
     89 
     90     void
     91     printShufAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
     92     {
     93       char value = MI->getOperand(OpNo).getImm();
     94       O << (int) value;
     95       O << "(";
     96       printOperand(MI, OpNo+1, O);
     97       O << ")";
     98     }
     99 
    100     void
    101     printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    102     {
    103       O << (short) MI->getOperand(OpNo).getImm();
    104     }
    105 
    106     void
    107     printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    108     {
    109       O << (unsigned short)MI->getOperand(OpNo).getImm();
    110     }
    111 
    112     void
    113     printMemRegReg(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    114       // When used as the base register, r0 reads constant zero rather than
    115       // the value contained in the register.  For this reason, the darwin
    116       // assembler requires that we print r0 as 0 (no r) when used as the base.
    117       const MachineOperand &MO = MI->getOperand(OpNo);
    118       O << getRegisterName(MO.getReg()) << ", ";
    119       printOperand(MI, OpNo+1, O);
    120     }
    121 
    122     void
    123     printU18ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    124     {
    125       unsigned int value = MI->getOperand(OpNo).getImm();
    126       assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
    127       O << value;
    128     }
    129 
    130     void
    131     printS10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    132     {
    133       short value = MI->getOperand(OpNo).getImm();
    134       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
    135              && "Invalid s10 argument");
    136       O << value;
    137     }
    138 
    139     void
    140     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    141     {
    142       short value = MI->getOperand(OpNo).getImm();
    143       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
    144       O << value;
    145     }
    146 
    147     void
    148     printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    149     {
    150       assert(MI->getOperand(OpNo).isImm() &&
    151              "printDFormAddr first operand is not immediate");
    152       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
    153       int16_t value16 = int16_t(value);
    154       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
    155              && "Invalid dform s10 offset argument");
    156       O << (value16 & ~0xf) << "(";
    157       printOperand(MI, OpNo+1, O);
    158       O << ")";
    159     }
    160 
    161     void
    162     printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    163     {
    164       /* Note: operand 1 is an offset or symbol name. */
    165       if (MI->getOperand(OpNo).isImm()) {
    166         printS16ImmOperand(MI, OpNo, O);
    167       } else {
    168         printOp(MI->getOperand(OpNo), O);
    169         if (MI->getOperand(OpNo+1).isImm()) {
    170           int displ = int(MI->getOperand(OpNo+1).getImm());
    171           if (displ > 0)
    172             O << "+" << displ;
    173           else if (displ < 0)
    174             O << displ;
    175         }
    176       }
    177     }
    178 
    179     void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    180       printOp(MI->getOperand(OpNo), O);
    181     }
    182 
    183     void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    184       printOp(MI->getOperand(OpNo), O);
    185     }
    186 
    187     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    188       // Used to generate a ".-<target>", but it turns out that the assembler
    189       // really wants the target.
    190       //
    191       // N.B.: This operand is used for call targets. Branch hints are another
    192       // animal entirely.
    193       printOp(MI->getOperand(OpNo), O);
    194     }
    195 
    196     void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    197       if (MI->getOperand(OpNo).isImm()) {
    198         printS16ImmOperand(MI, OpNo, O);
    199       } else {
    200         printOp(MI->getOperand(OpNo), O);
    201         O << "@h";
    202       }
    203     }
    204 
    205     void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    206       if (MI->getOperand(OpNo).isImm()) {
    207         printS16ImmOperand(MI, OpNo, O);
    208       } else {
    209         printOp(MI->getOperand(OpNo), O);
    210         O << "@l";
    211       }
    212     }
    213 
    214     /// Print local store address
    215     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    216       printOp(MI->getOperand(OpNo), O);
    217     }
    218 
    219     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo,
    220                           raw_ostream &O) {
    221       if (MI->getOperand(OpNo).isImm()) {
    222         int value = (int) MI->getOperand(OpNo).getImm();
    223         assert((value >= 0 && value < 16)
    224                && "Invalid negated immediate rotate 7-bit argument");
    225         O << -value;
    226       } else {
    227         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
    228       }
    229     }
    230 
    231     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){
    232       assert(MI->getOperand(OpNo).isImm() &&
    233              "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
    234       int value = (int) MI->getOperand(OpNo).getImm();
    235       assert((value >= 0 && value <= 32)
    236              && "Invalid negated immediate rotate 7-bit argument");
    237       O << -value;
    238     }
    239   };
    240 } // end of anonymous namespace
    241 
    242 // Include the auto-generated portion of the assembly writer
    243 #include "SPUGenAsmWriter.inc"
    244 
    245 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
    246   switch (MO.getType()) {
    247   case MachineOperand::MO_Immediate:
    248     report_fatal_error("printOp() does not handle immediate values");
    249 
    250   case MachineOperand::MO_MachineBasicBlock:
    251     O << *MO.getMBB()->getSymbol();
    252     return;
    253   case MachineOperand::MO_JumpTableIndex:
    254     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
    255       << '_' << MO.getIndex();
    256     return;
    257   case MachineOperand::MO_ConstantPoolIndex:
    258     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
    259       << '_' << MO.getIndex();
    260     return;
    261   case MachineOperand::MO_ExternalSymbol:
    262     // Computing the address of an external symbol, not calling it.
    263     if (TM.getRelocationModel() != Reloc::Static) {
    264       O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
    265         << "$non_lazy_ptr";
    266       return;
    267     }
    268     O << *GetExternalSymbolSymbol(MO.getSymbolName());
    269     return;
    270   case MachineOperand::MO_GlobalAddress:
    271     // External or weakly linked global variables need non-lazily-resolved
    272     // stubs
    273     if (TM.getRelocationModel() != Reloc::Static) {
    274       const GlobalValue *GV = MO.getGlobal();
    275       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
    276             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
    277         O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
    278         return;
    279       }
    280     }
    281     O << *Mang->getSymbol(MO.getGlobal());
    282     return;
    283   case MachineOperand::MO_MCSymbol:
    284     O << *(MO.getMCSymbol());
    285     return;
    286   default:
    287     O << "<unknown operand type: " << MO.getType() << ">";
    288     return;
    289   }
    290 }
    291 
    292 /// PrintAsmOperand - Print out an operand for an inline asm expression.
    293 ///
    294 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
    295                                     unsigned AsmVariant,
    296                                     const char *ExtraCode, raw_ostream &O) {
    297   // Does this asm operand have a single letter operand modifier?
    298   if (ExtraCode && ExtraCode[0]) {
    299     if (ExtraCode[1] != 0) return true; // Unknown modifier.
    300 
    301     switch (ExtraCode[0]) {
    302     default:
    303       // See if this is a generic print operand
    304       return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
    305     case 'L': // Write second word of DImode reference.
    306       // Verify that this operand has two consecutive registers.
    307       if (!MI->getOperand(OpNo).isReg() ||
    308           OpNo+1 == MI->getNumOperands() ||
    309           !MI->getOperand(OpNo+1).isReg())
    310         return true;
    311       ++OpNo;   // Return the high-part.
    312       break;
    313     }
    314   }
    315 
    316   printOperand(MI, OpNo, O);
    317   return false;
    318 }
    319 
    320 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
    321                                           unsigned OpNo, unsigned AsmVariant,
    322                                           const char *ExtraCode,
    323                                           raw_ostream &O) {
    324   if (ExtraCode && ExtraCode[0])
    325     return true; // Unknown modifier.
    326   printMemRegReg(MI, OpNo, O);
    327   return false;
    328 }
    329 
    330 // Force static initialization.
    331 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
    332   RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget);
    333 }
    334