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 = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
    134                              >> 16);
    135       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
    136              && "Invalid s10 argument");
    137       O << value;
    138     }
    139 
    140     void
    141     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    142     {
    143       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
    144                              >> 16);
    145       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
    146       O << value;
    147     }
    148 
    149     void
    150     printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    151     {
    152       assert(MI->getOperand(OpNo).isImm() &&
    153              "printDFormAddr first operand is not immediate");
    154       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
    155       int16_t value16 = int16_t(value);
    156       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
    157              && "Invalid dform s10 offset argument");
    158       O << (value16 & ~0xf) << "(";
    159       printOperand(MI, OpNo+1, O);
    160       O << ")";
    161     }
    162 
    163     void
    164     printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
    165     {
    166       /* Note: operand 1 is an offset or symbol name. */
    167       if (MI->getOperand(OpNo).isImm()) {
    168         printS16ImmOperand(MI, OpNo, O);
    169       } else {
    170         printOp(MI->getOperand(OpNo), O);
    171         if (MI->getOperand(OpNo+1).isImm()) {
    172           int displ = int(MI->getOperand(OpNo+1).getImm());
    173           if (displ > 0)
    174             O << "+" << displ;
    175           else if (displ < 0)
    176             O << displ;
    177         }
    178       }
    179     }
    180 
    181     void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    182       printOp(MI->getOperand(OpNo), O);
    183     }
    184 
    185     void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    186       printOp(MI->getOperand(OpNo), O);
    187     }
    188 
    189     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    190       // Used to generate a ".-<target>", but it turns out that the assembler
    191       // really wants the target.
    192       //
    193       // N.B.: This operand is used for call targets. Branch hints are another
    194       // animal entirely.
    195       printOp(MI->getOperand(OpNo), O);
    196     }
    197 
    198     void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    199       if (MI->getOperand(OpNo).isImm()) {
    200         printS16ImmOperand(MI, OpNo, O);
    201       } else {
    202         printOp(MI->getOperand(OpNo), O);
    203         O << "@h";
    204       }
    205     }
    206 
    207     void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    208       if (MI->getOperand(OpNo).isImm()) {
    209         printS16ImmOperand(MI, OpNo, O);
    210       } else {
    211         printOp(MI->getOperand(OpNo), O);
    212         O << "@l";
    213       }
    214     }
    215 
    216     /// Print local store address
    217     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
    218       printOp(MI->getOperand(OpNo), O);
    219     }
    220 
    221     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo,
    222                           raw_ostream &O) {
    223       if (MI->getOperand(OpNo).isImm()) {
    224         int value = (int) MI->getOperand(OpNo).getImm();
    225         assert((value >= 0 && value < 16)
    226                && "Invalid negated immediate rotate 7-bit argument");
    227         O << -value;
    228       } else {
    229         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
    230       }
    231     }
    232 
    233     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){
    234       assert(MI->getOperand(OpNo).isImm() &&
    235              "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
    236       int value = (int) MI->getOperand(OpNo).getImm();
    237       assert((value >= 0 && value <= 32)
    238              && "Invalid negated immediate rotate 7-bit argument");
    239       O << -value;
    240     }
    241   };
    242 } // end of anonymous namespace
    243 
    244 // Include the auto-generated portion of the assembly writer
    245 #include "SPUGenAsmWriter.inc"
    246 
    247 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
    248   switch (MO.getType()) {
    249   case MachineOperand::MO_Immediate:
    250     report_fatal_error("printOp() does not handle immediate values");
    251 
    252   case MachineOperand::MO_MachineBasicBlock:
    253     O << *MO.getMBB()->getSymbol();
    254     return;
    255   case MachineOperand::MO_JumpTableIndex:
    256     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
    257       << '_' << MO.getIndex();
    258     return;
    259   case MachineOperand::MO_ConstantPoolIndex:
    260     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
    261       << '_' << MO.getIndex();
    262     return;
    263   case MachineOperand::MO_ExternalSymbol:
    264     // Computing the address of an external symbol, not calling it.
    265     if (TM.getRelocationModel() != Reloc::Static) {
    266       O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
    267         << "$non_lazy_ptr";
    268       return;
    269     }
    270     O << *GetExternalSymbolSymbol(MO.getSymbolName());
    271     return;
    272   case MachineOperand::MO_GlobalAddress:
    273     // External or weakly linked global variables need non-lazily-resolved
    274     // stubs
    275     if (TM.getRelocationModel() != Reloc::Static) {
    276       const GlobalValue *GV = MO.getGlobal();
    277       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
    278             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
    279         O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
    280         return;
    281       }
    282     }
    283     O << *Mang->getSymbol(MO.getGlobal());
    284     return;
    285   case MachineOperand::MO_MCSymbol:
    286     O << *(MO.getMCSymbol());
    287     return;
    288   default:
    289     O << "<unknown operand type: " << MO.getType() << ">";
    290     return;
    291   }
    292 }
    293 
    294 /// PrintAsmOperand - Print out an operand for an inline asm expression.
    295 ///
    296 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
    297                                     unsigned AsmVariant,
    298                                     const char *ExtraCode, raw_ostream &O) {
    299   // Does this asm operand have a single letter operand modifier?
    300   if (ExtraCode && ExtraCode[0]) {
    301     if (ExtraCode[1] != 0) return true; // Unknown modifier.
    302 
    303     switch (ExtraCode[0]) {
    304     default: return true;  // Unknown modifier.
    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