Convert assembly emission over to a two pass approach.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@1662 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2002-02-03 23:41:08 +00:00
parent ccca2ed854
commit c19b8b10e5

View File

@ -4,7 +4,10 @@
// LLVM. The code in this file assumes that the specified module has already
// been compiled into the internal data structures of the Module.
//
// The entry point of this file is the UltraSparc::emitAssembly method.
// This code largely consists of two LLVM Pass's: a MethodPass and a Pass. The
// MethodPass is pipelined together with all of the rest of the code generation
// stages, and the Pass runs at the end to emit code for global variables and
// such.
//
//===----------------------------------------------------------------------===//
@ -24,17 +27,21 @@ using std::string;
namespace {
//===----------------------------------------------------------------------===//
// Code Shared By the two printer passes, as a mixin
//===----------------------------------------------------------------------===//
class SparcAsmPrinter {
class AsmPrinter {
typedef std::hash_map<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,
@ -42,28 +49,27 @@ class SparcAsmPrinter {
InitRWData,
UninitRWData,
} CurSection;
public:
inline SparcAsmPrinter(std::ostream &o, const Module *M, const UltraSparc &t)
: toAsm(o), Table(SlotCalculator(M, true)), Target(t), CurSection(Unknown) {
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();
}
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);
bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum);
bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum);
// enterSection - Use this method to enter a different section of the output
// executable. This is used to only output neccesary section transitions.
@ -84,7 +90,7 @@ private :
toAsm << "\n";
}
std::string getValidSymbolName(const string &S) {
static std::string getValidSymbolName(const string &S) {
string Result;
// Symbol names in Sparc assembly language have these rules:
@ -120,11 +126,13 @@ private :
if (V->hasName()) {
Result = FP + V->getName();
} else {
int valId = Table.getValSlot(V);
int valId = Table->getValSlot(V);
if (valId == -1) {
ValIdMapConstIterator I = valToIdMap.find(V);
valId = (I == valToIdMap.end())? (valToIdMap[V] = valToIdMap.size())
: (*I).second;
if (I == valToIdMap.end())
valId = valToIdMap[V] = valToIdMap.size();
else
valId = I->second;
}
Result = FP + string(Prefix) + itostr(valId);
}
@ -147,6 +155,45 @@ private :
string getID(const Constant *CV) {
return getID(CV, "LLVMConst_", ".C_");
}
};
//===----------------------------------------------------------------------===//
// SparcMethodAsmPrinter Code
//===----------------------------------------------------------------------===//
struct SparcMethodAsmPrinter : public MethodPass, public AsmPrinter {
inline SparcMethodAsmPrinter(std::ostream &os, const UltraSparc &t)
: AsmPrinter(os, t) {}
virtual bool doInitialization(Module *M) {
startModule(M);
return false;
}
virtual bool runOnMethod(Method *M) {
startMethod(M);
emitMethod(M);
endMethod(M);
return false;
}
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) {
@ -157,6 +204,215 @@ private :
}
};
inline bool
SparcMethodAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI,
unsigned int opNum) {
switch (MI->getOpCode()) {
case JMPLCALL:
case JMPLRET: return (opNum == 0);
default: return false;
}
}
inline bool
SparcMethodAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
unsigned int opNum) {
if (Target.getInstrInfo().isLoad(MI->getOpCode()))
return (opNum == 0);
else if (Target.getInstrInfo().isStore(MI->getOpCode()))
return (opNum == 1);
else
return false;
}
#define PrintOp1PlusOp2(Op1, Op2) \
printOneOperand(Op1); \
toAsm << "+"; \
printOneOperand(Op2);
unsigned int
SparcMethodAsmPrinter::printOperands(const MachineInstr *MI,
unsigned int opNum)
{
const MachineOperand& Op = MI->getOperand(opNum);
if (OpIsBranchTargetLabel(MI, opNum))
{
PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
return 2;
}
else if (OpIsMemoryAddressBase(MI, opNum))
{
toAsm << "[";
PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
toAsm << "]";
return 2;
}
else
{
printOneOperand(Op);
return 1;
}
}
void
SparcMethodAsmPrinter::printOneOperand(const MachineOperand &op)
{
switch (op.getOperandType())
{
case MachineOperand::MO_VirtualRegister:
case MachineOperand::MO_CCRegister:
case MachineOperand::MO_MachineRegister:
{
int RegNum = (int)op.getAllocatedRegNum();
// ****this code is temporary till NULL Values are fixed
if (RegNum == Target.getRegInfo().getInvalidRegNum()) {
toAsm << "<NULL VALUE>";
} else {
toAsm << "%" << Target.getRegInfo().getUnifiedRegName(RegNum);
}
break;
}
case MachineOperand::MO_PCRelativeDisp:
{
const Value *Val = op.getVRegValue();
if (!Val)
toAsm << "\t<*NULL Value*>";
else if (const BasicBlock *BB = dyn_cast<const BasicBlock>(Val))
toAsm << getID(BB);
else if (const Method *M = dyn_cast<const Method>(Val))
toAsm << getID(M);
else if (const GlobalVariable *GV=dyn_cast<const GlobalVariable>(Val))
toAsm << getID(GV);
else if (const Constant *CV = dyn_cast<const Constant>(Val))
toAsm << getID(CV);
else
toAsm << "<unknown value=" << Val << ">";
break;
}
case MachineOperand::MO_SignExtendedImmed:
case MachineOperand::MO_UnextendedImmed:
toAsm << (long)op.getImmedValue();
break;
default:
toAsm << op; // use dump field
break;
}
}
void
SparcMethodAsmPrinter::emitMachineInst(const MachineInstr *MI)
{
unsigned Opcode = MI->getOpCode();
if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG)
return; // IGNORE PHI NODES
toAsm << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t";
unsigned Mask = getOperandMask(Opcode);
bool NeedComma = false;
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
NeedComma = true;
N = printOperands(MI, OpNum);
}
else
N = 1;
toAsm << "\n";
}
void
SparcMethodAsmPrinter::emitBasicBlock(const BasicBlock *BB)
{
// 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();
// Loop over all of the instructions in the basic block...
for (; MII != MIE; ++MII)
emitMachineInst(*MII);
toAsm << "\n"; // Seperate BB's with newlines
}
void
SparcMethodAsmPrinter::emitMethod(const Method *M)
{
string methName = getID(M);
toAsm << "!****** Outputing Method: " << methName << " ******\n";
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";
toAsm << methName << ":\n";
// Output code for all of the basic blocks in the method...
for (Method::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
emitBasicBlock(*I);
// Output a .size directive so the debugger knows the extents of the function
toAsm << ".EndOf_" << methName << ":\n\t.size "
<< methName << ", .EndOf_"
<< methName << "-" << methName << "\n";
// Put some spaces between the methods
toAsm << "\n\n";
}
} // 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.
@ -219,185 +475,6 @@ static string getAsCString(ConstantArray *CPA) {
}
}
inline bool
SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI,
unsigned int opNum) {
switch (MI->getOpCode()) {
case JMPLCALL:
case JMPLRET: return (opNum == 0);
default: return false;
}
}
inline bool
SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
unsigned int opNum) {
if (Target.getInstrInfo().isLoad(MI->getOpCode()))
return (opNum == 0);
else if (Target.getInstrInfo().isStore(MI->getOpCode()))
return (opNum == 1);
else
return false;
}
#define PrintOp1PlusOp2(Op1, Op2) \
printOneOperand(Op1); \
toAsm << "+"; \
printOneOperand(Op2);
unsigned int
SparcAsmPrinter::printOperands(const MachineInstr *MI,
unsigned int opNum)
{
const MachineOperand& Op = MI->getOperand(opNum);
if (OpIsBranchTargetLabel(MI, opNum))
{
PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
return 2;
}
else if (OpIsMemoryAddressBase(MI, opNum))
{
toAsm << "[";
PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
toAsm << "]";
return 2;
}
else
{
printOneOperand(Op);
return 1;
}
}
void
SparcAsmPrinter::printOneOperand(const MachineOperand &op)
{
switch (op.getOperandType())
{
case MachineOperand::MO_VirtualRegister:
case MachineOperand::MO_CCRegister:
case MachineOperand::MO_MachineRegister:
{
int RegNum = (int)op.getAllocatedRegNum();
// ****this code is temporary till NULL Values are fixed
if (RegNum == Target.getRegInfo().getInvalidRegNum()) {
toAsm << "<NULL VALUE>";
} else {
toAsm << "%" << Target.getRegInfo().getUnifiedRegName(RegNum);
}
break;
}
case MachineOperand::MO_PCRelativeDisp:
{
const Value *Val = op.getVRegValue();
if (!Val)
toAsm << "\t<*NULL Value*>";
else if (const BasicBlock *BB = dyn_cast<const BasicBlock>(Val))
toAsm << getID(BB);
else if (const Method *M = dyn_cast<const Method>(Val))
toAsm << getID(M);
else if (const GlobalVariable *GV=dyn_cast<const GlobalVariable>(Val))
toAsm << getID(GV);
else if (const Constant *CV = dyn_cast<const Constant>(Val))
toAsm << getID(CV);
else
toAsm << "<unknown value=" << Val << ">";
break;
}
case MachineOperand::MO_SignExtendedImmed:
case MachineOperand::MO_UnextendedImmed:
toAsm << (long)op.getImmedValue();
break;
default:
toAsm << op; // use dump field
break;
}
}
void
SparcAsmPrinter::emitMachineInst(const MachineInstr *MI)
{
unsigned Opcode = MI->getOpCode();
if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG)
return; // IGNORE PHI NODES
toAsm << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t";
unsigned Mask = getOperandMask(Opcode);
bool NeedComma = false;
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
NeedComma = true;
N = printOperands(MI, OpNum);
}
else
N = 1;
toAsm << "\n";
}
void
SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB)
{
// 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();
// Loop over all of the instructions in the basic block...
for (; MII != MIE; ++MII)
emitMachineInst(*MII);
toAsm << "\n"; // Seperate BB's with newlines
}
void
SparcAsmPrinter::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);
toAsm << "\t.align\t4\n\t.global\t" << methName << "\n";
//toAsm << "\t.type\t" << methName << ",#function\n";
toAsm << "\t.type\t" << methName << ", 2\n";
toAsm << methName << ":\n";
// Output code for all of the basic blocks in the method...
for (Method::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
emitBasicBlock(*I);
// Output a .size directive so the debugger knows the extents of the function
toAsm << ".EndOf_" << methName << ":\n\t.size "
<< methName << ", .EndOf_"
<< methName << "-" << methName << "\n";
// Put some spaces between the methods
toAsm << "\n\n";
// Forget all about M.
Table.purgeMethod();
}
inline bool
ArrayTypeIsString(ArrayType* arrayType)
{
@ -488,7 +565,7 @@ ConstantToAlignment(const Constant* CV, const TargetMachine& target)
// Print a single constant value.
void
SparcAsmPrinter::printSingleConstant(const Constant* CV)
SparcModuleAsmPrinter::printSingleConstant(const Constant* CV)
{
assert(CV->getType() != Type::VoidTy &&
CV->getType() != Type::TypeTy &&
@ -498,8 +575,7 @@ SparcAsmPrinter::printSingleConstant(const Constant* CV)
assert((! isa<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())
{
@ -526,7 +602,7 @@ SparcAsmPrinter::printSingleConstant(const Constant* CV)
// Print a constant value or values (it may be an aggregate).
// Uses printSingleConstant() to print each individual value.
void
SparcAsmPrinter::printConstantValueOnly(const Constant* CV)
SparcModuleAsmPrinter::printConstantValueOnly(const Constant* CV)
{
ConstantArray *CPA = dyn_cast<ConstantArray>(CV);
@ -554,13 +630,12 @@ SparcAsmPrinter::printConstantValueOnly(const Constant* CV)
// appropriate directives. Uses printConstantValueOnly() to print the
// value or values.
void
SparcAsmPrinter::printConstant(const Constant* CV, string valID)
SparcModuleAsmPrinter::printConstant(const Constant* CV, string valID)
{
if (valID.length() == 0)
valID = getID(CV);
toAsm << "\t.align\t" << ConstantToAlignment(CV, Target)
<< "\n";
toAsm << "\t.align\t" << ConstantToAlignment(CV, Target) << "\n";
// Print .size and .type only if it is not a string.
ConstantArray *CPA = dyn_cast<ConstantArray>(CV);
@ -575,25 +650,33 @@ SparcAsmPrinter::printConstant(const Constant* CV, string valID)
unsigned int constSize = ConstantToSize(CV, Target);
if (constSize)
toAsm << "\t.size" << "\t" << valID << ","
<< constSize << "\n";
toAsm << "\t.size" << "\t" << valID << "," << constSize << "\n";
toAsm << valID << ":\n";
this->printConstantValueOnly(CV);
printConstantValueOnly(CV);
}
void
SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV)
void SparcModuleAsmPrinter::FoldConstants(const Module *M,
std::hash_set<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())
@ -602,23 +685,7 @@ SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV)
}
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,
@ -627,7 +694,7 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M)
//
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!
//
@ -638,10 +705,10 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M)
if (GV->hasInitializer() && GV->isConstant())
{
if (GI == M->gbegin())
enterSection(ReadOnlyData);
enterSection(AsmPrinter::ReadOnlyData);
printGlobalVariable(GV);
}
}
}
for (std::hash_set<const Constant*>::const_iterator
I = moduleConstants.begin(),
@ -655,11 +722,11 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M)
if (GV->hasInitializer() && ! GV->isConstant())
{
if (GI == M->gbegin())
enterSection(InitRWData);
enterSection(AsmPrinter::InitRWData);
printGlobalVariable(GV);
}
}
}
// Uninitialized read-write data section
for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI)
{
@ -667,38 +734,16 @@ SparcAsmPrinter::emitGlobalsAndConstants(const Module *M)
if (! GV->hasInitializer())
{
if (GI == M->gbegin())
enterSection(UninitRWData);
enterSection(AsmPrinter::UninitRWData);
printGlobalVariable(GV);
}
}
}
toAsm << "\n";
}
} // End anonymous namespace
//
// emitAssembly - Output assembly language code (a .s file) for global
// components of the specified module. This assumes that methods have been
// previously output.
//
void
UltraSparc::emitAssembly(const Method *M, std::ostream &OutStr) const
{
SparcAsmPrinter Print(OutStr, M->getParent(), *this);
Print.emitMethod(M);
Pass *UltraSparc::getModuleAsmPrinterPass(PassManager &PM, std::ostream &Out) {
return new SparcModuleAsmPrinter(Out, *this);
}
//
// emitAssembly - Output assembly language code (a .s file) for the specified
// method. The specified method must have been compiled before this may be
// used.
//
void
UltraSparc::emitAssembly(const Module *M, std::ostream &OutStr) const
{
SparcAsmPrinter Print(OutStr, M, *this);
Print.emitGlobalsAndConstants(M);
}