Fixed call stack alignment. Improved AsmPrinter alignment issues.
[oota-llvm.git] / lib / Target / Mips / MipsAsmPrinter.cpp
index 6ae6104cb2960dff635e0faa673354e82740c240..d37d08748300495f10f4b9f36178387b78393f3a 100644 (file)
@@ -15,6 +15,7 @@
 #define DEBUG_TYPE "mips-asm-printer"
 
 #include "Mips.h"
+#include "MipsSubtarget.h"
 #include "MipsInstrInfo.h"
 #include "MipsTargetMachine.h"
 #include "MipsMachineFunction.h"
@@ -32,7 +33,6 @@
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Support/Mangler.h"
 #include "llvm/ADT/Statistic.h"
-#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/CommandLine.h"
@@ -45,35 +45,35 @@ STATISTIC(EmittedInsts, "Number of machine instrs printed");
 
 namespace {
   struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter {
+
+    const MipsSubtarget *Subtarget;
+
     MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM, 
                    const TargetAsmInfo *T): 
-                   AsmPrinter(O, TM, T) {}
+                   AsmPrinter(O, TM, T) {
+      Subtarget = &TM.getSubtarget<MipsSubtarget>();
+    }
 
     virtual const char *getPassName() const {
       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);
 
+    const char *emitCurrentABIString(void);
     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);
     bool doInitialization(Module &M);
@@ -124,6 +124,10 @@ FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o,
 //
 //===----------------------------------------------------------------------===//
 
+//===----------------------------------------------------------------------===//
+// Mask directives
+//===----------------------------------------------------------------------===//
+
 /// Mask directive for GPR
 void MipsAsmPrinter::
 emitMaskDirective(MachineFunction &MF)
@@ -147,7 +151,7 @@ emitMaskDirective(MachineFunction &MF)
   O << "," << Offset << "\n";
 }
 
-/// TODO: Mask Directive for Float Point
+/// TODO: Mask Directive for Floating Point
 void MipsAsmPrinter::
 emitFMaskDirective(MachineFunction &MF)
 {
@@ -158,46 +162,15 @@ emitFMaskDirective(MachineFunction &MF)
   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,
+// or Floating 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
+  // Floating Point Registers, TODO
   if (isFloat)
     return 0;
 
@@ -230,6 +203,44 @@ printHex32(unsigned int Value)
   O << std::dec;
 }
 
+//===----------------------------------------------------------------------===//
+// Frame and Set directives
+//===----------------------------------------------------------------------===//
+
+/// 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.
+const char * MipsAsmPrinter::
+emitCurrentABIString(void) 
+{  
+  switch(Subtarget->getTargetABI()) {
+    case MipsSubtarget::O32:  return "abi32";  
+    case MipsSubtarget::O64:  return "abiO64";
+    case MipsSubtarget::N32:  return "abiN32";
+    case MipsSubtarget::N64:  return "abi64";
+    case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64
+    default: break;
+  }
+
+  assert(0 && "Unknown Mips ABI");
+  return NULL;
+}  
+
 /// Emit the directives used by GAS on the start of functions
 void MipsAsmPrinter::
 emitFunctionStart(MachineFunction &MF)
@@ -243,18 +254,16 @@ emitFunctionStart(MachineFunction &MF)
 
   O << "\t.globl\t"  << CurrentFnName << "\n";
   O << "\t.ent\t"    << CurrentFnName << "\n";
-  O << "\t.type\t"   << CurrentFnName << ", @function\n";
+
+  if ((TAI->hasDotTypeDotSizeDirective()) && Subtarget->isLinux())
+    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";
 }
 
@@ -262,12 +271,15 @@ emitFunctionStart(MachineFunction &MF)
 void MipsAsmPrinter::
 emitFunctionEnd(MachineFunction &MF) 
 {
-  if (TM.getRelocationModel() == Reloc::Static) {
-    emitSetDirective(MACRO);
-    emitSetDirective(REORDER);
-  }    
+  // There are instruction for this macros, but they must
+  // always be at the function end, and we can't emit and
+  // break with BB logic. 
+  O << "\t.set\tmacro\n"; 
+  O << "\t.set\treorder\n"; 
 
   O << "\t.end\t" << CurrentFnName << "\n";
+  if (TAI->hasDotTypeDotSizeDirective() && !Subtarget->isLinux())
+    O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << "\n";
 }
 
 /// runOnMachineFunction - This uses the printMachineInstruction()
@@ -429,10 +441,29 @@ printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
   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) 
 {
   Mang = new Mangler(M);
+
+  // Tell the assembler which ABI we are using
+  O << "\t.section .mdebug." << emitCurrentABIString() << "\n";
+
+  // TODO: handle O64 ABI
+  if (Subtarget->isABI_EABI())
+    O << "\t.section .gcc_compiled_long" << 
+      (Subtarget->isGP32bit() ? "32" : "64") << "\n";
+
+  // return to previous section
+  O << "\t.previous" << "\n"; 
+
   return false; // success
 }
 
@@ -455,9 +486,24 @@ doFinalization(Module &M)
       
       O << "\n\n";
       std::string name = Mang->getValueName(I);
-      Constant *C      = I->getInitializer();
-      unsigned Size    = TD->getABITypeSize(C->getType());
-      unsigned Align   = TD->getPreferredAlignmentLog(I);
+      Constant *C = I->getInitializer();
+      const Type *CTy = C->getType();
+      unsigned Size = TD->getABITypeSize(CTy);
+      bool printSizeAndType = true;
+
+      // A data structure or array is aligned in memory to the largest 
+      // alignment boundary required by any data type inside it (this matches
+      // the Preferred Type Alignment). For integral types, the alignment is 
+      // the type size. 
+      //unsigned Align = TD->getPreferredAlignmentLog(I);
+      //unsigned Align = TD->getPrefTypeAlignment(C->getType());
+      unsigned Align;
+      if (CTy->getTypeID() == Type::IntegerTyID || 
+          CTy->getTypeID() == Type::VoidTyID) {
+        assert(!(Size & (Size-1)) && "Alignment is not a power of two!");
+        Align = Log2_32(Size);
+      } else
+        Align = TD->getPreferredTypeAlignmentShift(CTy);
 
       // Is this correct ?
       if (C->isNullValue() && (I->hasLinkOnceLinkage() || 
@@ -518,10 +564,20 @@ doFinalization(Module &M)
               else if (!I->isConstant())
                 SwitchToDataSection(TAI->getDataSection(), I);
               else {
-                // Read-only data.
-                if (TAI->getReadOnlySection())
+                // Read-only data. We have two possible scenary here
+                // 1) Readonly section for strings (char arrays).
+                // 2) for other types.
+                if (TAI->getReadOnlySection()) {
+                  const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
+                  if (CVA && CVA->isString()) {
+                      std::string SectionName = "\t.section\t.rodata.str1.4,"
+                                                "\"aMS\",@progbits,1";
+                      SwitchToDataSection(SectionName.c_str());
+                      printSizeAndType = false;
+                      break;
+                  }
                   SwitchToDataSection(TAI->getReadOnlySection(), I);
-                else
+                else
                   SwitchToDataSection(TAI->getDataSection(), I);
               }
             }
@@ -537,15 +593,21 @@ doFinalization(Module &M)
             abort();
           default:
             assert(0 && "Unknown linkage type!");          
-        }
+        } 
+
+        if (Align)
+          O << "\t.align " << Align << "\n";
 
-        O << "\t.align " << Align << "\n";
-        O << "\t.type " << name << ",@object\n";
-        O << "\t.size " << name << "," << Size << "\n";
+        if (TAI->hasDotTypeDotSizeDirective() && printSizeAndType) {
+          O << "\t.type " << name << ",@object\n";
+          O << "\t.size " << name << "," << Size << "\n";
+        }
         O << name << ":\n";
         EmitGlobalConstant(C);
-    }
+    } 
   }
 
+  O << "\n";
+
   return AsmPrinter::doFinalization(M);
 }