// 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.
//
//===----------------------------------------------------------------------===//
namespace {
+//===----------------------------------------------------------------------===//
+// Code Shared By the two printer passes, as a mixin
+//===----------------------------------------------------------------------===//
-class SparcAsmPrinter {
+class AsmPrinter {
typedef std::hash_map<const Value*, int> 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,
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.
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:
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);
}
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<ArrayType>(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<ConstantSInt>(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<ArrayType>(CPA->getType())->getElementType();
- Result = "\"";
- for (unsigned i = 0; i < CPA->getNumOperands(); ++i) {
- unsigned char C = (ETy == Type::SByteTy) ?
- (unsigned char)cast<ConstantSInt>(CPA->getOperand(i))->getValue() :
- (unsigned char)cast<ConstantUInt>(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:
inline bool
-SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
+SparcMethodAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
unsigned int opNum) {
if (Target.getInstrInfo().isLoad(MI->getOpCode()))
return (opNum == 0);
printOneOperand(Op2);
unsigned int
-SparcAsmPrinter::printOperands(const MachineInstr *MI,
+SparcMethodAsmPrinter::printOperands(const MachineInstr *MI,
unsigned int opNum)
{
const MachineOperand& Op = MI->getOperand(opNum);
void
-SparcAsmPrinter::printOneOperand(const MachineOperand &op)
+SparcMethodAsmPrinter::printOneOperand(const MachineOperand &op)
{
switch (op.getOperandType())
{
void
-SparcAsmPrinter::emitMachineInst(const MachineInstr *MI)
+SparcMethodAsmPrinter::emitMachineInst(const MachineInstr *MI)
{
unsigned Opcode = MI->getOpCode();
}
void
-SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB)
+SparcMethodAsmPrinter::emitBasicBlock(const BasicBlock *BB)
{
// Emit a label for the basic block
toAsm << getID(BB) << ":\n";
}
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";
// 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<const Constant*> &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<ArrayType>(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<ConstantSInt>(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<ArrayType>(CPA->getType())->getElementType();
+ Result = "\"";
+ for (unsigned i = 0; i < CPA->getNumOperands(); ++i) {
+ unsigned char C = (ETy == Type::SByteTy) ?
+ (unsigned char)cast<ConstantSInt>(CPA->getOperand(i))->getValue() :
+ (unsigned char)cast<ConstantUInt>(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
// 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 &&
assert((! isa<ConstantArray>( CV) && ! isa<ConstantStruct>(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())
{
// 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<ConstantArray>(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<ConstantArray>(CV);
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<const Constant*> &MC) {
+ for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
+ if (!(*I)->isExternal()) {
+ const std::hash_set<const Constant*> &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())
}
-static void
-FoldConstants(const Module *M,
- std::hash_set<const Constant*>& moduleConstants)
-{
- for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
- if (! (*I)->isExternal())
- {
- const std::hash_set<const Constant*>& 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,
//
std::hash_set<const Constant*> 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!
//
if (GV->hasInitializer() && GV->isConstant())
{
if (GI == M->gbegin())
- enterSection(ReadOnlyData);
+ enterSection(AsmPrinter::ReadOnlyData);
printGlobalVariable(GV);
}
- }
+ }
for (std::hash_set<const Constant*>::const_iterator
I = moduleConstants.begin(),
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)
{
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);
-}
-