diff --git a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp index 59cd52ab84c..fcc4c059f8e 100644 --- a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp +++ b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp @@ -10,25 +10,39 @@ #include "SparcInternals.h" #include "llvm/Analysis/SlotCalculator.h" +#include "llvm/Transforms/Linker.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/GlobalVariable.h" +#include "llvm/GlobalValue.h" +#include "llvm/ConstPoolVals.h" +#include "llvm/DerivedTypes.h" #include "llvm/BasicBlock.h" #include "llvm/Method.h" #include "llvm/Module.h" +#include "llvm/Support/HashExtras.h" #include "llvm/Support/StringExtras.h" namespace { -class SparcAsmPrinter { - ostream &Out; - SlotCalculator Table; - const UltraSparc &Target; +class SparcAsmPrinter { + typedef hash_map ValIdMap; + typedef ValIdMap:: iterator ValIdMapIterator; + typedef ValIdMap::const_iterator ValIdMapConstIterator; + + ostream &Out; + SlotCalculator Table; // map anonymous values to unique integer IDs + ValIdMap valToIdMap; // used for values not handled by SlotCalculator + const UltraSparc &Target; + enum Sections { Unknown, Text, - Data, - ReadOnly, + ReadOnlyData, + InitRWData, + UninitRWData, } CurSection; + public: inline SparcAsmPrinter(ostream &o, const Module *M, const UltraSparc &t) : Out(o), Table(SlotCalculator(M, true)), Target(t), CurSection(Unknown) { @@ -37,18 +51,21 @@ public: 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 emitGlobalsAndConstants(const Module* module); //void processMethodArgument(const MethodArgument *MA); void emitBasicBlock(const BasicBlock *BB); void emitMachineInst(const MachineInstr *MI); - void printOperand(const MachineOperand &Op); + void printGlobalVariable(const GlobalVariable* GV); + void printConstant(const ConstPoolVal* CV, string valID = string("")); + + unsigned int printOperands(const MachineInstr *MI, unsigned int opNum); + void printOneOperand(const MachineOperand &Op); + bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum); + bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum); + // enterSection - Use this method to enter a different section of the output // executable. This is used to only output neccesary section transitions. // @@ -56,14 +73,16 @@ private : 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"; + Out << "\n\t.section "; + switch (S) + { + default: assert(0 && "Bad section name!"); + case Text: Out << "\".text\""; break; + case ReadOnlyData: Out << "\".rodata\",#alloc"; break; + case InitRWData: Out << "\".data\",#alloc,#write"; break; + case UninitRWData: Out << "\".bss\",#alloc,#write\nBbss.bss:"; break; + } + Out << "\n"; } string getEscapedString(const string &S) { @@ -75,7 +94,7 @@ private : (C >= '0' && C <= '9')) { Result += C; } else { - Result += '$'; + Result += '_'; Result += char('0' + ((unsigned char)C >> 4)); Result += char('0' + (C & 0xF)); } @@ -92,17 +111,33 @@ private : if (V->hasName()) { return FP + getEscapedString(V->getName()); } else { - assert(Table.getValSlot(V) != -1 && "Value not in value table!"); - return FP + string(Prefix) + itostr(Table.getValSlot(V)); + int valId = Table.getValSlot(V); + if (valId == -1) { + ValIdMapConstIterator I = valToIdMap.find(V); + valId = (I == valToIdMap.end())? (valToIdMap[V] = valToIdMap.size()) + : (*I).second; + } + return FP + string(Prefix) + itostr(valId); } } - + // 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()); + string getID(const Module *M) { + return getID(M, "LLVMModule_"); } - + string getID(const Method *M) { + return getID(M, "LLVMMethod_"); + } + string getID(const BasicBlock *BB) { + return getID(BB, "LL", (".L_"+getID(BB->getParent())+"_").c_str()); + } + string getID(const GlobalVariable *GV) { + return getID(GV, "LLVMGlobal_", ".G_"); + } + string getID(const ConstPoolVal *CV) { + return getID(CV, "LLVMConst_", ".C_"); + } + unsigned getOperandMask(unsigned Opcode) { switch (Opcode) { case SUBcc: return 1 << 3; // Remove CC argument @@ -110,52 +145,118 @@ private : case BRLEZ: case BRLZ: case BRNZ: case BRGZ: case BRGEZ: return 1 << 0; - // case RETURN: return 1 << 1; // Remove Arg #2 which is zero default: return 0; // By default, don't hack operands... } } }; - -void SparcAsmPrinter::printOperand(const MachineOperand &Op) { - 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 << ""; - } else { - Out << "%" << Target.getRegInfo().getUnifiedRegName(RegNum); - } - break; - } - - case MachineOperand::MO_PCRelativeDisp: { - const Value *Val = Op.getVRegValue(); - if (!Val) { - Out << "\t<*NULL Value*>"; - } else if (const BasicBlock *BB = dyn_cast(Val)) { - Out << getID(BB); - } else if (const Method *M = dyn_cast(Val)) { - Out << getID(M); - } else { - Out << ""; - } - break; - } - - default: - Out << Op; // use dump field - break; +inline bool +SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, + unsigned int opNum) { + switch (MI->getOpCode()) { + case JMPLCALL: + case JMPLRET: return (opNum == 0); + default: return false; } } -void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { +inline bool +SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, + unsigned int opNum) { + if (Target.getInstrInfo().isLoad(MI->getOpCode())) + return (opNum == 0); + else if (Target.getInstrInfo().isStore(MI->getOpCode())) + return (opNum == 1); + else + return false; +} + + +#define PrintOp1PlusOp2(Op1, Op2) \ + printOneOperand(Op1); Out << "+"; printOneOperand(Op2); + + +unsigned int +SparcAsmPrinter::printOperands(const MachineInstr *MI, + unsigned int opNum) +{ + const MachineOperand& Op = MI->getOperand(opNum); + + if (OpIsBranchTargetLabel(MI, opNum)) + { + PrintOp1PlusOp2(Op, MI->getOperand(opNum+1)); + return 2; + } + else if (OpIsMemoryAddressBase(MI, opNum)) + { + Out << "["; + PrintOp1PlusOp2(Op, MI->getOperand(opNum+1)); + Out << "]"; + return 2; + } + else + { + printOneOperand(Op); + return 1; + } +} + + +void +SparcAsmPrinter::printOneOperand(const MachineOperand &Op) +{ + 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 << ""; + } else { + Out << "%" << Target.getRegInfo().getUnifiedRegName(RegNum); + } + break; + } + + case MachineOperand::MO_PCRelativeDisp: + { + const Value *Val = Op.getVRegValue(); + if (!Val) + Out << "\t<*NULL Value*>"; + else if (const BasicBlock *BB = dyn_cast(Val)) + Out << getID(BB); + else if (const Method *M = dyn_cast(Val)) + Out << getID(M); + else if (const GlobalVariable *GV=dyn_cast(Val)) + Out << getID(GV); + else if (const ConstPoolVal *CV = dyn_cast(Val)) + Out << getID(CV); + else + Out << ""; + break; + } + + case MachineOperand::MO_SignExtendedImmed: + case MachineOperand::MO_UnextendedImmed: + Out << Op.getImmedValue(); + break; + + default: + Out << Op; // use dump field + break; + } +} + + +void +SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) +{ unsigned Opcode = MI->getOpCode(); if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG) @@ -163,82 +264,25 @@ void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { Out << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t"; - switch (Opcode) { // Some opcodes have special syntax... - case JMPLCALL: - case JMPLRET: - assert(MI->getNumOperands() == 3 && "Unexpected JMPL instr!"); - printOperand(MI->getOperand(0)); - Out << "+"; - printOperand(MI->getOperand(1)); - Out << ", "; - printOperand(MI->getOperand(2)); - Out << endl; - return; - - case RETURN: - assert(MI->getNumOperands() == 2 && "Unexpected RETURN instr!"); - printOperand(MI->getOperand(0)); - Out << "+"; - printOperand(MI->getOperand(1)); - Out << endl; - return; - - default: break; - } - - if( Target.getInstrInfo().isLoad(Opcode) ) { // if Load - assert(MI->getNumOperands() == 3 && "Loads must have 3 operands"); - Out << "["; - printOperand(MI->getOperand(0)); - - const MachineOperand& ImmOp = MI->getOperand(1); - if( ImmOp.getImmedValue() >= 0) - Out << "+"; - printOperand(ImmOp); - Out << "]"; - Out << ", "; - - printOperand(MI->getOperand(2)); - Out << endl; - return; - - } - - if( Target.getInstrInfo().isStore(Opcode) ) { // if Store - assert(MI->getNumOperands() == 3 && "Stores must have 3 operands"); - printOperand(MI->getOperand(0)); - Out << ", "; - Out << "["; - printOperand(MI->getOperand(1)); - - const MachineOperand& ImmOp = MI->getOperand(2); - if( ImmOp.getImmedValue() >= 0) - Out << "+"; - printOperand(ImmOp); - Out << "]"; - Out << endl; - return; - - } - - - 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; - - printOperand(Op); - } + unsigned N = 1; + for (unsigned OpNum = 0; OpNum < MI->getNumOperands(); OpNum += N) + if (! ((1 << OpNum) & Mask)) { // Ignore this operand? + if (NeedComma) Out << ", "; // Handle comma outputing + NeedComma = true; + N = printOperands(MI, OpNum); + } + else + N = 1; + Out << endl; } -void SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) { +void +SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) +{ // Emit a label for the basic block Out << getID(BB) << ":\n"; @@ -252,7 +296,9 @@ void SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) { Out << "\n"; // Seperate BB's with newlines } -void SparcAsmPrinter::emitMethod(const Method *M) { +void +SparcAsmPrinter::emitMethod(const Method *M) +{ if (M->isExternal()) return; // Make sure the slot table has information about this method... @@ -261,7 +307,7 @@ void SparcAsmPrinter::emitMethod(const Method *M) { string MethName = getID(M); Out << "!****** Outputing Method: " << MethName << " ******\n"; enterSection(Text); - Out << "\t.align 4\n\t.global\t" << MethName << "\n"; + Out << "\t.align\t4\n\t.global\t" << MethName << "\n"; //Out << "\t.type\t" << MethName << ",#function\n"; Out << "\t.type\t" << MethName << ", 2\n"; Out << MethName << ":\n"; @@ -271,7 +317,8 @@ void SparcAsmPrinter::emitMethod(const Method *M) { emitBasicBlock(*I); // Output a .size directive so the debugger knows the extents of the function - Out << ".EndOf$" << MethName << ":\n\t.size " << MethName << ", .EndOf$" + Out << ".EndOf_" << MethName << ":\n\t.size " + << MethName << ", .EndOf_" << MethName << "-" << MethName << endl; // Put some spaces between the methods @@ -281,20 +328,195 @@ void SparcAsmPrinter::emitMethod(const Method *M) { Table.purgeMethod(); } +inline bool +ArrayTypeIsString(ArrayType* arrayType) +{ + return (arrayType->getElementType() == Type::UByteTy || + arrayType->getElementType() == Type::SByteTy); +} -void SparcAsmPrinter::emitModule(const Module *M) { +inline const string TypeToDataDirective(const Type* type) { + switch(type->getPrimitiveID()) { + case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: + return ".byte"; + case Type::UShortTyID: case Type::ShortTyID: + return ".half"; + case Type::UIntTyID: case Type::IntTyID: + return ".word"; + case Type::ULongTyID: case Type::LongTyID: case Type::PointerTyID: + return ".xword"; + case Type::FloatTyID: + return ".float"; + case Type::DoubleTyID: + return ".double"; + case Type::ArrayTyID: + if (ArrayTypeIsString((ArrayType*) type)) + return ".ascii"; + else + return ""; + default: + return ""; + } +} + +inline unsigned int ConstantToSize(const ConstPoolVal* CV, + const TargetMachine& target) { + if (ConstPoolArray* AV = dyn_cast(CV)) + if (ArrayTypeIsString((ArrayType*) CV->getType())) + return 1 + AV->getNumOperands(); + + return target.findOptimalStorageSize(CV->getType()); +} + + +inline +unsigned int TypeToSize(const Type* type, const TargetMachine& target) +{ + return target.findOptimalStorageSize(type); +} + + +inline unsigned int +TypeToAlignment(const Type* type, const TargetMachine& target) +{ + if (type->getPrimitiveID() == Type::ArrayTyID && + ArrayTypeIsString((ArrayType*) type)) + return target.findOptimalStorageSize(Type::LongTy); + + return target.findOptimalStorageSize(type); +} + + +void +SparcAsmPrinter::printConstant(const ConstPoolVal* CV, string valID) +{ + if (valID.length() == 0) + valID = getID(CV); + + Out << "\t.align\t" << TypeToAlignment(CV->getType(), Target) + << endl; + + Out << valID << ":" << endl; + + Out << "\t" + << TypeToDataDirective(CV->getType()) << "\t" + << CV->getStrValue(false) << endl; + + Out << "\t.type" << "\t" << valID << ",#object" << endl; + Out << "\t.size" << "\t" << valID << "," + << ConstantToSize(CV, Target) << endl; +} + + +void +SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) +{ + Out << "\t.global\t" << getID(GV) << endl; + + if (GV->hasInitializer()) + printConstant(GV->getInitializer(), getID(GV)); + else { + Out << "\t.align" << TypeToAlignment(GV->getType()->getValueType(), Target) + << getID(GV) << ":" << endl; + + Out << "\t.type" << "\t" << getID(GV) << ",#object" << endl; + Out << "\t.size" << "\t" << getID(GV) << "," + << TypeToSize(GV->getType()->getValueType(), Target) + << endl; + } +} + + +static void +FoldConstPools(const Module *M, + hash_set& moduleConstPool) { + for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) { + const hash_set& pool = + (*I)->getMachineCode().getConstantPoolValues(); + moduleConstPool.insert(pool.begin(), pool.end()); + } +} + + +void +SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) +{ + // First, get the constants there were marked by the code generator for + // inclusion in the assembly code data area and fold them all into a + // single constant pool since there may be lots of duplicates. Also, + // lets force these constants into the slot table so that we can get + // unique names for unnamed constants also. + // + hash_set moduleConstPool; + FoldConstPools(M, moduleConstPool); + + // Now, emit the three data sections separately; the cost of I/O should + // make up for the cost of extra passes over the globals list! + // + // Read-only data section (implies initialized) + for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) + { + const GlobalVariable* GV = *GI; + if (GV->hasInitializer() && GV->isConstant()) + { + if (GI == M->gbegin()) + enterSection(ReadOnlyData); + printGlobalVariable(GV); + } + } + + for (hash_set::const_iterator I=moduleConstPool.begin(), + E = moduleConstPool.end(); I != E; ++I) + printConstant(*I); + + // Initialized read-write data section + for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) + { + const GlobalVariable* GV = *GI; + if (GV->hasInitializer() && ! GV->isConstant()) + { + if (GI == M->gbegin()) + enterSection(InitRWData); + printGlobalVariable(GV); + } + } + + // Uninitialized read-write data section + for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) + { + const GlobalVariable* GV = *GI; + if (! GV->hasInitializer()) + { + if (GI == M->gbegin()) + enterSection(UninitRWData); + printGlobalVariable(GV); + } + } + + Out << endl; +} + + +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); + + emitGlobalsAndConstants(M); } } // 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) const { +void +UltraSparc::emitAssembly(const Module *M, ostream &Out) const +{ SparcAsmPrinter Print(Out, M, *this); }