diff --git a/lib/Target/Sparc/EmitAssembly.cpp b/lib/Target/Sparc/EmitAssembly.cpp new file mode 100644 index 00000000000..9014d216aa5 --- /dev/null +++ b/lib/Target/Sparc/EmitAssembly.cpp @@ -0,0 +1,213 @@ +//===-- EmitAssembly.cpp - Emit Sparc Specific .s File ---------------------==// +// +// This file implements all of the stuff neccesary to output a .s file from +// LLVM. The code in this file assumes that the specified module has already +// been compiled into the internal data structures of the Module. +// +// The entry point of this file is the UltraSparc::emitAssembly method. +// +//===----------------------------------------------------------------------===// + +#include "SparcInternals.h" +#include "llvm/Analysis/SlotCalculator.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/BasicBlock.h" +#include "llvm/Method.h" +#include "llvm/Module.h" +#include "llvm/Support/StringExtras.h" + +namespace { + +class SparcAsmPrinter { + ostream &Out; + SlotCalculator Table; + UltraSparc &Target; + + enum Sections { + Unknown, + Text, + Data, + ReadOnly, + } CurSection; +public: + inline SparcAsmPrinter(ostream &o, const Module *M, UltraSparc &t) + : Out(o), Table(SlotCalculator(M, true)), Target(t), CurSection(Unknown) { + emitModule(M); + } + +private : + void emitModule(const Module *M); + /* + void processSymbolTable(const SymbolTable &ST); + void processConstant(const ConstPoolVal *CPV); + void processGlobal(const GlobalVariable *GV); + */ + void emitMethod(const Method *M); + //void processMethodArgument(const MethodArgument *MA); + void emitBasicBlock(const BasicBlock *BB); + void emitMachineInst(const MachineInstr *MI); + + + //void writeOperand(const Value *Op, bool PrintType, bool PrintName = true); + + + // enterSection - Use this method to enter a different section of the output + // executable. This is used to only output neccesary section transitions. + // + void enterSection(enum Sections S) { + if (S == CurSection) return; // Only switch section if neccesary + CurSection = S; + + Out << ".section \"."; + switch (S) { + default: assert(0 && "Bad section name!"); + case Text: Out << "text"; break; + case Data: Out << "data"; break; + case ReadOnly: Out << "rodata"; break; + } + Out << "\"\n"; + } + + // getID - Return a valid identifier for the specified value. Base it on + // the name of the identifier if possible, use a numbered value based on + // prefix otherwise. FPrefix is always prepended to the output identifier. + // + string getID(const Value *V, const char *Prefix, const char *FPrefix = 0) { + string FP(FPrefix ? FPrefix : ""); // "Forced prefix" + if (V->hasName()) { + return FP + V->getName(); // TODO: Escape name if needed + } else { + assert(Table.getValSlot(V) != -1 && "Value not in value table!"); + return FP + string(Prefix) + itostr(Table.getValSlot(V)); + } + } + + // getID Wrappers - Ensure consistent usage... + string getID(const Method *M) { return getID(M, "anon_method$"); } + string getID(const BasicBlock *BB) { + return getID(BB, "LL", (".L$"+getID(BB->getParent())).c_str()); + } + + unsigned getOperandMask(unsigned Opcode) { + switch (Opcode) { + case SUBcc: return 1 << 3; // Remove CC argument + case BA: return 1 << 0; // Remove Arg #0, which is always null + default: return 0; // By default, don't hack operands... + } + } +}; + + +void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { + unsigned Opcode = MI->getOpCode(); + + if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG) + return; // IGNORE PHI NODES + + Out << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t"; + + unsigned Mask = getOperandMask(Opcode); + + bool NeedComma = false; + for(unsigned OpNum = 0; OpNum < MI->getNumOperands(); ++OpNum) { + if ((1 << OpNum) & Mask) continue; // Ignore this operand? + + const MachineOperand &Op = MI->getOperand(OpNum); + if (NeedComma) Out << ", "; // Handle comma outputing + NeedComma = true; + + switch (Op.getOperandType()) { + case MachineOperand::MO_VirtualRegister: + case MachineOperand::MO_CCRegister: + case MachineOperand::MO_MachineRegister: { + int RegNum = (int)Op.getAllocatedRegNum(); + + // ****this code is temporary till NULL Values are fixed + if (RegNum == 10000) { + Out << ""; + continue; + } + + Out << "%" << Target.getRegInfo().getUnifiedRegName(RegNum); + break; + } + + case MachineOperand::MO_PCRelativeDisp: { + const Value *Val = Op.getVRegValue(); + if (!Val) { + Out << "\t<*NULL Value*>"; + } else if (Val->isBasicBlock()) { + Out << getID(Val->castBasicBlockAsserting()); + } else { + Out << ""; + } + break; + } + + default: + Out << Op; // use dump field + break; + } + } + Out << endl; +} + +void SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) { + // Emit a label for the basic block + Out << getID(BB) << ":\n"; + + // Get the vector of machine instructions corresponding to this bb. + const MachineCodeForBasicBlock &MIs = BB->getMachineInstrVec(); + MachineCodeForBasicBlock::const_iterator MII = MIs.begin(), MIE = MIs.end(); + + // Loop over all of the instructions in the basic block... + for (; MII != MIE; ++MII) + emitMachineInst(*MII); + Out << "\n"; // Seperate BB's with newlines +} + +void SparcAsmPrinter::emitMethod(const Method *M) { + if (M->isExternal()) return; + + // Make sure the slot table has information about this method... + Table.incorporateMethod(M); + + string MethName = getID(M); + Out << "!****** Outputing Method: " << MethName << " ******\n"; + enterSection(Text); + Out << "\t.align 4\n\t.global\t" << MethName << "\n"; + Out << "\t.type\t" << MethName << ",#function\n"; + Out << MethName << ":\n"; + + // Output code for all of the basic blocks in the method... + for (Method::const_iterator I = M->begin(), E = M->end(); I != E; ++I) + emitBasicBlock(*I); + + // Output a .size directive so the debugger knows the extents of the function + Out << ".EndOf$" << MethName << ":\n\t.size " << MethName << ", .EndOf$" + << MethName << "-" << MethName << endl; + + // Put some spaces between the methods + Out << "\n\n"; + + // Forget all about M. + Table.purgeMethod(); +} + + +void SparcAsmPrinter::emitModule(const Module *M) { + // TODO: Look for a filename annotation on M to emit a .file directive + for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) + emitMethod(*I); +} + +} // End anonymous namespace + +// +// emitAssembly - Output assembly language code (a .s file) for the specified +// method. The specified method must have been compiled before this may be +// used. +// +void UltraSparc::emitAssembly(const Module *M, ostream &Out) { + SparcAsmPrinter Print(Out, M, *this); +}