Several changes to Mips backend, experimental fp support being the most
[oota-llvm.git] / lib / Target / Mips / MipsAsmPrinter.cpp
index fdf60d92a248f1e1a54c3a11b7b15eed8b513b35..11f14e115559850c779c4ab0b1f947ccd3a965ec 100644 (file)
@@ -2,8 +2,8 @@
 //
 //                     The LLVM Compiler Infrastructure
 //
-// This file was developed by Bruno Cardoso Lopes and is distributed under the 
-// University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 #include "Mips.h"
 #include "MipsInstrInfo.h"
 #include "MipsTargetMachine.h"
+#include "MipsMachineFunction.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Module.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/Target/TargetAsmInfo.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Mangler.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/MathExtras.h"
 #include <cctype>
@@ -48,9 +52,28 @@ namespace {
       return "Mips Assembly Printer";
     }
 
+    enum SetDirectiveFlags {
+      REORDER,      // enables instruction reordering.
+      NOREORDER,    // disables instruction reordering.
+      MACRO,        // enables GAS macros.
+      NOMACRO       // disables GAS macros.
+    };
+
     void printOperand(const MachineInstr *MI, int opNum);
     void printMemOperand(const MachineInstr *MI, int opNum, 
                          const char *Modifier = 0);
+    void printFCCOperand(const MachineInstr *MI, int opNum, 
+                         const char *Modifier = 0);
+
+    unsigned int getSavedRegsBitmask(bool isFloat, MachineFunction &MF);
+    void printHex32(unsigned int Value);
+
+    void emitFunctionStart(MachineFunction &MF);
+    void emitFunctionEnd(MachineFunction &MF);
+    void emitFrameDirective(MachineFunction &MF);
+    void emitMaskDirective(MachineFunction &MF);
+    void emitFMaskDirective(MachineFunction &MF);
+    void emitSetDirective(SetDirectiveFlags Flag);
 
     bool printInstruction(const MachineInstr *MI);  // autogenerated.
     bool runOnMachineFunction(MachineFunction &F);
@@ -71,6 +94,183 @@ FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o,
   return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo());
 }
 
+//===----------------------------------------------------------------------===//
+//
+//  Mips Asm Directives
+//
+//  -- Frame directive "frame Stackpointer, Stacksize, RARegister"
+//  Describe the stack frame.
+//
+//  -- Mask directives "(f)mask  bitmask, offset" 
+//  Tells the assembler which registers are saved and where.
+//  bitmask - contain a little endian bitset indicating which registers are 
+//            saved on function prologue (e.g. with a 0x80000000 mask, the 
+//            assembler knows the register 31 (RA) is saved at prologue.
+//  offset  - the position before stack pointer subtraction indicating where 
+//            the first saved register on prologue is located. (e.g. with a
+//
+//  Consider the following function prologue:
+//
+//    .frame  $fp,48,$ra
+//    .mask   0xc0000000,-8
+//       addiu $sp, $sp, -48
+//       sw $ra, 40($sp)
+//       sw $fp, 36($sp)
+//
+//    With a 0xc0000000 mask, the assembler knows the register 31 (RA) and 
+//    30 (FP) are saved at prologue. As the save order on prologue is from 
+//    left to right, RA is saved first. A -8 offset means that after the 
+//    stack pointer subtration, the first register in the mask (RA) will be
+//    saved at address 48-8=40.
+//
+//===----------------------------------------------------------------------===//
+
+/// Mask directive for GPR
+void MipsAsmPrinter::
+emitMaskDirective(MachineFunction &MF)
+{
+  MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
+
+  int StackSize = MF.getFrameInfo()->getStackSize();
+  int Offset    = (!MipsFI->getTopSavedRegOffset()) ? 0 : 
+                  (-(StackSize-MipsFI->getTopSavedRegOffset()));
+             
+  #ifndef NDEBUG
+  DOUT << "--> emitMaskDirective" << "\n";
+  DOUT << "StackSize :  " << StackSize << "\n";
+  DOUT << "getTopSavedReg : " << MipsFI->getTopSavedRegOffset() << "\n";
+  DOUT << "Offset : " << Offset << "\n\n";
+  #endif
+
+  unsigned int Bitmask = getSavedRegsBitmask(false, MF);
+  O << "\t.mask \t"; 
+  printHex32(Bitmask);
+  O << "," << Offset << "\n";
+}
+
+/// TODO: Mask Directive for Float Point
+void MipsAsmPrinter::
+emitFMaskDirective(MachineFunction &MF)
+{
+  unsigned int Bitmask = getSavedRegsBitmask(true, MF);
+
+  O << "\t.fmask\t";
+  printHex32(Bitmask);
+  O << ",0" << "\n";
+}
+
+/// Frame Directive
+void MipsAsmPrinter::
+emitFrameDirective(MachineFunction &MF)
+{
+  const TargetRegisterInfo &RI = *TM.getRegisterInfo();
+
+  unsigned stackReg  = RI.getFrameRegister(MF);
+  unsigned returnReg = RI.getRARegister();
+  unsigned stackSize = MF.getFrameInfo()->getStackSize();
+
+
+  O << "\t.frame\t" << "$" << LowercaseString(RI.get(stackReg).AsmName)
+                    << "," << stackSize << ","
+                    << "$" << LowercaseString(RI.get(returnReg).AsmName)
+                    << "\n";
+}
+
+/// Emit Set directives.
+void MipsAsmPrinter::
+emitSetDirective(SetDirectiveFlags Flag) 
+{  
+  O << "\t.set\t";
+  switch(Flag) {
+      case REORDER:   O << "reorder" << "\n"; break;
+      case NOREORDER: O << "noreorder" << "\n"; break;
+      case MACRO:     O << "macro" << "\n"; break;
+      case NOMACRO:   O << "nomacro" << "\n"; break;
+      default: break;
+  }
+}  
+
+// Create a bitmask with all callee saved registers for CPU
+// or Float Point registers. For CPU registers consider RA,
+// GP and FP for saving if necessary.
+unsigned int MipsAsmPrinter::
+getSavedRegsBitmask(bool isFloat, MachineFunction &MF)
+{
+  const TargetRegisterInfo &RI = *TM.getRegisterInfo();
+             
+  // Float Point Registers, TODO
+  if (isFloat)
+    return 0;
+
+  // CPU Registers
+  unsigned int Bitmask = 0;
+
+  MachineFrameInfo *MFI = MF.getFrameInfo();
+  const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+  for (unsigned i = 0, e = CSI.size(); i != e; ++i)
+    Bitmask |= (1 << MipsRegisterInfo::getRegisterNumbering(CSI[i].getReg()));
+
+  if (RI.hasFP(MF)) 
+    Bitmask |= (1 << MipsRegisterInfo::
+                getRegisterNumbering(RI.getFrameRegister(MF)));
+  
+  if (MF.getFrameInfo()->hasCalls()) 
+    Bitmask |= (1 << MipsRegisterInfo::
+                getRegisterNumbering(RI.getRARegister()));
+
+  return Bitmask;
+}
+
+// Print a 32 bit hex number with all numbers.
+void MipsAsmPrinter::
+printHex32(unsigned int Value) 
+{
+  O << "0x" << std::hex;
+  for (int i = 7; i >= 0; i--) 
+    O << std::hex << ( (Value & (0xF << (i*4))) >> (i*4) );
+  O << std::dec;
+}
+
+/// Emit the directives used by GAS on the start of functions
+void MipsAsmPrinter::
+emitFunctionStart(MachineFunction &MF)
+{
+  // Print out the label for the function.
+  const Function *F = MF.getFunction();
+  SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
+
+  // 2 bits aligned
+  EmitAlignment(2, F);
+
+  O << "\t.globl\t"  << CurrentFnName << "\n";
+  O << "\t.ent\t"    << CurrentFnName << "\n";
+  O << "\t.type\t"   << CurrentFnName << ", @function\n";
+  O << CurrentFnName << ":\n";
+
+  emitFrameDirective(MF);
+  emitMaskDirective(MF);
+  emitFMaskDirective(MF);
+
+  if (TM.getRelocationModel() == Reloc::Static) {
+    emitSetDirective(NOREORDER);
+    emitSetDirective(NOMACRO);
+  }
+
+  O << "\n";
+}
+
+/// Emit the directives used by GAS on the end of functions
+void MipsAsmPrinter::
+emitFunctionEnd(MachineFunction &MF) 
+{
+  if (TM.getRelocationModel() == Reloc::Static) {
+    emitSetDirective(MACRO);
+    emitSetDirective(REORDER);
+  }    
+
+  O << "\t.end\t" << CurrentFnName << "\n";
+}
+
 /// runOnMachineFunction - This uses the printMachineInstruction()
 /// method to print assembly for each instruction.
 bool MipsAsmPrinter::
@@ -81,25 +281,16 @@ runOnMachineFunction(MachineFunction &MF)
   // Print out constants referenced by the function
   EmitConstantPool(MF.getConstantPool());
 
+  // Print out jump tables referenced by the function
+  EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
+
   O << "\n\n";
 
   // What's my mangled name?
   CurrentFnName = Mang->getValueName(MF.getFunction());
 
-  // Print out the label for the function.
-  const Function *F = MF.getFunction();
-  SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
-
-  // On Mips GAS if .align #n is present, #n means the number of bits 
-  // to be cleared to align. So, if we want 4 byte alignment, we must 
-  // have .align 2
-  // TODO:
-  //  add gas ".mask" and ".fmask"
-  EmitAlignment(1, F);
-  O << "\t.globl\t" << CurrentFnName << "\n";
-  O << "\t.ent\t" << CurrentFnName << "\n";
-  O << "\t.type\t"  << CurrentFnName << ", @function\n";
-  O << CurrentFnName << ":\n";
+  // Emit the function start directives
+  emitFunctionStart(MF);
 
   // Print out code for the function.
   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
@@ -107,21 +298,23 @@ runOnMachineFunction(MachineFunction &MF)
 
     // Print a label for the basic block.
     if (I != MF.begin()) {
-      printBasicBlockLabel(I, true);
+      printBasicBlockLabel(I, true, true);
       O << '\n';
     }
 
     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
          II != E; ++II) {
       // Print the assembly for the instruction.
-      O << "\t";
       printInstruction(II);
       ++EmittedInsts;
     }
+
+    // Each Basic Block is separated by a newline
+    O << '\n';
   }
 
-  // close function with asm directive
-  O << "\t.end\t" << CurrentFnName << "\n";
+  // Emit function end directives
+  emitFunctionEnd(MF);
 
   // We didn't modify anything.
   return false;
@@ -131,39 +324,63 @@ void MipsAsmPrinter::
 printOperand(const MachineInstr *MI, int opNum) 
 {
   const MachineOperand &MO = MI->getOperand(opNum);
-  const MRegisterInfo  &RI = *TM.getRegisterInfo();
-  bool  closeP=false;
-
-  // %hi and %lo used on mips gas to break large constants
+  const TargetRegisterInfo  &RI = *TM.getRegisterInfo();
+  bool closeP = false;
+  bool isPIC = (TM.getRelocationModel() == Reloc::PIC_);
+  bool isCodeLarge = (TM.getCodeModel() == CodeModel::Large);
+
+  // %hi and %lo used on mips gas to load global addresses on
+  // static code. %got is used to load global addresses when 
+  // using PIC_. %call16 is used to load direct call targets
+  // on PIC_ and small code size. %call_lo and %call_hi load 
+  // direct call targets on PIC_ and large code size.
   if (MI->getOpcode() == Mips::LUi && !MO.isRegister() 
       && !MO.isImmediate()) {
-    O << "%hi(";
+    if ((isPIC) && (isCodeLarge))
+      O << "%call_hi(";
+    else
+      O << "%hi(";
     closeP = true;
   } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister() 
              && !MO.isImmediate()) {
     O << "%lo(";
     closeP = true;
+  } else if ((isPIC) && (MI->getOpcode() == Mips::LW)
+             && (!MO.isRegister()) && (!MO.isImmediate())) {
+    const MachineOperand &firstMO = MI->getOperand(opNum-1);
+    const MachineOperand &lastMO  = MI->getOperand(opNum+1);
+    if ((firstMO.isRegister()) && (lastMO.isRegister())) {
+      if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() == Mips::GP) 
+          && (!isCodeLarge))
+        O << "%call16(";
+      else if ((firstMO.getReg() != Mips::T9) && (lastMO.getReg() == Mips::GP))
+        O << "%got(";
+      else if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() != Mips::GP) 
+               && (isCodeLarge))
+        O << "%call_lo(";
+      closeP = true;
+    }
   }
  
   switch (MO.getType()) 
   {
     case MachineOperand::MO_Register:
-      if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
-        O << "$" << LowercaseString (RI.get(MO.getReg()).Name);
+      if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
+        O << "$" << LowercaseString (RI.get(MO.getReg()).AsmName);
       else
         O << "$" << MO.getReg();
       break;
 
     case MachineOperand::MO_Immediate:
       if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) || 
-          (MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi))
-        O << (unsigned int)MO.getImmedValue();
+          (MI->getOpcode() == Mips::LUi)   || (MI->getOpcode() == Mips::ANDi))
+        O << (unsigned short int)MO.getImm();
       else
-        O << (int)MO.getImmedValue();
+        O << (short int)MO.getImm();
       break;
 
     case MachineOperand::MO_MachineBasicBlock:
-      printBasicBlockLabel(MO.getMachineBasicBlock());
+      printBasicBlockLabel(MO.getMBB());
       return;
 
     case MachineOperand::MO_GlobalAddress:
@@ -174,9 +391,15 @@ printOperand(const MachineInstr *MI, int opNum)
       O << MO.getSymbolName();
       break;
 
+    case MachineOperand::MO_JumpTableIndex:
+      O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
+      << '_' << MO.getIndex();
+      break;
+
+    // FIXME: Verify correct
     case MachineOperand::MO_ConstantPoolIndex:
       O << TAI->getPrivateGlobalPrefix() << "CPI"
-        << getFunctionNumber() << "_" << MO.getConstantPoolIndex();
+        << getFunctionNumber() << "_" << MO.getIndex();
       break;
   
     default:
@@ -189,15 +412,31 @@ printOperand(const MachineInstr *MI, int opNum)
 void MipsAsmPrinter::
 printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) 
 {
-  // lw/sw $reg, MemOperand
-  // will turn into :
-  // lw/sw $reg, imm($reg)
+  // when using stack locations for not load/store instructions
+  // print the same way as all normal 3 operand instructions.
+  if (Modifier && !strcmp(Modifier, "stackloc")) {
+    printOperand(MI, opNum+1);
+    O << ", ";
+    printOperand(MI, opNum);
+    return;
+  }
+
+  // Load/Store memory operands -- imm($reg) 
+  // If PIC target the target is loaded as the 
+  // pattern lw $25,%call16($28)
   printOperand(MI, opNum);
   O << "(";
   printOperand(MI, opNum+1);
   O << ")";
 }
 
+void MipsAsmPrinter::
+printFCCOperand(const MachineInstr *MI, int opNum, const char *Modifier) 
+{
+  const MachineOperand& MO = MI->getOperand(opNum);
+  O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); 
+}
+
 bool MipsAsmPrinter::
 doInitialization(Module &M) 
 {
@@ -225,27 +464,40 @@ doFinalization(Module &M)
       O << "\n\n";
       std::string name = Mang->getValueName(I);
       Constant *C      = I->getInitializer();
-      unsigned Size    = TD->getTypeSize(C->getType());
-      unsigned Align   = TD->getPrefTypeAlignment(C->getType());
+      unsigned Size    = TD->getABITypeSize(C->getType());
+      unsigned Align   = TD->getPreferredAlignmentLog(I);
 
+      // Is this correct ?
       if (C->isNullValue() && (I->hasLinkOnceLinkage() || 
-        I->hasInternalLinkage() || I->hasWeakLinkage() 
-        /* FIXME: Verify correct */)) {
-
-        SwitchToDataSection(".data", I);
-        if (I->hasInternalLinkage())
-          O << "\t.local " << name << "\n";
-
-        O << "\t.comm " << name << "," 
-          << TD->getTypeSize(C->getType()) 
-          << "," << Align << "\n";
+          I->hasInternalLinkage() || I->hasWeakLinkage() ||
+          I->hasCommonLinkage()))
+      {
+        if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
+
+        if (!NoZerosInBSS && TAI->getBSSSection())
+          SwitchToDataSection(TAI->getBSSSection(), I);
+        else
+          SwitchToDataSection(TAI->getDataSection(), I);
+
+        if (I->hasInternalLinkage()) {
+          if (TAI->getLCOMMDirective())
+            O << TAI->getLCOMMDirective() << name << "," << Size;
+          else            
+            O << "\t.local\t" << name << "\n";
+        } else {
+          O << TAI->getCOMMDirective() << name << "," << Size;
+          // The .comm alignment in bytes.
+          if (TAI->getCOMMDirectiveTakesAlignment())
+            O << "," << (1 << Align);
+        }
 
       } else {
 
         switch (I->getLinkage()) 
         {
           case GlobalValue::LinkOnceLinkage:
-          case GlobalValue::WeakLinkage:   
+          case GlobalValue::CommonLinkage:
+          case GlobalValue::WeakLinkage:
             // FIXME: Verify correct for weak.
             // Nonnull linkonce -> weak
             O << "\t.weak " << name << "\n";
@@ -259,28 +511,42 @@ doFinalization(Module &M)
             // something.  For now, just emit them as external.
           case GlobalValue::ExternalLinkage:
             // If external or appending, declare as a global symbol
-            O << "\t.globl " << name << "\n";
+            O << TAI->getGlobalDirective() << name << "\n";
+            // Fall Through
           case GlobalValue::InternalLinkage:
-            if (C->isNullValue())
-              SwitchToDataSection(".bss", I);
-            else
-              SwitchToDataSection(".data", I);
+            // FIXME: special handling for ".ctors" & ".dtors" sections
+            if (I->hasSection() && (I->getSection() == ".ctors" ||
+                I->getSection() == ".dtors")) {
+              std::string SectionName = ".section " + I->getSection();
+              SectionName += ",\"aw\",%progbits";
+              SwitchToDataSection(SectionName.c_str());
+            } else {
+              if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection())
+                SwitchToDataSection(TAI->getBSSSection(), I);
+              else if (!I->isConstant())
+                SwitchToDataSection(TAI->getDataSection(), I);
+              else {
+                // Read-only data.
+                if (TAI->getReadOnlySection())
+                  SwitchToDataSection(TAI->getReadOnlySection(), I);
+                else
+                  SwitchToDataSection(TAI->getDataSection(), I);
+              }
+            }
             break;
           case GlobalValue::GhostLinkage:
-            cerr << "Should not have any" 
-                 << "unmaterialized functions!\n";
+            cerr << "Should not have any unmaterialized functions!\n";
             abort();
           case GlobalValue::DLLImportLinkage:
-            cerr << "DLLImport linkage is" 
-                 << "not supported by this target!\n";
+            cerr << "DLLImport linkage is not supported by this target!\n";
             abort();
           case GlobalValue::DLLExportLinkage:
-            cerr << "DLLExport linkage is" 
-                 << "not supported by this target!\n";
+            cerr << "DLLExport linkage is not supported by this target!\n";
             abort();
           default:
             assert(0 && "Unknown linkage type!");          
         }
+
         O << "\t.align " << Align << "\n";
         O << "\t.type " << name << ",@object\n";
         O << "\t.size " << name << "," << Size << "\n";
@@ -289,6 +555,7 @@ doFinalization(Module &M)
     }
   }
 
-  AsmPrinter::doFinalization(M);
-  return false; // success
+  O << "\n";
+
+  return AsmPrinter::doFinalization(M);
 }