From 6275a0476867303f544b4bc16d382ea16265bc2c Mon Sep 17 00:00:00 2001 From: Misha Brukman Date: Thu, 13 Nov 2003 00:22:19 +0000 Subject: [PATCH] Substantially re-organized this file: * There is now only one pass to print out assembly instead of two * It is a FunctionPass * The Module-level printing of globals is now in doFinalization() method of the FunctionPass * The code has been reformatted to follow LLVM coding standards * Some comments, not all, were doxygenified * Last but not least, the function to create an instance of this pass is also no longer a method in the UltraSparc class. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@9953 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SparcV9/SparcV9AsmPrinter.cpp | 1168 +++++++++++----------- 1 file changed, 561 insertions(+), 607 deletions(-) diff --git a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp index 6af9836e29b..1e75acabbe4 100644 --- a/lib/Target/SparcV9/SparcV9AsmPrinter.cpp +++ b/lib/Target/SparcV9/SparcV9AsmPrinter.cpp @@ -33,91 +33,88 @@ #include "SparcInternals.h" #include +using namespace llvm; + namespace llvm { namespace { -Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); + Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); -class GlobalIdTable: public Annotation { - static AnnotationID AnnotId; - friend class AsmPrinter; // give access to AnnotId + class GlobalIdTable: public Annotation { + static AnnotationID AnnotId; + friend class AsmPrinter; // give access to AnnotId - typedef 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 - - GlobalIdTable(Module* M) : Annotation(AnnotId), Table(M, true) {} -}; + typedef 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 + + GlobalIdTable(Module* M) : Annotation(AnnotId), Table(M, true) {} + }; -AnnotationID GlobalIdTable::AnnotId = + AnnotationID GlobalIdTable::AnnotId = AnnotationManager::getID("ASM PRINTER GLOBAL TABLE ANNOT"); + + //===--------------------------------------------------------------------===// + // Utility functions -// Can we treat the specified array as a string? Only if it is an array of -// ubytes or non-negative sbytes. -// -static bool isStringCompatible(const ConstantArray *CVA) { - const Type *ETy = cast(CVA->getType())->getElementType(); - if (ETy == Type::UByteTy) return true; - if (ETy != Type::SByteTy) return false; + /// Can we treat the specified array as a string? Only if it is an array of + /// ubytes or non-negative sbytes. + /// + bool isStringCompatible(const ConstantArray *CVA) { + const Type *ETy = cast(CVA->getType())->getElementType(); + if (ETy == Type::UByteTy) return true; + if (ETy != Type::SByteTy) return false; - for (unsigned i = 0; i < CVA->getNumOperands(); ++i) - if (cast(CVA->getOperand(i))->getValue() < 0) - return false; + for (unsigned i = 0; i < CVA->getNumOperands(); ++i) + if (cast(CVA->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 std::string getAsCString(const ConstantArray *CVA) { - assert(isStringCompatible(CVA) && "Array is not string compatible!"); - - std::string Result; - const Type *ETy = cast(CVA->getType())->getElementType(); - 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 - Result += toOctal(C >> 6); - Result += toOctal(C >> 3); - Result += toOctal(C >> 0); - } + return true; } - Result += "\""; - return Result; -} + /// getAsCString - Return the specified array as a C compatible string, only + /// if the predicate isStringCompatible is true. + /// + std::string getAsCString(const ConstantArray *CVA) { + assert(isStringCompatible(CVA) && "Array is not string compatible!"); -inline bool -ArrayTypeIsString(const ArrayType* arrayType) -{ - return (arrayType->getElementType() == Type::UByteTy || - arrayType->getElementType() == Type::SByteTy); -} + std::string Result; + const Type *ETy = cast(CVA->getType())->getElementType(); + 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 += "\""; -inline const std::string -TypeToDataDirective(const Type* type) -{ - switch(type->getPrimitiveID()) + 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"; @@ -139,274 +136,169 @@ TypeToDataDirective(const Type* type) default: return ""; } -} + } -// Get the size of the type -// -inline unsigned int -TypeToSize(const Type* type, const TargetMachine& target) -{ - return target.findOptimalStorageSize(type); -} - -// 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)) - { + /// 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(); } - return TypeToSize(CV->getType(), target); -} + 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; -} + /// 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(TypeToSize(type, target), target); -} + /// 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); -} + /// 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 + +} // End namespace llvm + + + //===---------------------------------------------------------------------===// -// 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; - - enum Sections { - Unknown, - Text, - ReadOnlyData, - InitRWData, - ZeroInitRWData, - } CurSection; +namespace llvm { - 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); - } - } +namespace { - void - PrintZeroBytesToPad(int numBytes) - { - for ( ; numBytes >= 8; numBytes -= 8) - printSingleConstantValue(Constant::getNullValue(Type::ULongTy)); - - if (numBytes >= 4) - { - printSingleConstantValue(Constant::getNullValue(Type::UIntTy)); - numBytes -= 4; - } - - while (numBytes--) - printSingleConstantValue(Constant::getNullValue(Type::UByteTy)); - } - - // Print a single constant value. - void printSingleConstantValue(const Constant* CV) - { - assert(CV->getType() != Type::VoidTy && - CV->getType() != Type::TypeTy && - CV->getType() != Type::LabelTy && - "Unexpected type for Constant"); + class AsmPrinter { + GlobalIdTable* idTable; + public: + std::ostream &toAsm; + const TargetMachine &Target; - assert((!isa(CV) && ! isa(CV)) - && "Aggregate types should be handled outside this function"); + enum Sections { + Unknown, + Text, + ReadOnlyData, + InitRWData, + ZeroInitRWData, + } CurSection; + + AsmPrinter(std::ostream &os, const TargetMachine &T) + : idTable(0), toAsm(os), Target(T), CurSection(Unknown) {} - 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 { - WriteAsOperand(toAsm, CV, false, false) << "\n"; + // (start|end)(Module|Function) - Callback methods 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); } } - else - { - assert(0 && "Unknown elementary type for constant"); - } - } - // 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) - { - const ConstantArray *CVA = dyn_cast(CV); + void PrintZeroBytesToPad(int numBytes) { + for (/* no init */; numBytes >= 8; numBytes -= 8) + printSingleConstantValue(Constant::getNullValue(Type::ULongTy)); - if (CVA && isStringCompatible(CVA)) - { // print the string alone and return - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; - } - else if (CVA) - { // 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); + if (numBytes >= 4) { + printSingleConstantValue(Constant::getNullValue(Type::UIntTy)); + numBytes -= 4; } - assert(sizeSoFar == cvsLayout->StructSize && - "Layout of constant struct may be incorrect!"); + + while (numBytes--) + printSingleConstantValue(Constant::getNullValue(Type::UByteTy)); } - else - printSingleConstantValue(CV); - if (numPadBytesAfter) - PrintZeroBytesToPad(numPadBytesAfter); - } + /// Print a single constant value. + /// + void printSingleConstantValue(const Constant* CV); - // 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); + /// 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); - 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. + const ConstantArray *CVA = dyn_cast(CV); + if (CVA && isStringCompatible(CVA)) { + // 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"; - // Print .size and .type only if it is not a string. - const ConstantArray *CVA = dyn_cast(CV); - if (CVA && isStringCompatible(CVA)) - { // print it as a string and return toAsm << valID << ":\n"; - toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; - return; + + printConstantValueOnly(CV); + } + + void startFunction(Function &F) { + // Make sure the slot table has information about this function... + idTable->Table.incorporateFunction(&F); + } + void endFunction(Function &) { + idTable->Table.purgeFunction(); // Forget all about F + } + + // Check if a value is external or accessible from external code. + bool isExternal(const Value* V) { + const GlobalValue *GV = dyn_cast(V); + return GV && GV->hasExternalLinkage(); } - toAsm << "\t.type" << "\t" << valID << ",#object\n"; + // 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; - unsigned int constSize = ConstantToSize(CV, Target); - if (constSize) - toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n"; - - toAsm << valID << ":\n"; - - printConstantValueOnly(CV); - } - - void startFunction(Function &F) { - // Make sure the slot table has information about this function... - idTable->Table.incorporateFunction(&F); - } - void endFunction(Function &) { - idTable->Table.purgeFunction(); // Forget all about F - } - void endModule() { - } - - // Check if a value is external or accessible from external code. - bool isExternal(const Value* V) { - const GlobalValue *GV = dyn_cast(V); - return GV && GV->hasExternalLinkage(); - } - - // 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) + toAsm << "\n\t.section "; + switch (S) { default: assert(0 && "Bad section name!"); case Text: toAsm << "\".text\""; break; @@ -414,264 +306,381 @@ public: case InitRWData: toAsm << "\".data\",#alloc,#write"; break; case ZeroInitRWData: toAsm << "\".bss\",#alloc,#write"; break; } - toAsm << "\n"; - } + toAsm << "\n"; + } - static std::string getValidSymbolName(const std::string &S) { - std::string Result; + static std::string getValidSymbolName(const std::string &S) { + std::string Result; - // 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. - // - if (isdigit(S[0])) - Result = "ll"; + // 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. + // + if (isdigit(S[0])) + Result = "ll"; - for (unsigned i = 0; i < S.size(); ++i) - { + 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)); - } + else { + Result += '_'; + Result += char('0' + ((unsigned char)C >> 4)); + Result += char('0' + (C & 0xF)); + } } - return Result; - } - - // 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. - // - std::string getID(const Value *V, const char *Prefix, const char *FPrefix = 0) { - std::string Result = FPrefix ? FPrefix : ""; // "Forced prefix" - - Result += V->hasName() ? V->getName() : std::string(Prefix); - - // Qualify all internal names with a unique id. - if (!isExternal(V)) { - int valId = idTable->Table.getSlot(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); - - // Replace or prefix problem characters in the name - Result = getValidSymbolName(Result); + return Result; } - return Result; - } + // 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. + // + std::string getID(const Value *V, const char *Prefix, + const char *FPrefix = 0) + { + std::string Result = FPrefix ? FPrefix : ""; // "Forced prefix" + + Result += V->hasName() ? V->getName() : std::string(Prefix); + + // Qualify all internal names with a unique id. + if (!isExternal(V)) { + int valId = idTable->Table.getSlot(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); + + // Replace or prefix problem characters in the name + Result = getValidSymbolName(Result); + } + + return Result; + } - // getID Wrappers - Ensure consistent usage... - std::string getID(const Function *F) { - return getID(F, "LLVMFunction_"); - } - std::string getID(const BasicBlock *BB) { - return getID(BB, "LL", (".L_"+getID(BB->getParent())+"_").c_str()); - } - std::string getID(const GlobalVariable *GV) { - return getID(GV, "LLVMGlobal_"); - } - std::string getID(const Constant *CV) { - return getID(CV, "LLVMConst_", ".C_"); - } - 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 Wrappers - Ensure consistent usage... + std::string getID(const Function *F) { + return getID(F, "LLVMFunction_"); + } + std::string getID(const BasicBlock *BB) { + return getID(BB, "LL", (".L_"+getID(BB->getParent())+"_").c_str()); + } + std::string getID(const GlobalVariable *GV) { + return getID(GV, "LLVMGlobal_"); + } + std::string getID(const Constant *CV) { + return getID(CV, "LLVMConst_", ".C_"); + } + 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 ""; + } - // 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) + ")"; - } + // 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) + ")"; + } - // ConstantExprToString() - Convert a ConstantExpr to an asm expression - // and return this as a string. - std::string 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; + /// 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 + +} // End namespace llvm + +/// 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"); + + 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 { + WriteAsOperand(toAsm, CV, false, false) << "\n"; + } + } else { + assert(0 && "Unknown elementary type for constant"); + } +} - 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; +/// 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) +{ + const ConstantArray *CVA = dyn_cast(CV); - case Instruction::Add: - S += ConstantArithExprToString(CE, target, ") + ("); - break; + if (CVA && isStringCompatible(CVA)) { + // print the string alone and return + toAsm << "\t" << ".ascii" << "\t" << getAsCString(CVA) << "\n"; + } else if (CVA) { + // 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()); - case Instruction::Sub: - S += ConstantArithExprToString(CE, target, ") - ("); - break; + // 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); - case Instruction::Mul: - S += ConstantArithExprToString(CE, target, ") * ("); - break; + // Now print the actual field value + printConstantValueOnly(field, padSize); + } + assert(sizeSoFar == cvsLayout->StructSize && + "Layout of constant struct may be incorrect!"); + } + else + printSingleConstantValue(CV); - case Instruction::Div: - S += ConstantArithExprToString(CE, target, ") / ("); - break; + if (numPadBytesAfter) + PrintZeroBytesToPad(numPadBytesAfter); +} - 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()"); +/// 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; } - return S; + 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; } - // valToExprString - Helper function for ConstantExprToString(). - // Appends result to argument string S. - // - std::string valToExprString(const Value* V, const TargetMachine& target) { - std::string S; - bool failed = false; - if (const Constant* CV = dyn_cast(V)) { // symbolic or known + return S; +} - 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); - } +/// 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; + 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 llvm { - const Function *currFunction; +namespace { - const char *getPassName() const { - return "Output Sparc Assembly for Functions"; - } + 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) { - currFunction = &F; - startFunction(F); - emitFunction(F); - endFunction(F); - return false; - } - - virtual bool doFinalization(Module &M) { - endModule(); - return false; - } - - 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, MachineOpCode opCode); - - bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum); - bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum); - - unsigned getOperandMask(unsigned Opcode) { - switch (Opcode) { - case V9::SUBccr: - case V9::SUBcci: 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... + const char *getPassName() const { + return "Output Sparc Assembly for Functions"; } - } -}; + + virtual bool doInitialization(Module &M) { + startModule(M); + return false; + } + + virtual bool runOnFunction(Function &F) { + currFunction = &F; + startFunction(F); + emitFunction(F); + endFunction(F); + return false; + } + + virtual bool doFinalization(Module &M) { + emitGlobals(M); + return false; + } + + 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, MachineOpCode opCode); + + bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum); + bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum); + + 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) { +SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, + unsigned int opNum) { switch (MI->getOpCode()) { case V9::JMPLCALLr: case V9::JMPLCALLi: @@ -683,10 +692,9 @@ SparcFunctionAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI, } } - inline bool -SparcFunctionAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, - unsigned int opNum) { +SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, + unsigned int opNum) { if (Target.getInstrInfo().isLoad(MI->getOpCode())) return (opNum == 0); else if (Target.getInstrInfo().isStore(MI->getOpCode())) @@ -702,33 +710,28 @@ SparcFunctionAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI, printOneOperand(mop2, opCode); unsigned int -SparcFunctionAsmPrinter::printOperands(const MachineInstr *MI, +SparcAsmPrinter::printOperands(const MachineInstr *MI, unsigned int opNum) { const MachineOperand& mop = MI->getOperand(opNum); - 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; - } + 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 &mop, - MachineOpCode opCode) +SparcAsmPrinter::printOneOperand(const MachineOperand &mop, + MachineOpCode opCode) { bool needBitsFlag = true; @@ -770,7 +773,7 @@ SparcFunctionAsmPrinter::printOneOperand(const MachineOperand &mop, case MachineOperand::MO_PCRelativeDisp: { const Value *Val = mop.getVRegValue(); - assert(Val && "\tNULL Value in SparcFunctionAsmPrinter"); + assert(Val && "\tNULL Value in SparcAsmPrinter"); if (const BasicBlock *BB = dyn_cast(Val)) toAsm << getID(BB); @@ -781,7 +784,7 @@ SparcFunctionAsmPrinter::printOneOperand(const MachineOperand &mop, else if (const Constant *CV = dyn_cast(Val)) toAsm << getID(CV); else - assert(0 && "Unrecognized value in SparcFunctionAsmPrinter"); + assert(0 && "Unrecognized value in SparcAsmPrinter"); break; } @@ -802,9 +805,7 @@ SparcFunctionAsmPrinter::printOneOperand(const MachineOperand &mop, toAsm << ")"; } -void -SparcFunctionAsmPrinter::emitMachineInst(const MachineInstr *MI) -{ +void SparcAsmPrinter::emitMachineInst(const MachineInstr *MI) { unsigned Opcode = MI->getOpCode(); if (Target.getInstrInfo().isDummyPhiInstr(Opcode)) @@ -828,9 +829,7 @@ SparcFunctionAsmPrinter::emitMachineInst(const MachineInstr *MI) ++EmittedInsts; } -void -SparcFunctionAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) -{ +void SparcAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) { // Emit a label for the basic block toAsm << getID(MBB.getBasicBlock()) << ":\n"; @@ -841,9 +840,7 @@ SparcFunctionAsmPrinter::emitBasicBlock(const MachineBasicBlock &MBB) toAsm << "\n"; // Separate BB's with newlines } -void -SparcFunctionAsmPrinter::emitFunction(const Function &F) -{ +void SparcAsmPrinter::emitFunction(const Function &F) { std::string methName = getID(&F); toAsm << "!****** Outputing Function: " << methName << " ******\n"; @@ -877,64 +874,23 @@ SparcFunctionAsmPrinter::emitFunction(const Function &F) toAsm << "\n\n"; } -} // End anonymous namespace - -namespace llvm { - -Pass *UltraSparc::getFunctionAsmPrinterPass(std::ostream &Out) { - return new SparcFunctionAsmPrinter(Out, *this); -} - -} // End llvm namespace - - -//===----------------------------------------------------------------------===// -// SparcFunctionAsmPrinter Code -//===----------------------------------------------------------------------===// - -namespace { - -class SparcModuleAsmPrinter : public Pass, public AsmPrinter { -public: - SparcModuleAsmPrinter(std::ostream &os, TargetMachine &t) - : AsmPrinter(os, t) {} - - const char *getPassName() const { return "Output Sparc Assembly for Module"; } - - virtual bool run(Module &M) { - startModule(M); - emitGlobals(M); - endModule(); - return false; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } - -private: - void emitGlobals(const Module &M); - void printGlobalVariable(const GlobalVariable *GV); -}; - -void SparcModuleAsmPrinter::printGlobalVariable(const GlobalVariable* GV) -{ +void SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV) { if (GV->hasExternalLinkage()) toAsm << "\t.global\t" << getID(GV) << "\n"; - if (GV->hasInitializer() && ! GV->getInitializer()->isNullValue()) + 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"; toAsm << "\t.reserve\t" << getID(GV) << "," - << TypeToSize(GV->getType()->getElementType(), Target) + << Target.findOptimalStorageSize(GV->getType()->getElementType()) << "\n"; } } -void SparcModuleAsmPrinter::emitGlobals(const Module &M) { +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()) { @@ -952,10 +908,8 @@ void SparcModuleAsmPrinter::emitGlobals(const Module &M) { toAsm << "\n"; } -} // End anonymous namespace - -Pass *UltraSparc::getModuleAsmPrinterPass(std::ostream &Out) { - return new SparcModuleAsmPrinter(Out, *this); +FunctionPass *createAsmPrinterPass(std::ostream &Out, const TargetMachine &TM) { + return new SparcAsmPrinter(Out, TM); } } // End llvm namespace