From: Chris Lattner Date: Sun, 3 Feb 2002 23:41:08 +0000 (+0000) Subject: Convert assembly emission over to a two pass approach. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=c19b8b10e5768bf411e094b86a161b1f608749e2;p=oota-llvm.git Convert assembly emission over to a two pass approach. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1662 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp index 74b1f44f912..6159f98e9bc 100644 --- a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp +++ b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp @@ -4,7 +4,10 @@ // 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. +// This code largely consists of two LLVM Pass's: a MethodPass and a Pass. The +// MethodPass is pipelined together with all of the rest of the code generation +// stages, and the Pass runs at the end to emit code for global variables and +// such. // //===----------------------------------------------------------------------===// @@ -24,17 +27,21 @@ using std::string; namespace { +//===----------------------------------------------------------------------===// +// Code Shared By the two printer passes, as a mixin +//===----------------------------------------------------------------------===// -class SparcAsmPrinter { +class AsmPrinter { typedef std::hash_map ValIdMap; typedef ValIdMap:: iterator ValIdMapIterator; typedef ValIdMap::const_iterator ValIdMapConstIterator; + SlotCalculator *Table; // map anonymous values to unique integer IDs + ValIdMap valToIdMap; // used for values not handled by SlotCalculator +public: std::ostream &toAsm; - 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, @@ -42,28 +49,27 @@ class SparcAsmPrinter { InitRWData, UninitRWData, } CurSection; - -public: - inline SparcAsmPrinter(std::ostream &o, const Module *M, const UltraSparc &t) - : toAsm(o), Table(SlotCalculator(M, true)), Target(t), CurSection(Unknown) { - } - void emitMethod(const Method *M); - void emitGlobalsAndConstants(const Module *M); -private : - void emitBasicBlock(const BasicBlock *BB); - void emitMachineInst(const MachineInstr *MI); - - void printGlobalVariable( const GlobalVariable* GV); - void printSingleConstant( const Constant* CV); - void printConstantValueOnly(const Constant* CV); - void printConstant( const Constant* CV, std::string valID = ""); - - unsigned int printOperands(const MachineInstr *MI, unsigned int opNum); - void printOneOperand(const MachineOperand &Op); + AsmPrinter(std::ostream &os, const UltraSparc &T) + : Table(0), toAsm(os), Target(T), CurSection(Unknown) {} + + + // (start|end)(Module|Method) - Callback methods to be invoked by subclasses + void startModule(Module *M) { + Table = new SlotCalculator(M, true); + } + void startMethod(Method *M) { + // Make sure the slot table has information about this method... + Table->incorporateMethod(M); + } + void endMethod(Method *M) { + Table->purgeMethod(); // Forget all about M. + } + void endModule() { + delete Table; Table = 0; + valToIdMap.clear(); + } - 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. @@ -84,7 +90,7 @@ private : toAsm << "\n"; } - std::string getValidSymbolName(const string &S) { + static std::string getValidSymbolName(const string &S) { string Result; // Symbol names in Sparc assembly language have these rules: @@ -120,11 +126,13 @@ private : if (V->hasName()) { Result = FP + V->getName(); } else { - int valId = 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; + if (I == valToIdMap.end()) + valId = valToIdMap[V] = valToIdMap.size(); + else + valId = I->second; } Result = FP + string(Prefix) + itostr(valId); } @@ -147,81 +155,57 @@ private : string getID(const Constant *CV) { return getID(CV, "LLVMConst_", ".C_"); } - - 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 or xcc - default: return 0; // By default, don't hack operands... - } - } }; -// Can we treat the specified array as a string? Only if it is an array of -// ubytes or non-negative sbytes. -// -static bool isStringCompatible(ConstantArray *CPA) { - const Type *ETy = cast(CPA->getType())->getElementType(); - if (ETy == Type::UByteTy) return true; - if (ETy != Type::SByteTy) return false; - for (unsigned i = 0; i < CPA->getNumOperands(); ++i) - if (cast(CPA->getOperand(i))->getValue() < 0) - return false; +//===----------------------------------------------------------------------===// +// SparcMethodAsmPrinter Code +//===----------------------------------------------------------------------===// - return true; -} +struct SparcMethodAsmPrinter : public MethodPass, public AsmPrinter { + inline SparcMethodAsmPrinter(std::ostream &os, const UltraSparc &t) + : AsmPrinter(os, t) {} -// toOctal - Convert the low order bits of X into an octal letter -static inline char toOctal(int X) { - return (X&7)+'0'; -} - -// getAsCString - Return the specified array as a C compatible string, only if -// the predicate isStringCompatible is true. -// -static string getAsCString(ConstantArray *CPA) { - if (isStringCompatible(CPA)) { - string Result; - const Type *ETy = cast(CPA->getType())->getElementType(); - Result = "\""; - for (unsigned i = 0; i < CPA->getNumOperands(); ++i) { - unsigned char C = (ETy == Type::SByteTy) ? - (unsigned char)cast(CPA->getOperand(i))->getValue() : - (unsigned char)cast(CPA->getOperand(i))->getValue(); + virtual bool doInitialization(Module *M) { + startModule(M); + return false; + } - if (isprint(C)) { - Result += C; - } else { - switch(C) { - case '\a': Result += "\\a"; break; - case '\b': Result += "\\b"; break; - case '\f': Result += "\\f"; break; - case '\n': Result += "\\n"; break; - case '\r': Result += "\\r"; break; - case '\t': Result += "\\t"; break; - case '\v': Result += "\\v"; break; - default: - Result += '\\'; - Result += toOctal(C >> 6); - Result += toOctal(C >> 3); - Result += toOctal(C >> 0); - break; - } - } - } - Result += "\""; + virtual bool runOnMethod(Method *M) { + startMethod(M); + emitMethod(M); + endMethod(M); + return false; + } - return Result; - } else { - return CPA->getStrValue(); + virtual bool doFinalization(Module *M) { + endModule(); + return false; } -} + void emitMethod(const Method *M); +private : + void emitBasicBlock(const BasicBlock *BB); + void emitMachineInst(const MachineInstr *MI); + + 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); + + 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 or xcc + default: return 0; // By default, don't hack operands... + } + } +}; inline bool -SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, +SparcMethodAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum) { switch (MI->getOpCode()) { case JMPLCALL: @@ -232,7 +216,7 @@ SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, inline bool -SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, +SparcMethodAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum) { if (Target.getInstrInfo().isLoad(MI->getOpCode())) return (opNum == 0); @@ -249,7 +233,7 @@ SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, printOneOperand(Op2); unsigned int -SparcAsmPrinter::printOperands(const MachineInstr *MI, +SparcMethodAsmPrinter::printOperands(const MachineInstr *MI, unsigned int opNum) { const MachineOperand& Op = MI->getOperand(opNum); @@ -275,7 +259,7 @@ SparcAsmPrinter::printOperands(const MachineInstr *MI, void -SparcAsmPrinter::printOneOperand(const MachineOperand &op) +SparcMethodAsmPrinter::printOneOperand(const MachineOperand &op) { switch (op.getOperandType()) { @@ -325,7 +309,7 @@ SparcAsmPrinter::printOneOperand(const MachineOperand &op) void -SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) +SparcMethodAsmPrinter::emitMachineInst(const MachineInstr *MI) { unsigned Opcode = MI->getOpCode(); @@ -351,7 +335,7 @@ SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) } void -SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) +SparcMethodAsmPrinter::emitBasicBlock(const BasicBlock *BB) { // Emit a label for the basic block toAsm << getID(BB) << ":\n"; @@ -367,16 +351,11 @@ SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB) } void -SparcAsmPrinter::emitMethod(const Method *M) +SparcMethodAsmPrinter::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); toAsm << "!****** Outputing Method: " << methName << " ******\n"; - enterSection(Text); + enterSection(AsmPrinter::Text); toAsm << "\t.align\t4\n\t.global\t" << methName << "\n"; //toAsm << "\t.type\t" << methName << ",#function\n"; toAsm << "\t.type\t" << methName << ", 2\n"; @@ -388,14 +367,112 @@ SparcAsmPrinter::emitMethod(const Method *M) // Output a .size directive so the debugger knows the extents of the function toAsm << ".EndOf_" << methName << ":\n\t.size " - << methName << ", .EndOf_" - << methName << "-" << methName << "\n"; + << methName << ", .EndOf_" + << methName << "-" << methName << "\n"; // Put some spaces between the methods toAsm << "\n\n"; +} - // Forget all about M. - Table.purgeMethod(); +} // End anonymous namespace + +Pass *UltraSparc::getMethodAsmPrinterPass(PassManager &PM, std::ostream &Out) { + return new SparcMethodAsmPrinter(Out, *this); +} + + + + + +//===----------------------------------------------------------------------===// +// SparcMethodAsmPrinter Code +//===----------------------------------------------------------------------===// + +namespace { + +class SparcModuleAsmPrinter : public Pass, public AsmPrinter { +public: + SparcModuleAsmPrinter(ostream &os, UltraSparc &t) : AsmPrinter(os, t) {} + + virtual bool run(Module *M) { + startModule(M); + emitGlobalsAndConstants(M); + endModule(); + return false; + } + + void emitGlobalsAndConstants(const Module *M); + + void printGlobalVariable(const GlobalVariable *GV); + void printSingleConstant( const Constant* CV); + void printConstantValueOnly(const Constant* CV); + void printConstant( const Constant* CV, std::string valID = ""); + + static void FoldConstants(const Module *M, + std::hash_set &moduleConstants); + +}; + + +// Can we treat the specified array as a string? Only if it is an array of +// ubytes or non-negative sbytes. +// +static bool isStringCompatible(ConstantArray *CPA) { + const Type *ETy = cast(CPA->getType())->getElementType(); + if (ETy == Type::UByteTy) return true; + if (ETy != Type::SByteTy) return false; + + for (unsigned i = 0; i < CPA->getNumOperands(); ++i) + if (cast(CPA->getOperand(i))->getValue() < 0) + return false; + + return true; +} + +// toOctal - Convert the low order bits of X into an octal letter +static inline char toOctal(int X) { + return (X&7)+'0'; +} + +// getAsCString - Return the specified array as a C compatible string, only if +// the predicate isStringCompatible is true. +// +static string getAsCString(ConstantArray *CPA) { + if (isStringCompatible(CPA)) { + string Result; + const Type *ETy = cast(CPA->getType())->getElementType(); + Result = "\""; + for (unsigned i = 0; i < CPA->getNumOperands(); ++i) { + unsigned char C = (ETy == Type::SByteTy) ? + (unsigned char)cast(CPA->getOperand(i))->getValue() : + (unsigned char)cast(CPA->getOperand(i))->getValue(); + + if (isprint(C)) { + Result += C; + } else { + switch(C) { + case '\a': Result += "\\a"; break; + case '\b': Result += "\\b"; break; + case '\f': Result += "\\f"; break; + case '\n': Result += "\\n"; break; + case '\r': Result += "\\r"; break; + case '\t': Result += "\\t"; break; + case '\v': Result += "\\v"; break; + default: + Result += '\\'; + Result += toOctal(C >> 6); + Result += toOctal(C >> 3); + Result += toOctal(C >> 0); + break; + } + } + } + Result += "\""; + + return Result; + } else { + return CPA->getStrValue(); + } } inline bool @@ -488,7 +565,7 @@ ConstantToAlignment(const Constant* CV, const TargetMachine& target) // Print a single constant value. void -SparcAsmPrinter::printSingleConstant(const Constant* CV) +SparcModuleAsmPrinter::printSingleConstant(const Constant* CV) { assert(CV->getType() != Type::VoidTy && CV->getType() != Type::TypeTy && @@ -498,8 +575,7 @@ SparcAsmPrinter::printSingleConstant(const Constant* CV) assert((! isa( CV) && ! isa(CV)) && "Collective types should be handled outside this function"); - toAsm << "\t" - << TypeToDataDirective(CV->getType()) << "\t"; + toAsm << "\t" << TypeToDataDirective(CV->getType()) << "\t"; if (CV->getType()->isPrimitiveType()) { @@ -526,7 +602,7 @@ SparcAsmPrinter::printSingleConstant(const Constant* CV) // Print a constant value or values (it may be an aggregate). // Uses printSingleConstant() to print each individual value. void -SparcAsmPrinter::printConstantValueOnly(const Constant* CV) +SparcModuleAsmPrinter::printConstantValueOnly(const Constant* CV) { ConstantArray *CPA = dyn_cast(CV); @@ -554,13 +630,12 @@ SparcAsmPrinter::printConstantValueOnly(const Constant* CV) // appropriate directives. Uses printConstantValueOnly() to print the // value or values. void -SparcAsmPrinter::printConstant(const Constant* CV, string valID) +SparcModuleAsmPrinter::printConstant(const Constant* CV, string valID) { if (valID.length() == 0) valID = getID(CV); - toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) - << "\n"; + toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n"; // Print .size and .type only if it is not a string. ConstantArray *CPA = dyn_cast(CV); @@ -575,25 +650,33 @@ SparcAsmPrinter::printConstant(const Constant* CV, string valID) unsigned int constSize = ConstantToSize(CV, Target); if (constSize) - toAsm << "\t.size" << "\t" << valID << "," - << constSize << "\n"; + toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n"; toAsm << valID << ":\n"; - this->printConstantValueOnly(CV); + printConstantValueOnly(CV); } -void -SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) +void SparcModuleAsmPrinter::FoldConstants(const Module *M, + std::hash_set &MC) { + for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!(*I)->isExternal()) { + const std::hash_set &pool = + MachineCodeForMethod::get(*I).getConstantPoolValues(); + MC.insert(pool.begin(), pool.end()); + } +} + +void SparcModuleAsmPrinter::printGlobalVariable(const GlobalVariable* GV) { toAsm << "\t.global\t" << getID(GV) << "\n"; if (GV->hasInitializer()) printConstant(GV->getInitializer(), getID(GV)); else { - toAsm << "\t.align\t" - << TypeToAlignment(GV->getType()->getElementType(), Target) << "\n"; + toAsm << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(), + Target) << "\n"; toAsm << "\t.type\t" << getID(GV) << ",#object\n"; toAsm << "\t.reserve\t" << getID(GV) << "," << Target.findOptimalStorageSize(GV->getType()->getElementType()) @@ -602,23 +685,7 @@ SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) } -static void -FoldConstants(const Module *M, - std::hash_set& moduleConstants) -{ - for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) - if (! (*I)->isExternal()) - { - const std::hash_set& pool = - MachineCodeForMethod::get(*I).getConstantPoolValues(); - moduleConstants.insert(pool.begin(), pool.end()); - } -} - - -void -SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) -{ +void SparcModuleAsmPrinter::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, @@ -627,7 +694,7 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) // std::hash_set moduleConstants; FoldConstants(M, moduleConstants); - + // 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! // @@ -638,10 +705,10 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) if (GV->hasInitializer() && GV->isConstant()) { if (GI == M->gbegin()) - enterSection(ReadOnlyData); + enterSection(AsmPrinter::ReadOnlyData); printGlobalVariable(GV); } - } + } for (std::hash_set::const_iterator I = moduleConstants.begin(), @@ -655,11 +722,11 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) if (GV->hasInitializer() && ! GV->isConstant()) { if (GI == M->gbegin()) - enterSection(InitRWData); + enterSection(AsmPrinter::InitRWData); printGlobalVariable(GV); } - } - + } + // Uninitialized read-write data section for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) { @@ -667,38 +734,16 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M) if (! GV->hasInitializer()) { if (GI == M->gbegin()) - enterSection(UninitRWData); + enterSection(AsmPrinter::UninitRWData); printGlobalVariable(GV); } - } - + } + toAsm << "\n"; } } // End anonymous namespace - -// -// emitAssembly - Output assembly language code (a .s file) for global -// components of the specified module. This assumes that methods have been -// previously output. -// -void -UltraSparc::emitAssembly(const Method *M, std::ostream &OutStr) const -{ - SparcAsmPrinter Print(OutStr, M->getParent(), *this); - Print.emitMethod(M); +Pass *UltraSparc::getModuleAsmPrinterPass(PassManager &PM, std::ostream &Out) { + return new SparcModuleAsmPrinter(Out, *this); } - -// -// 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, std::ostream &OutStr) const -{ - SparcAsmPrinter Print(OutStr, M, *this); - Print.emitGlobalsAndConstants(M); -} -