X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FSparcV9%2FSparcV9AsmPrinter.cpp;h=af86e05a9050b8679873760c0d61a9d8b07f7518;hb=12c1d2c25ac0f7cb9b6bb927e0283d2c376d3456;hp=fa2aeaa3b1176b0b7850dad507ae7e934d5712aa;hpb=d50b6712804c222a54534ba40dd8b0f660ffce43;p=oota-llvm.git diff --git a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp index fa2aeaa3b11..af86e05a905 100644 --- a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp +++ b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp @@ -1,6 +1,13 @@ //===-- EmitAssembly.cpp - Emit Sparc Specific .s File ---------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// // -// This file implements all of the stuff neccesary to output a .s file from +// This file implements all of the stuff necessary 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. // @@ -11,304 +18,649 @@ // //===----------------------------------------------------------------------===// -#include "SparcInternals.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineCodeForMethod.h" -#include "llvm/GlobalVariable.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" -#include "llvm/Annotation.h" -#include "llvm/BasicBlock.h" -#include "llvm/Function.h" #include "llvm/Module.h" -#include "llvm/SlotCalculator.h" #include "llvm/Pass.h" #include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionInfo.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Support/Mangler.h" #include "Support/StringExtras.h" -#include "Support/HashExtras.h" -#include -using std::string; +#include "Support/Statistic.h" +#include "SparcInternals.h" +#include +using namespace llvm; namespace { + Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); + + //===--------------------------------------------------------------------===// + // Utility functions + + /// getAsCString - Return the specified array as a C compatible string, only + /// if the predicate isString() is true. + /// + std::string getAsCString(const ConstantArray *CVA) { + assert(CVA->isString() && "Array is not string compatible!"); + + std::string Result = "\""; + for (unsigned i = 0; i != CVA->getNumOperands(); ++i) { + unsigned char C = cast(CVA->getOperand(i))->getRawValue(); + + if (C == '"') { + Result += "\\\""; + } else if (C == '\\') { + Result += "\\\\"; + } else if (isprint(C)) { + Result += C; + } else { + Result += '\\'; // print all other chars as octal value + // Convert C to octal representation + Result += ((C >> 6) & 7) + '0'; + Result += ((C >> 3) & 7) + '0'; + Result += ((C >> 0) & 7) + '0'; + } + } + Result += "\""; -class GlobalIdTable: public Annotation { - static AnnotationID AnnotId; - friend class AsmPrinter; // give access to AnnotId - - typedef std::hash_map ValIdMap; - typedef ValIdMap::const_iterator ValIdMapConstIterator; - typedef ValIdMap:: iterator ValIdMapIterator; -public: - SlotCalculator Table; // map anonymous values to unique integer IDs - ValIdMap valToIdMap; // used for values not handled by SlotCalculator + return Result; + } + + inline bool ArrayTypeIsString(const ArrayType* arrayType) { + return (arrayType->getElementType() == Type::UByteTy || + arrayType->getElementType() == Type::SByteTy); + } + + inline const std::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 ".word"; + case Type::DoubleTyID: + return ".xword"; + case Type::ArrayTyID: + if (ArrayTypeIsString((ArrayType*) type)) + return ".ascii"; + else + return ""; + default: + return ""; + } + } + + /// Get the size of the constant for the given target. + /// If this is an unsized array, return 0. + /// + inline unsigned int + ConstantToSize(const Constant* CV, const TargetMachine& target) { + if (const ConstantArray* CVA = dyn_cast(CV)) { + const ArrayType *aty = cast(CVA->getType()); + if (ArrayTypeIsString(aty)) + return 1 + CVA->getNumOperands(); + } - GlobalIdTable(Module* M) : Annotation(AnnotId), Table(M, true) {} -}; + return target.findOptimalStorageSize(CV->getType()); + } -AnnotationID GlobalIdTable::AnnotId = - AnnotationManager::getID("ASM PRINTER GLOBAL TABLE ANNOT"); + /// Align data larger than one L1 cache line on L1 cache line boundaries. + /// Align all smaller data on the next higher 2^x boundary (4, 8, ...). + /// + inline unsigned int + SizeToAlignment(unsigned int size, const TargetMachine& target) { + unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); + if (size > (unsigned) cacheLineSize / 2) + return cacheLineSize; + else + for (unsigned sz=1; /*no condition*/; sz *= 2) + if (sz >= size) + return sz; + } + + /// Get the size of the type and then use SizeToAlignment. + /// + inline unsigned int + TypeToAlignment(const Type* type, const TargetMachine& target) { + return SizeToAlignment(target.findOptimalStorageSize(type), target); + } + + /// Get the size of the constant and then use SizeToAlignment. + /// Handles strings as a special case; + inline unsigned int + ConstantToAlignment(const Constant* CV, const TargetMachine& target) { + if (const ConstantArray* CVA = dyn_cast(CV)) + if (ArrayTypeIsString(cast(CVA->getType()))) + return SizeToAlignment(1 + CVA->getNumOperands(), target); + return TypeToAlignment(CV->getType(), target); + } + +} // End anonymous namespace + + + //===---------------------------------------------------------------------===// -// Code Shared By the two printer passes, as a mixin +// Code abstracted away from the AsmPrinter //===---------------------------------------------------------------------===// -class AsmPrinter { - GlobalIdTable* idTable; -public: - std::ostream &toAsm; - const TargetMachine &Target; +namespace { + class AsmPrinter { + // Mangle symbol names appropriately + Mangler *Mang; + + public: + std::ostream &toAsm; + const TargetMachine &Target; - enum Sections { - Unknown, - Text, - ReadOnlyData, - InitRWData, - UninitRWData, - } CurSection; - - AsmPrinter(std::ostream &os, const TargetMachine &T) - : idTable(0), toAsm(os), Target(T), CurSection(Unknown) {} + enum Sections { + Unknown, + Text, + ReadOnlyData, + InitRWData, + ZeroInitRWData, + } CurSection; + + AsmPrinter(std::ostream &os, const TargetMachine &T) + : /* idTable(0), */ toAsm(os), Target(T), CurSection(Unknown) {} - // (start|end)(Module|Function) - Callback methods to be invoked by subclasses - void startModule(Module *M) { - // Create the global id table if it does not already exist - idTable = (GlobalIdTable*) M->getAnnotation(GlobalIdTable::AnnotId); - if (idTable == NULL) { - idTable = new GlobalIdTable(M); - M->addAnnotation(idTable); + ~AsmPrinter() { + delete Mang; } - } - void startFunction(Function *F) { - // Make sure the slot table has information about this function... - idTable->Table.incorporateFunction(F); - } - void endFunction(Function *F) { - idTable->Table.purgeFunction(); // Forget all about F - } - void endModule() { - } - // Check if a name is external or accessible from external code. - // Only functions can currently be external. "main" is the only name - // that is visible externally. - bool isExternal(const Value* V) { - const Function *F = dyn_cast(V); - return F && (F->isExternal() || F->getName() == "main"); - } + // (start|end)(Module|Function) - Callback methods invoked by subclasses + void startModule(Module &M) { + Mang = new Mangler(M); + } + + void PrintZeroBytesToPad(int numBytes) { + // + // Always use single unsigned bytes for padding. We don't know upon + // what data size the beginning address is aligned, so using anything + // other than a byte may cause alignment errors in the assembler. + // + while (numBytes--) + printSingleConstantValue(Constant::getNullValue(Type::UByteTy)); + } + + /// Print a single constant value. + /// + void printSingleConstantValue(const Constant* CV); + + /// Print a constant value or values (it may be an aggregate). + /// Uses printSingleConstantValue() to print each individual value. + /// + void printConstantValueOnly(const Constant* CV, int numPadBytesAfter = 0); + + // Print a constant (which may be an aggregate) prefixed by all the + // appropriate directives. Uses printConstantValueOnly() to print the + // value or values. + void printConstant(const Constant* CV, std::string valID = "") { + if (valID.length() == 0) + valID = getID(CV); - // 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; - - toAsm << "\n\t.section "; - switch (S) + toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n"; + + // Print .size and .type only if it is not a string. + if (const ConstantArray *CVA = dyn_cast(CV)) + if (CVA->isString()) { + // print it as a string and return + toAsm << valID << ":\n"; + toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; + return; + } + + toAsm << "\t.type" << "\t" << valID << ",#object\n"; + + unsigned int constSize = ConstantToSize(CV, Target); + if (constSize) + toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n"; + + toAsm << valID << ":\n"; + + printConstantValueOnly(CV); + } + + // enterSection - Use this method to enter a different section of the output + // executable. This is used to only output necessary section transitions. + // + void enterSection(enum Sections S) { + if (S == CurSection) return; // Only switch section if necessary + CurSection = S; + + toAsm << "\n\t.section "; + switch (S) { default: assert(0 && "Bad section name!"); case Text: toAsm << "\".text\""; break; case ReadOnlyData: toAsm << "\".rodata\",#alloc"; break; case InitRWData: toAsm << "\".data\",#alloc,#write"; break; - case UninitRWData: toAsm << "\".bss\",#alloc,#write\nBbss.bss:"; break; + case ZeroInitRWData: toAsm << "\".bss\",#alloc,#write"; break; } - toAsm << "\n"; - } + toAsm << "\n"; + } - static std::string getValidSymbolName(const string &S) { - string Result; - + // getID Wrappers - Ensure consistent usage // Symbol names in Sparc assembly language have these rules: // (a) Must match { letter | _ | . | $ } { letter | _ | . | $ | digit }* // (b) A name beginning in "." is treated as a local name. - // (c) Names beginning with "_" are reserved by ANSI C and shd not be used. - // - if (S[0] == '_' || isdigit(S[0])) - Result += "ll"; - - for (unsigned i = 0; i < S.size(); ++i) - { - char C = S[i]; - if (C == '_' || C == '.' || C == '$' || isalpha(C) || isdigit(C)) - Result += C; - else - { - Result += '_'; - Result += char('0' + ((unsigned char)C >> 4)); - Result += char('0' + (C & 0xF)); - } - } - return Result; - } + std::string getID(const Function *F) { + return Mang->getValueName(F); + } + std::string getID(const BasicBlock *BB) { + return ".L_" + getID(BB->getParent()) + "_" + Mang->getValueName(BB); + } + std::string getID(const GlobalVariable *GV) { + return Mang->getValueName(GV); + } + std::string getID(const Constant *CV) { + return ".C_" + Mang->getValueName(CV); + } + std::string getID(const GlobalValue *GV) { + if (const GlobalVariable *V = dyn_cast(GV)) + return getID(V); + else if (const Function *F = dyn_cast(GV)) + return getID(F); + assert(0 && "Unexpected type of GlobalValue!"); + return ""; + } - // getID - Return a valid identifier for the specified value. Base it on - // the name of the identifier if possible (qualified by the type), and - // 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 Result = FPrefix ? FPrefix : ""; // "Forced prefix" - - Result = Result + (V->hasName()? V->getName() : string(Prefix)); - - // Qualify all internal names with a unique id. - if (!isExternal(V)) { - int valId = idTable->Table.getValSlot(V); - if (valId == -1) { - GlobalIdTable::ValIdMapConstIterator I = idTable->valToIdMap.find(V); - if (I == idTable->valToIdMap.end()) - valId = idTable->valToIdMap[V] = idTable->valToIdMap.size(); - else - valId = I->second; - } - Result = Result + "_" + itostr(valId); + // Combines expressions + inline std::string ConstantArithExprToString(const ConstantExpr* CE, + const TargetMachine &TM, + const std::string &op) { + return "(" + valToExprString(CE->getOperand(0), TM) + op + + valToExprString(CE->getOperand(1), TM) + ")"; } - - return getValidSymbolName(Result); - } + + /// ConstantExprToString() - Convert a ConstantExpr to an asm expression + /// and return this as a string. + /// + std::string ConstantExprToString(const ConstantExpr* CE, + const TargetMachine& target); + + /// valToExprString - Helper function for ConstantExprToString(). + /// Appends result to argument string S. + /// + std::string valToExprString(const Value* V, const TargetMachine& target); + }; +} // End anonymous namespace + + +/// Print a single constant value. +/// +void AsmPrinter::printSingleConstantValue(const Constant* CV) { + assert(CV->getType() != Type::VoidTy && + CV->getType() != Type::TypeTy && + CV->getType() != Type::LabelTy && + "Unexpected type for Constant"); - // getID Wrappers - Ensure consistent usage... - string getID(const Function *F) { - return getID(F, "LLVMFunction_"); - } - string getID(const BasicBlock *BB) { - return getID(BB, "LL", (".L_"+getID(BB->getParent())+"_").c_str()); + assert((!isa(CV) && ! isa(CV)) + && "Aggregate types should be handled outside this function"); + + toAsm << "\t" << TypeToDataDirective(CV->getType()) << "\t"; + + if (const ConstantPointerRef* CPR = dyn_cast(CV)) { + // This is a constant address for a global variable or method. + // Use the name of the variable or method as the address value. + assert(isa(CPR->getValue()) && "Unexpected non-global"); + toAsm << getID(CPR->getValue()) << "\n"; + } else if (isa(CV)) { + // Null pointer value + toAsm << "0\n"; + } else if (const ConstantExpr* CE = dyn_cast(CV)) { + // Constant expression built from operators, constants, and symbolic addrs + toAsm << ConstantExprToString(CE, Target) << "\n"; + } else if (CV->getType()->isPrimitiveType()) { + // Check primitive types last + if (CV->getType()->isFloatingPoint()) { + // FP Constants are printed as integer constants to avoid losing + // precision... + double Val = cast(CV)->getValue(); + if (CV->getType() == Type::FloatTy) { + float FVal = (float)Val; + char *ProxyPtr = (char*)&FVal; // Abide by C TBAA rules + toAsm << *(unsigned int*)ProxyPtr; + } else if (CV->getType() == Type::DoubleTy) { + char *ProxyPtr = (char*)&Val; // Abide by C TBAA rules + toAsm << *(uint64_t*)ProxyPtr; + } else { + assert(0 && "Unknown floating point type!"); + } + + toAsm << "\t! " << CV->getType()->getDescription() + << " value: " << Val << "\n"; + } else if (const ConstantBool *CB = dyn_cast(CV)) { + toAsm << (int)CB->getValue() << "\n"; + } else { + WriteAsOperand(toAsm, CV, false, false) << "\n"; + } + } else { + assert(0 && "Unknown elementary type for constant"); } - string getID(const GlobalVariable *GV) { - return getID(GV, "LLVMGlobal_", ".G_"); +} + +/// Print a constant value or values (it may be an aggregate). +/// Uses printSingleConstantValue() to print each individual value. +/// +void AsmPrinter::printConstantValueOnly(const Constant* CV, + int numPadBytesAfter) { + if (const ConstantArray *CVA = dyn_cast(CV)) { + if (CVA->isString()) { + // print the string alone and return + toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; + } else { + // Not a string. Print the values in successive locations + const std::vector &constValues = CVA->getValues(); + for (unsigned i=0; i < constValues.size(); i++) + printConstantValueOnly(cast(constValues[i].get())); + } + } else if (const ConstantStruct *CVS = dyn_cast(CV)) { + // Print the fields in successive locations. Pad to align if needed! + const StructLayout *cvsLayout = + Target.getTargetData().getStructLayout(CVS->getType()); + const std::vector& constValues = CVS->getValues(); + unsigned sizeSoFar = 0; + for (unsigned i=0, N = constValues.size(); i < N; i++) { + const Constant* field = cast(constValues[i].get()); + + // Check if padding is needed and insert one or more 0s. + unsigned fieldSize = + Target.getTargetData().getTypeSize(field->getType()); + int padSize = ((i == N-1? cvsLayout->StructSize + : cvsLayout->MemberOffsets[i+1]) + - cvsLayout->MemberOffsets[i]) - fieldSize; + sizeSoFar += (fieldSize + padSize); + + // Now print the actual field value + printConstantValueOnly(field, padSize); + } + assert(sizeSoFar == cvsLayout->StructSize && + "Layout of constant struct may be incorrect!"); } - string getID(const Constant *CV) { - return getID(CV, "LLVMConst_", ".C_"); + else + printSingleConstantValue(CV); + + if (numPadBytesAfter) + PrintZeroBytesToPad(numPadBytesAfter); +} + +/// ConstantExprToString() - Convert a ConstantExpr to an asm expression +/// and return this as a string. +/// +std::string AsmPrinter::ConstantExprToString(const ConstantExpr* CE, + const TargetMachine& target) { + std::string S; + switch(CE->getOpcode()) { + case Instruction::GetElementPtr: + { // generate a symbolic expression for the byte address + const Value* ptrVal = CE->getOperand(0); + std::vector idxVec(CE->op_begin()+1, CE->op_end()); + const TargetData &TD = target.getTargetData(); + S += "(" + valToExprString(ptrVal, target) + ") + (" + + utostr(TD.getIndexedOffset(ptrVal->getType(),idxVec)) + ")"; + break; + } + + case Instruction::Cast: + // Support only non-converting casts for now, i.e., a no-op. + // This assertion is not a complete check. + assert(target.getTargetData().getTypeSize(CE->getType()) == + target.getTargetData().getTypeSize(CE->getOperand(0)->getType())); + S += "(" + valToExprString(CE->getOperand(0), target) + ")"; + break; + + case Instruction::Add: + S += ConstantArithExprToString(CE, target, ") + ("); + break; + + case Instruction::Sub: + S += ConstantArithExprToString(CE, target, ") - ("); + break; + + case Instruction::Mul: + S += ConstantArithExprToString(CE, target, ") * ("); + break; + + case Instruction::Div: + S += ConstantArithExprToString(CE, target, ") / ("); + break; + + case Instruction::Rem: + S += ConstantArithExprToString(CE, target, ") % ("); + break; + + case Instruction::And: + // Logical && for booleans; bitwise & otherwise + S += ConstantArithExprToString(CE, target, + ((CE->getType() == Type::BoolTy)? ") && (" : ") & (")); + break; + + case Instruction::Or: + // Logical || for booleans; bitwise | otherwise + S += ConstantArithExprToString(CE, target, + ((CE->getType() == Type::BoolTy)? ") || (" : ") | (")); + break; + + case Instruction::Xor: + // Bitwise ^ for all types + S += ConstantArithExprToString(CE, target, ") ^ ("); + break; + + default: + assert(0 && "Unsupported operator in ConstantExprToString()"); + break; } -}; + return S; +} + +/// valToExprString - Helper function for ConstantExprToString(). +/// Appends result to argument string S. +/// +std::string AsmPrinter::valToExprString(const Value* V, + const TargetMachine& target) { + std::string S; + bool failed = false; + if (const Constant* CV = dyn_cast(V)) { // symbolic or known + if (const ConstantBool *CB = dyn_cast(CV)) + S += std::string(CB == ConstantBool::True ? "1" : "0"); + else if (const ConstantSInt *CI = dyn_cast(CV)) + S += itostr(CI->getValue()); + else if (const ConstantUInt *CI = dyn_cast(CV)) + S += utostr(CI->getValue()); + else if (const ConstantFP *CFP = dyn_cast(CV)) + S += ftostr(CFP->getValue()); + else if (isa(CV)) + S += "0"; + else if (const ConstantPointerRef *CPR = dyn_cast(CV)) + S += valToExprString(CPR->getValue(), target); + else if (const ConstantExpr *CE = dyn_cast(CV)) + S += ConstantExprToString(CE, target); + else + failed = true; + } else if (const GlobalValue* GV = dyn_cast(V)) { + S += getID(GV); + } else + failed = true; + + if (failed) { + assert(0 && "Cannot convert value to string"); + S += ""; + } + return S; +} //===----------------------------------------------------------------------===// -// SparcFunctionAsmPrinter Code +// SparcAsmPrinter Code //===----------------------------------------------------------------------===// -struct SparcFunctionAsmPrinter : public FunctionPass, public AsmPrinter { - inline SparcFunctionAsmPrinter(std::ostream &os, const TargetMachine &t) - : AsmPrinter(os, t) {} +namespace { + + struct SparcAsmPrinter : public FunctionPass, public AsmPrinter { + inline SparcAsmPrinter(std::ostream &os, const TargetMachine &t) + : AsmPrinter(os, t) {} - virtual bool doInitialization(Module *M) { - startModule(M); - return false; - } + const Function *currFunction; - virtual bool runOnFunction(Function *F) { - startFunction(F); - emitFunction(F); - endFunction(F); - return false; - } + const char *getPassName() const { + return "Output Sparc Assembly for Functions"; + } - virtual bool doFinalization(Module *M) { - endModule(); - return false; - } + virtual bool doInitialization(Module &M) { + startModule(M); + return false; + } + + virtual bool runOnFunction(Function &F) { + currFunction = &F; + emitFunction(F); + return false; + } + + virtual bool doFinalization(Module &M) { + emitGlobals(M); + return false; + } - void emitFunction(const Function *F); -private : - void emitBasicBlock(const BasicBlock *BB); - void emitMachineInst(const MachineInstr *MI); + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + void emitFunction(const Function &F); + private : + void emitBasicBlock(const MachineBasicBlock &MBB); + void emitMachineInst(const MachineInstr *MI); - unsigned int printOperands(const MachineInstr *MI, unsigned int opNum); - void printOneOperand(const MachineOperand &Op); + unsigned int printOperands(const MachineInstr *MI, unsigned int opNum); + void printOneOperand(const MachineOperand &Op, MachineOpCode opCode); - bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum); - bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum); + 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... + unsigned getOperandMask(unsigned Opcode) { + switch (Opcode) { + case V9::SUBccr: + case V9::SUBcci: return 1 << 3; // Remove CC argument + default: return 0; // By default, don't hack operands... + } } - } -}; + + void emitGlobals(const Module &M); + void printGlobalVariable(const GlobalVariable *GV); + }; + +} // End anonymous namespace inline bool -SparcFunctionAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, - unsigned int opNum) { - switch (MI->getOpCode()) { - case JMPLCALL: - case JMPLRET: return (opNum == 0); - default: return false; +SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, + unsigned int opNum) { + switch (MI->getOpcode()) { + case V9::JMPLCALLr: + case V9::JMPLCALLi: + case V9::JMPLRETr: + case V9::JMPLRETi: + return (opNum == 0); + default: + return false; } } - inline bool -SparcFunctionAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, - unsigned int opNum) { - if (Target.getInstrInfo().isLoad(MI->getOpCode())) +SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, + unsigned int opNum) { + if (Target.getInstrInfo().isLoad(MI->getOpcode())) return (opNum == 0); - else if (Target.getInstrInfo().isStore(MI->getOpCode())) + else if (Target.getInstrInfo().isStore(MI->getOpcode())) return (opNum == 1); else return false; } -#define PrintOp1PlusOp2(Op1, Op2) \ - printOneOperand(Op1); \ +#define PrintOp1PlusOp2(mop1, mop2, opCode) \ + printOneOperand(mop1, opCode); \ toAsm << "+"; \ - printOneOperand(Op2); + printOneOperand(mop2, opCode); unsigned int -SparcFunctionAsmPrinter::printOperands(const MachineInstr *MI, +SparcAsmPrinter::printOperands(const MachineInstr *MI, unsigned int opNum) { - const MachineOperand& Op = MI->getOperand(opNum); + const MachineOperand& mop = MI->getOperand(opNum); - if (OpIsBranchTargetLabel(MI, opNum)) - { - PrintOp1PlusOp2(Op, MI->getOperand(opNum+1)); - return 2; - } - else if (OpIsMemoryAddressBase(MI, opNum)) - { - toAsm << "["; - PrintOp1PlusOp2(Op, MI->getOperand(opNum+1)); - toAsm << "]"; - return 2; - } - else - { - printOneOperand(Op); - return 1; - } + if (OpIsBranchTargetLabel(MI, opNum)) { + PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); + return 2; + } else if (OpIsMemoryAddressBase(MI, opNum)) { + toAsm << "["; + PrintOp1PlusOp2(mop, MI->getOperand(opNum+1), MI->getOpcode()); + toAsm << "]"; + return 2; + } else { + printOneOperand(mop, MI->getOpcode()); + return 1; + } } - void -SparcFunctionAsmPrinter::printOneOperand(const MachineOperand &op) +SparcAsmPrinter::printOneOperand(const MachineOperand &mop, + MachineOpCode opCode) { - switch (op.getOperandType()) + bool needBitsFlag = true; + + if (mop.isHiBits32()) + toAsm << "%lm("; + else if (mop.isLoBits32()) + toAsm << "%lo("; + else if (mop.isHiBits64()) + toAsm << "%hh("; + else if (mop.isLoBits64()) + toAsm << "%hm("; + else + needBitsFlag = false; + + switch (mop.getType()) { case MachineOperand::MO_VirtualRegister: case MachineOperand::MO_CCRegister: case MachineOperand::MO_MachineRegister: { - int RegNum = (int)op.getAllocatedRegNum(); + int regNum = (int)mop.getAllocatedRegNum(); - // better to print code with NULL registers than to die - if (RegNum == Target.getRegInfo().getInvalidRegNum()) { + if (regNum == Target.getRegInfo().getInvalidRegNum()) { + // better to print code with NULL registers than to die toAsm << ""; } else { - toAsm << "%" << Target.getRegInfo().getUnifiedRegName(RegNum); + toAsm << "%" << Target.getRegInfo().getUnifiedRegName(regNum); } break; } + case MachineOperand::MO_ConstantPoolIndex: + { + toAsm << ".CPI_" << currFunction->getName() + << "_" << mop.getConstantPoolIndex(); + break; + } + case MachineOperand::MO_PCRelativeDisp: { - const Value *Val = op.getVRegValue(); - if (!Val) - toAsm << "\t<*NULL Value*>"; - else if (const BasicBlock *BB = dyn_cast(Val)) + const Value *Val = mop.getVRegValue(); + assert(Val && "\tNULL Value in SparcAsmPrinter"); + + if (const BasicBlock *BB = dyn_cast(Val)) toAsm << getID(BB); else if (const Function *M = dyn_cast(Val)) toAsm << getID(M); @@ -317,31 +669,34 @@ SparcFunctionAsmPrinter::printOneOperand(const MachineOperand &op) else if (const Constant *CV = dyn_cast(Val)) toAsm << getID(CV); else - toAsm << ""; + assert(0 && "Unrecognized value in SparcAsmPrinter"); break; } case MachineOperand::MO_SignExtendedImmed: + toAsm << mop.getImmedValue(); + break; + case MachineOperand::MO_UnextendedImmed: - toAsm << (long)op.getImmedValue(); + toAsm << (uint64_t) mop.getImmedValue(); break; default: - toAsm << op; // use dump field + toAsm << mop; // use dump field break; } + + if (needBitsFlag) + toAsm << ")"; } +void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); -void -SparcFunctionAsmPrinter::emitMachineInst(const MachineInstr *MI) -{ - unsigned Opcode = MI->getOpCode(); - - if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG) + if (Target.getInstrInfo().isDummyPhiInstr(Opcode)) return; // IGNORE PHI NODES - toAsm << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t"; + toAsm << "\t" << Target.getInstrInfo().getName(Opcode) << "\t"; unsigned Mask = getOperandMask(Opcode); @@ -349,37 +704,41 @@ SparcFunctionAsmPrinter::emitMachineInst(const MachineInstr *MI) unsigned N = 1; for (unsigned OpNum = 0; OpNum < MI->getNumOperands(); OpNum += N) if (! ((1 << OpNum) & Mask)) { // Ignore this operand? - if (NeedComma) toAsm << ", "; // Handle comma outputing + if (NeedComma) toAsm << ", "; // Handle comma outputting NeedComma = true; N = printOperands(MI, OpNum); - } - else - N = 1; + } else + N = 1; toAsm << "\n"; + ++EmittedInsts; } -void -SparcFunctionAsmPrinter::emitBasicBlock(const BasicBlock *BB) -{ +void SparcAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) { // Emit a label for the basic block - toAsm << 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(); + toAsm << getID(MBB.getBasicBlock()) << ":\n"; // Loop over all of the instructions in the basic block... - for (; MII != MIE; ++MII) + for (MachineBasicBlock::const_iterator MII = MBB.begin(), MIE = MBB.end(); + MII != MIE; ++MII) emitMachineInst(*MII); - toAsm << "\n"; // Seperate BB's with newlines + toAsm << "\n"; // Separate BB's with newlines } -void -SparcFunctionAsmPrinter::emitFunction(const Function *M) -{ - string methName = getID(M); +void SparcAsmPrinter::emitFunction(const Function &F) { + std::string methName = getID(&F); toAsm << "!****** Outputing Function: " << methName << " ******\n"; + + // Emit constant pool for this function + const MachineConstantPool *MCP = MachineFunction::get(&F).getConstantPool(); + const std::vector &CP = MCP->getConstants(); + + enterSection(AsmPrinter::ReadOnlyData); + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + std::string cpiName = ".CPI_" + F.getName() + "_" + utostr(i); + printConstant(CP[i], cpiName); + } + enterSection(AsmPrinter::Text); toAsm << "\t.align\t4\n\t.global\t" << methName << "\n"; //toAsm << "\t.type\t" << methName << ",#function\n"; @@ -387,7 +746,8 @@ SparcFunctionAsmPrinter::emitFunction(const Function *M) toAsm << methName << ":\n"; // Output code for all of the basic blocks in the function... - for (Function::const_iterator I = M->begin(), E = M->end(); I != E; ++I) + MachineFunction &MF = MachineFunction::get(&F); + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E;++I) emitBasicBlock(*I); // Output a .size directive so the debugger knows the extents of the function @@ -399,323 +759,13 @@ SparcFunctionAsmPrinter::emitFunction(const Function *M) toAsm << "\n\n"; } -} // End anonymous namespace - -Pass *UltraSparc::getFunctionAsmPrinterPass(PassManager &PM, std::ostream &Out){ - return new SparcFunctionAsmPrinter(Out, *this); -} - - - - - -//===----------------------------------------------------------------------===// -// SparcFunctionAsmPrinter Code -//===----------------------------------------------------------------------===// - -namespace { - -class SparcModuleAsmPrinter : public Pass, public AsmPrinter { -public: - SparcModuleAsmPrinter(std::ostream &os, TargetMachine &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) { - assert(isStringCompatible(CPA) && "Array is not string compatible!"); - - 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; -} - -inline bool -ArrayTypeIsString(ArrayType* arrayType) -{ - return (arrayType->getElementType() == Type::UByteTy || - arrayType->getElementType() == Type::SByteTy); -} - -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 ".word"; - case Type::DoubleTyID: - return ".xword"; - case Type::ArrayTyID: - if (ArrayTypeIsString((ArrayType*) type)) - return ".ascii"; - else - return ""; - default: - return ""; - } -} - -// Get the size of the constant for the given target. -// If this is an unsized array, return 0. -// -inline unsigned int -ConstantToSize(const Constant* CV, const TargetMachine& target) -{ - if (ConstantArray* CPA = dyn_cast(CV)) - { - ArrayType *aty = cast(CPA->getType()); - if (ArrayTypeIsString(aty)) - return 1 + CPA->getNumOperands(); - } - - return target.findOptimalStorageSize(CV->getType()); -} - - - -// Align data larger than one L1 cache line on L1 cache line boundaries. -// Align all smaller data on the next higher 2^x boundary (4, 8, ...). -// -inline unsigned int -SizeToAlignment(unsigned int size, const TargetMachine& target) -{ - unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); - if (size > (unsigned) cacheLineSize / 2) - return cacheLineSize; - else - for (unsigned sz=1; /*no condition*/; sz *= 2) - if (sz >= size) - return sz; -} - -// Get the size of the type and then use SizeToAlignment. -// -inline unsigned int -TypeToAlignment(const Type* type, const TargetMachine& target) -{ - return SizeToAlignment(target.findOptimalStorageSize(type), target); -} - -// Get the size of the constant and then use SizeToAlignment. -// Handles strings as a special case; -inline unsigned int -ConstantToAlignment(const Constant* CV, const TargetMachine& target) -{ - if (ConstantArray* CPA = dyn_cast(CV)) - if (ArrayTypeIsString(cast(CPA->getType()))) - return SizeToAlignment(1 + CPA->getNumOperands(), target); - - return TypeToAlignment(CV->getType(), target); -} - - -// Print a single constant value. -void -SparcModuleAsmPrinter::printSingleConstant(const Constant* CV) -{ - assert(CV->getType() != Type::VoidTy && - CV->getType() != Type::TypeTy && - CV->getType() != Type::LabelTy && - "Unexpected type for Constant"); - - assert((!isa(CV) && ! isa(CV)) - && "Aggregate types should be handled outside this function"); - - toAsm << "\t" << TypeToDataDirective(CV->getType()) << "\t"; - - if (CV->getType()->isPrimitiveType()) - { - if (CV->getType()->isFloatingPoint()) { - // FP Constants are printed as integer constants to avoid losing - // precision... - double Val = cast(CV)->getValue(); - if (CV->getType() == Type::FloatTy) { - float FVal = (float)Val; - char *ProxyPtr = (char*)&FVal; // Abide by C TBAA rules - toAsm << *(unsigned int*)ProxyPtr; - } else if (CV->getType() == Type::DoubleTy) { - char *ProxyPtr = (char*)&Val; // Abide by C TBAA rules - toAsm << *(uint64_t*)ProxyPtr; - } else { - assert(0 && "Unknown floating point type!"); - } - - toAsm << "\t! " << CV->getType()->getDescription() - << " value: " << Val << "\n"; - } else { - WriteAsOperand(toAsm, CV, false, false) << "\n"; - } - } - else if (ConstantPointer* CPP = dyn_cast(CV)) - { - assert(CPP->isNullValue() && - "Cannot yet print non-null pointer constants to assembly"); - toAsm << "0\n"; - } - else if (isa(CV)) - { - assert(0 && "Cannot yet initialize pointer refs in assembly"); - } - else - { - assert(0 && "Unknown elementary type for constant"); - } -} - -// Print a constant value or values (it may be an aggregate). -// Uses printSingleConstant() to print each individual value. -void -SparcModuleAsmPrinter::printConstantValueOnly(const Constant* CV) -{ - ConstantArray *CPA = dyn_cast(CV); - - if (CPA && isStringCompatible(CPA)) - { // print the string alone and return - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << "\n"; - } - else if (CPA) - { // Not a string. Print the values in successive locations - const std::vector &constValues = CPA->getValues(); - for (unsigned i=1; i < constValues.size(); i++) - this->printConstantValueOnly(cast(constValues[i].get())); - } - else if (ConstantStruct *CPS = dyn_cast(CV)) - { // Print the fields in successive locations - const std::vector& constValues = CPS->getValues(); - for (unsigned i=1; i < constValues.size(); i++) - this->printConstantValueOnly(cast(constValues[i].get())); - } - else - this->printSingleConstant(CV); -} - -// Print a constant (which may be an aggregate) prefixed by all the -// appropriate directives. Uses printConstantValueOnly() to print the -// value or values. -void -SparcModuleAsmPrinter::printConstant(const Constant* CV, string valID) -{ - if (valID.length() == 0) - valID = getID(CV); +void SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) { + if (GV->hasExternalLinkage()) + toAsm << "\t.global\t" << getID(GV) << "\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); - if (CPA && isStringCompatible(CPA)) - { // print it as a string and return - toAsm << valID << ":\n"; - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << "\n"; - return; - } - - toAsm << "\t.type" << "\t" << valID << ",#object\n"; - - unsigned int constSize = ConstantToSize(CV, Target); - if (constSize) - toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n"; - - toAsm << valID << ":\n"; - - printConstantValueOnly(CV); -} - - -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()) + if (GV->hasInitializer() && ! GV->getInitializer()->isNullValue()) { printConstant(GV->getInitializer(), getID(GV)); - else { + } else { toAsm << "\t.align\t" << TypeToAlignment(GV->getType()->getElementType(), Target) << "\n"; toAsm << "\t.type\t" << getID(GV) << ",#object\n"; @@ -725,48 +775,25 @@ void SparcModuleAsmPrinter::printGlobalVariable(const GlobalVariable* GV) } } +void SparcAsmPrinter::emitGlobals(const Module &M) { + // Output global variables... + for (Module::const_giterator GI = M.gbegin(), GE = M.gend(); GI != GE; ++GI) + if (! GI->isExternal()) { + assert(GI->hasInitializer()); + if (GI->isConstant()) + enterSection(AsmPrinter::ReadOnlyData); // read-only, initialized data + else if (GI->getInitializer()->isNullValue()) + enterSection(AsmPrinter::ZeroInitRWData); // read-write zero data + else + enterSection(AsmPrinter::InitRWData); // read-write non-zero data + + printGlobalVariable(GI); + } -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, - // lets force these constants into the slot table so that we can get - // unique names for unnamed constants also. - // - 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! - - // Section 1 : Read-only data section (implies initialized) - enterSection(AsmPrinter::ReadOnlyData); - for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) - if ((*GI)->hasInitializer() && (*GI)->isConstant()) - printGlobalVariable(*GI); - - for (std::hash_set::const_iterator - I = moduleConstants.begin(), - E = moduleConstants.end(); I != E; ++I) - printConstant(*I); - - // Section 2 : Initialized read-write data section - enterSection(AsmPrinter::InitRWData); - for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) - if ((*GI)->hasInitializer() && ! (*GI)->isConstant()) - printGlobalVariable(*GI); - - // Section 3 : Uninitialized read-write data section - enterSection(AsmPrinter::UninitRWData); - for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI) - if (! (*GI)->hasInitializer()) - printGlobalVariable(*GI); - toAsm << "\n"; } -} // End anonymous namespace - -Pass *UltraSparc::getModuleAsmPrinterPass(PassManager &PM, std::ostream &Out) { - return new SparcModuleAsmPrinter(Out, *this); +FunctionPass *llvm::createAsmPrinterPass(std::ostream &Out, + const TargetMachine &TM) { + return new SparcAsmPrinter(Out, TM); }