From 4acfd039f92fea3b02227020e4e28f2e5db2d92e Mon Sep 17 00:00:00 2001 From: Brian Gaeke Date: Thu, 4 Mar 2004 06:00:41 +0000 Subject: [PATCH] Asm printer support, based on x86 - only prints mnemonics for now git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12113 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Sparc/Sparc.h | 4 +- lib/Target/Sparc/SparcAsmPrinter.cpp | 458 ++++++++++++++++++++ lib/Target/Sparc/SparcTargetMachine.cpp | 2 + lib/Target/SparcV8/SparcV8.h | 4 +- lib/Target/SparcV8/SparcV8AsmPrinter.cpp | 458 ++++++++++++++++++++ lib/Target/SparcV8/SparcV8TargetMachine.cpp | 2 + 6 files changed, 924 insertions(+), 4 deletions(-) create mode 100644 lib/Target/Sparc/SparcAsmPrinter.cpp create mode 100644 lib/Target/SparcV8/SparcV8AsmPrinter.cpp diff --git a/lib/Target/Sparc/Sparc.h b/lib/Target/Sparc/Sparc.h index efe3d9f3eff..1cade3cd854 100644 --- a/lib/Target/Sparc/Sparc.h +++ b/lib/Target/Sparc/Sparc.h @@ -23,8 +23,8 @@ namespace llvm { class TargetMachine; FunctionPass *createSparcV8SimpleInstructionSelector(TargetMachine &TM); -// FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS, -// TargetMachine &TM); + FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS, + TargetMachine &TM); } // end namespace llvm; diff --git a/lib/Target/Sparc/SparcAsmPrinter.cpp b/lib/Target/Sparc/SparcAsmPrinter.cpp new file mode 100644 index 00000000000..9adb0e7b221 --- /dev/null +++ b/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -0,0 +1,458 @@ +//===-- SparcV8AsmPrinter.cpp - SparcV8 LLVM assembly writer --------------===// +// +// 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 contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format Sparc V8 assembly language. +// +//===----------------------------------------------------------------------===// + +#include "SparcV8.h" +#include "SparcV8InstrInfo.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Mangler.h" +#include "Support/Statistic.h" +#include "Support/StringExtras.h" +#include "Support/CommandLine.h" +using namespace llvm; + +namespace { + Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); + + struct V8Printer : public MachineFunctionPass { + /// Output stream on which we're printing assembly code. + /// + std::ostream &O; + + /// Target machine description which we query for reg. names, data + /// layout, etc. + /// + TargetMachine &TM; + + /// Name-mangler for global names. + /// + Mangler *Mang; + + V8Printer(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { } + + /// We name each basic block in a Function with a unique number, so + /// that we can consistently refer to them later. This is cleared + /// at the beginning of each call to runOnMachineFunction(). + /// + typedef std::map ValueMapTy; + ValueMapTy NumberForBB; + + /// Cache of mangled name for current function. This is + /// recalculated at the beginning of each call to + /// runOnMachineFunction(). + /// + std::string CurrentFnName; + + virtual const char *getPassName() const { + return "SparcV8 Assembly Printer"; + } + + void emitConstantValueOnly(const Constant *CV); + void emitGlobalConstant(const Constant *CV); + void printConstantPool(MachineConstantPool *MCP); + void printMachineInstruction(const MachineInstr *MI); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + +/// createSparcV8CodePrinterPass - Returns a pass that prints the SparcV8 +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *llvm::createSparcV8CodePrinterPass (std::ostream &o, + TargetMachine &tm) { + return new V8Printer(o, tm); +} + +/// toOctal - Convert the low order bits of X into an octal digit. +/// +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 void printAsCString(std::ostream &O, const ConstantArray *CVA) { + assert(CVA->isString() && "Array is not string compatible!"); + + O << "\""; + for (unsigned i = 0; i != CVA->getNumOperands(); ++i) { + unsigned char C = cast(CVA->getOperand(i))->getRawValue(); + + if (C == '"') { + O << "\\\""; + } else if (C == '\\') { + O << "\\\\"; + } else if (isprint(C)) { + O << C; + } else { + switch(C) { + case '\b': O << "\\b"; break; + case '\f': O << "\\f"; break; + case '\n': O << "\\n"; break; + case '\r': O << "\\r"; break; + case '\t': O << "\\t"; break; + default: + O << '\\'; + O << toOctal(C >> 6); + O << toOctal(C >> 3); + O << toOctal(C >> 0); + break; + } + } + } + O << "\""; +} + +// Print out the specified constant, without a storage class. Only the +// constants valid in constant expressions can occur here. +void V8Printer::emitConstantValueOnly(const Constant *CV) { + if (CV->isNullValue()) + O << "0"; + else if (const ConstantBool *CB = dyn_cast(CV)) { + assert(CB == ConstantBool::True); + O << "1"; + } else if (const ConstantSInt *CI = dyn_cast(CV)) + if (((CI->getValue() << 32) >> 32) == CI->getValue()) + O << CI->getValue(); + else + O << (unsigned long long)CI->getValue(); + else if (const ConstantUInt *CI = dyn_cast(CV)) + O << CI->getValue(); + else if (const ConstantPointerRef *CPR = dyn_cast(CV)) + // This is a constant address for a global variable or function. Use the + // name of the variable or function as the address value. + O << Mang->getValueName(CPR->getValue()); + else if (const ConstantExpr *CE = dyn_cast(CV)) { + const TargetData &TD = TM.getTargetData(); + switch(CE->getOpcode()) { + case Instruction::GetElementPtr: { + // generate a symbolic expression for the byte address + const Constant *ptrVal = CE->getOperand(0); + std::vector idxVec(CE->op_begin()+1, CE->op_end()); + if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) { + O << "("; + emitConstantValueOnly(ptrVal); + O << ") + " << Offset; + } else { + emitConstantValueOnly(ptrVal); + } + break; + } + case Instruction::Cast: { + // Support only non-converting or widening casts for now, that is, ones + // that do not involve a change in value. This assertion is really gross, + // and may not even be a complete check. + Constant *Op = CE->getOperand(0); + const Type *OpTy = Op->getType(), *Ty = CE->getType(); + + // Pointers on ILP32 machines can be losslessly converted back and + // forth into 32-bit or wider integers, regardless of signedness. + assert(((isa(OpTy) + && (Ty == Type::LongTy || Ty == Type::ULongTy + || Ty == Type::IntTy || Ty == Type::UIntTy)) + || (isa(Ty) + && (OpTy == Type::LongTy || OpTy == Type::ULongTy + || OpTy == Type::IntTy || OpTy == Type::UIntTy)) + || (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy)) + && OpTy->isLosslesslyConvertibleTo(Ty)))) + && "FIXME: Don't yet support this kind of constant cast expr"); + O << "("; + emitConstantValueOnly(Op); + O << ")"; + break; + } + case Instruction::Add: + O << "("; + emitConstantValueOnly(CE->getOperand(0)); + O << ") + ("; + emitConstantValueOnly(CE->getOperand(1)); + O << ")"; + break; + default: + assert(0 && "Unsupported operator!"); + } + } else { + assert(0 && "Unknown constant value!"); + } +} + +// Print a constant value or values, with the appropriate storage class as a +// prefix. +void V8Printer::emitGlobalConstant(const Constant *CV) { + const TargetData &TD = TM.getTargetData(); + + if (CV->isNullValue()) { + O << "\t.zero\t " << TD.getTypeSize(CV->getType()) << "\n"; + return; + } else if (const ConstantArray *CVA = dyn_cast(CV)) { + if (CVA->isString()) { + O << "\t.ascii\t"; + printAsCString(O, CVA); + O << "\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++) + emitGlobalConstant(cast(constValues[i].get())); + } + return; + } else if (const ConstantStruct *CVS = dyn_cast(CV)) { + // Print the fields in successive locations. Pad to align if needed! + const StructLayout *cvsLayout = TD.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 = TD.getTypeSize(field->getType()); + unsigned padSize = ((i == N-1? cvsLayout->StructSize + : cvsLayout->MemberOffsets[i+1]) + - cvsLayout->MemberOffsets[i]) - fieldSize; + sizeSoFar += fieldSize + padSize; + + // Now print the actual field value + emitGlobalConstant(field); + + // Insert the field padding unless it's zero bytes... + if (padSize) + O << "\t.zero\t " << padSize << "\n"; + } + assert(sizeSoFar == cvsLayout->StructSize && + "Layout of constant struct may be incorrect!"); + return; + } else if (const ConstantFP *CFP = dyn_cast(CV)) { + // FP Constants are printed as integer constants to avoid losing + // precision... + double Val = CFP->getValue(); + switch (CFP->getType()->getPrimitiveID()) { + default: assert(0 && "Unknown floating point type!"); + case Type::FloatTyID: { + union FU { // Abide by C TBAA rules + float FVal; + unsigned UVal; + } U; + U.FVal = Val; + O << ".long\t" << U.UVal << "\t# float " << Val << "\n"; + return; + } + case Type::DoubleTyID: { + union DU { // Abide by C TBAA rules + double FVal; + uint64_t UVal; + } U; + U.FVal = Val; + O << ".quad\t" << U.UVal << "\t# double " << Val << "\n"; + return; + } + } + } + + const Type *type = CV->getType(); + O << "\t"; + switch (type->getPrimitiveID()) { + case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: + O << ".byte"; + break; + case Type::UShortTyID: case Type::ShortTyID: + O << ".word"; + break; + case Type::FloatTyID: case Type::PointerTyID: + case Type::UIntTyID: case Type::IntTyID: + O << ".long"; + break; + case Type::DoubleTyID: + case Type::ULongTyID: case Type::LongTyID: + O << ".quad"; + break; + default: + assert (0 && "Can't handle printing this type of thing"); + break; + } + O << "\t"; + emitConstantValueOnly(CV); + O << "\n"; +} + +/// printConstantPool - Print to the current output stream assembly +/// representations of the constants in the constant pool MCP. This is +/// used to print out constants which have been "spilled to memory" by +/// the code generator. +/// +void V8Printer::printConstantPool(MachineConstantPool *MCP) { + const std::vector &CP = MCP->getConstants(); + const TargetData &TD = TM.getTargetData(); + + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.section .rodata\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) + << "\n"; + O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t#" + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); + } +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool V8Printer::runOnMachineFunction(MachineFunction &MF) { + // BBNumber is used here so that a given Printer will never give two + // BBs the same name. (If you have a better way, please let me know!) + static unsigned BBNumber = 0; + + O << "\n\n"; + // What's my mangled name? + CurrentFnName = Mang->getValueName(MF.getFunction()); + + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool()); + + // Print out labels for the function. + O << "\t.text\n"; + O << "\t.align 16\n"; + O << "\t.globl\t" << CurrentFnName << "\n"; + O << "\t.type\t" << CurrentFnName << ", @function\n"; + O << CurrentFnName << ":\n"; + + // Number each basic block so that we can consistently refer to them + // in PC-relative references. + NumberForBB.clear(); + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + NumberForBB[I->getBasicBlock()] = BBNumber++; + } + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + O << ".LBB" << NumberForBB[I->getBasicBlock()] << ":\t# " + << I->getBasicBlock()->getName() << "\n"; + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printMachineInstruction(II); + } + } + + // We didn't modify anything. + return false; +} + +/// printMachineInstruction -- Print out a single SparcV8 LLVM instruction +/// MI in GAS syntax to the current output stream. +/// +void V8Printer::printMachineInstruction(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + const TargetInstrInfo &TII = TM.getInstrInfo(); + const TargetInstrDescriptor &Desc = TII.get(Opcode); + O << Desc.Name << "\n"; // not yet done +} + +bool V8Printer::doInitialization(Module &M) { + Mang = new Mangler(M); + return false; // success +} + +// SwitchSection - Switch to the specified section of the executable if we are +// not already in it! +// +static void SwitchSection(std::ostream &OS, std::string &CurSection, + const char *NewSection) { + if (CurSection != NewSection) { + CurSection = NewSection; + if (!CurSection.empty()) + OS << "\t" << NewSection << "\n"; + } +} + +bool V8Printer::doFinalization(Module &M) { + const TargetData &TD = TM.getTargetData(); + std::string CurSection; + + // Print out module-level global variables here. + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) + if (I->hasInitializer()) { // External global require no code + O << "\n\n"; + std::string name = Mang->getValueName(I); + Constant *C = I->getInitializer(); + unsigned Size = TD.getTypeSize(C->getType()); + unsigned Align = TD.getTypeAlignment(C->getType()); + + if (C->isNullValue() && + (I->hasLinkOnceLinkage() || I->hasInternalLinkage() || + I->hasWeakLinkage() /* FIXME: Verify correct */)) { + SwitchSection(O, CurSection, ".data"); + if (I->hasInternalLinkage()) + O << "\t.local " << name << "\n"; + + O << "\t.comm " << name << "," << TD.getTypeSize(C->getType()) + << "," << (unsigned)TD.getTypeAlignment(C->getType()); + O << "\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << "\n"; + } else { + switch (I->getLinkage()) { + case GlobalValue::LinkOnceLinkage: + case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak. + // Nonnull linkonce -> weak + O << "\t.weak " << name << "\n"; + SwitchSection(O, CurSection, ""); + O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n"; + break; + + case GlobalValue::AppendingLinkage: + // FIXME: appending linkage variables should go into a section of + // their name or something. For now, just emit them as external. + case GlobalValue::ExternalLinkage: + // If external or appending, declare as a global symbol + O << "\t.globl " << name << "\n"; + // FALL THROUGH + case GlobalValue::InternalLinkage: + if (C->isNullValue()) + SwitchSection(O, CurSection, ".bss"); + else + SwitchSection(O, CurSection, ".data"); + break; + } + + O << "\t.align " << Align << "\n"; + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << "," << Size << "\n"; + O << name << ":\t\t\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << " = "; + WriteAsOperand(O, C, false, false, &M); + O << "\n"; + emitGlobalConstant(C); + } + } + + delete Mang; + return false; // success +} diff --git a/lib/Target/Sparc/SparcTargetMachine.cpp b/lib/Target/Sparc/SparcTargetMachine.cpp index f9a499dca43..581c535ccb2 100644 --- a/lib/Target/Sparc/SparcTargetMachine.cpp +++ b/lib/Target/Sparc/SparcTargetMachine.cpp @@ -53,6 +53,8 @@ bool SparcV8TargetMachine::addPassesToEmitAssembly(PassManager &PM, // are producing. PM.add(createMachineFunctionPrinterPass(&Out)); + PM.add(createSparcV8CodePrinterPass(Out, *this)); + PM.add(createMachineCodeDeleter()); return false; } diff --git a/lib/Target/SparcV8/SparcV8.h b/lib/Target/SparcV8/SparcV8.h index efe3d9f3eff..1cade3cd854 100644 --- a/lib/Target/SparcV8/SparcV8.h +++ b/lib/Target/SparcV8/SparcV8.h @@ -23,8 +23,8 @@ namespace llvm { class TargetMachine; FunctionPass *createSparcV8SimpleInstructionSelector(TargetMachine &TM); -// FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS, -// TargetMachine &TM); + FunctionPass *createSparcV8CodePrinterPass(std::ostream &OS, + TargetMachine &TM); } // end namespace llvm; diff --git a/lib/Target/SparcV8/SparcV8AsmPrinter.cpp b/lib/Target/SparcV8/SparcV8AsmPrinter.cpp new file mode 100644 index 00000000000..9adb0e7b221 --- /dev/null +++ b/lib/Target/SparcV8/SparcV8AsmPrinter.cpp @@ -0,0 +1,458 @@ +//===-- SparcV8AsmPrinter.cpp - SparcV8 LLVM assembly writer --------------===// +// +// 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 contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format Sparc V8 assembly language. +// +//===----------------------------------------------------------------------===// + +#include "SparcV8.h" +#include "SparcV8InstrInfo.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Mangler.h" +#include "Support/Statistic.h" +#include "Support/StringExtras.h" +#include "Support/CommandLine.h" +using namespace llvm; + +namespace { + Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); + + struct V8Printer : public MachineFunctionPass { + /// Output stream on which we're printing assembly code. + /// + std::ostream &O; + + /// Target machine description which we query for reg. names, data + /// layout, etc. + /// + TargetMachine &TM; + + /// Name-mangler for global names. + /// + Mangler *Mang; + + V8Printer(std::ostream &o, TargetMachine &tm) : O(o), TM(tm) { } + + /// We name each basic block in a Function with a unique number, so + /// that we can consistently refer to them later. This is cleared + /// at the beginning of each call to runOnMachineFunction(). + /// + typedef std::map ValueMapTy; + ValueMapTy NumberForBB; + + /// Cache of mangled name for current function. This is + /// recalculated at the beginning of each call to + /// runOnMachineFunction(). + /// + std::string CurrentFnName; + + virtual const char *getPassName() const { + return "SparcV8 Assembly Printer"; + } + + void emitConstantValueOnly(const Constant *CV); + void emitGlobalConstant(const Constant *CV); + void printConstantPool(MachineConstantPool *MCP); + void printMachineInstruction(const MachineInstr *MI); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + }; +} // end of anonymous namespace + +/// createSparcV8CodePrinterPass - Returns a pass that prints the SparcV8 +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *llvm::createSparcV8CodePrinterPass (std::ostream &o, + TargetMachine &tm) { + return new V8Printer(o, tm); +} + +/// toOctal - Convert the low order bits of X into an octal digit. +/// +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 void printAsCString(std::ostream &O, const ConstantArray *CVA) { + assert(CVA->isString() && "Array is not string compatible!"); + + O << "\""; + for (unsigned i = 0; i != CVA->getNumOperands(); ++i) { + unsigned char C = cast(CVA->getOperand(i))->getRawValue(); + + if (C == '"') { + O << "\\\""; + } else if (C == '\\') { + O << "\\\\"; + } else if (isprint(C)) { + O << C; + } else { + switch(C) { + case '\b': O << "\\b"; break; + case '\f': O << "\\f"; break; + case '\n': O << "\\n"; break; + case '\r': O << "\\r"; break; + case '\t': O << "\\t"; break; + default: + O << '\\'; + O << toOctal(C >> 6); + O << toOctal(C >> 3); + O << toOctal(C >> 0); + break; + } + } + } + O << "\""; +} + +// Print out the specified constant, without a storage class. Only the +// constants valid in constant expressions can occur here. +void V8Printer::emitConstantValueOnly(const Constant *CV) { + if (CV->isNullValue()) + O << "0"; + else if (const ConstantBool *CB = dyn_cast(CV)) { + assert(CB == ConstantBool::True); + O << "1"; + } else if (const ConstantSInt *CI = dyn_cast(CV)) + if (((CI->getValue() << 32) >> 32) == CI->getValue()) + O << CI->getValue(); + else + O << (unsigned long long)CI->getValue(); + else if (const ConstantUInt *CI = dyn_cast(CV)) + O << CI->getValue(); + else if (const ConstantPointerRef *CPR = dyn_cast(CV)) + // This is a constant address for a global variable or function. Use the + // name of the variable or function as the address value. + O << Mang->getValueName(CPR->getValue()); + else if (const ConstantExpr *CE = dyn_cast(CV)) { + const TargetData &TD = TM.getTargetData(); + switch(CE->getOpcode()) { + case Instruction::GetElementPtr: { + // generate a symbolic expression for the byte address + const Constant *ptrVal = CE->getOperand(0); + std::vector idxVec(CE->op_begin()+1, CE->op_end()); + if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) { + O << "("; + emitConstantValueOnly(ptrVal); + O << ") + " << Offset; + } else { + emitConstantValueOnly(ptrVal); + } + break; + } + case Instruction::Cast: { + // Support only non-converting or widening casts for now, that is, ones + // that do not involve a change in value. This assertion is really gross, + // and may not even be a complete check. + Constant *Op = CE->getOperand(0); + const Type *OpTy = Op->getType(), *Ty = CE->getType(); + + // Pointers on ILP32 machines can be losslessly converted back and + // forth into 32-bit or wider integers, regardless of signedness. + assert(((isa(OpTy) + && (Ty == Type::LongTy || Ty == Type::ULongTy + || Ty == Type::IntTy || Ty == Type::UIntTy)) + || (isa(Ty) + && (OpTy == Type::LongTy || OpTy == Type::ULongTy + || OpTy == Type::IntTy || OpTy == Type::UIntTy)) + || (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy)) + && OpTy->isLosslesslyConvertibleTo(Ty)))) + && "FIXME: Don't yet support this kind of constant cast expr"); + O << "("; + emitConstantValueOnly(Op); + O << ")"; + break; + } + case Instruction::Add: + O << "("; + emitConstantValueOnly(CE->getOperand(0)); + O << ") + ("; + emitConstantValueOnly(CE->getOperand(1)); + O << ")"; + break; + default: + assert(0 && "Unsupported operator!"); + } + } else { + assert(0 && "Unknown constant value!"); + } +} + +// Print a constant value or values, with the appropriate storage class as a +// prefix. +void V8Printer::emitGlobalConstant(const Constant *CV) { + const TargetData &TD = TM.getTargetData(); + + if (CV->isNullValue()) { + O << "\t.zero\t " << TD.getTypeSize(CV->getType()) << "\n"; + return; + } else if (const ConstantArray *CVA = dyn_cast(CV)) { + if (CVA->isString()) { + O << "\t.ascii\t"; + printAsCString(O, CVA); + O << "\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++) + emitGlobalConstant(cast(constValues[i].get())); + } + return; + } else if (const ConstantStruct *CVS = dyn_cast(CV)) { + // Print the fields in successive locations. Pad to align if needed! + const StructLayout *cvsLayout = TD.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 = TD.getTypeSize(field->getType()); + unsigned padSize = ((i == N-1? cvsLayout->StructSize + : cvsLayout->MemberOffsets[i+1]) + - cvsLayout->MemberOffsets[i]) - fieldSize; + sizeSoFar += fieldSize + padSize; + + // Now print the actual field value + emitGlobalConstant(field); + + // Insert the field padding unless it's zero bytes... + if (padSize) + O << "\t.zero\t " << padSize << "\n"; + } + assert(sizeSoFar == cvsLayout->StructSize && + "Layout of constant struct may be incorrect!"); + return; + } else if (const ConstantFP *CFP = dyn_cast(CV)) { + // FP Constants are printed as integer constants to avoid losing + // precision... + double Val = CFP->getValue(); + switch (CFP->getType()->getPrimitiveID()) { + default: assert(0 && "Unknown floating point type!"); + case Type::FloatTyID: { + union FU { // Abide by C TBAA rules + float FVal; + unsigned UVal; + } U; + U.FVal = Val; + O << ".long\t" << U.UVal << "\t# float " << Val << "\n"; + return; + } + case Type::DoubleTyID: { + union DU { // Abide by C TBAA rules + double FVal; + uint64_t UVal; + } U; + U.FVal = Val; + O << ".quad\t" << U.UVal << "\t# double " << Val << "\n"; + return; + } + } + } + + const Type *type = CV->getType(); + O << "\t"; + switch (type->getPrimitiveID()) { + case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID: + O << ".byte"; + break; + case Type::UShortTyID: case Type::ShortTyID: + O << ".word"; + break; + case Type::FloatTyID: case Type::PointerTyID: + case Type::UIntTyID: case Type::IntTyID: + O << ".long"; + break; + case Type::DoubleTyID: + case Type::ULongTyID: case Type::LongTyID: + O << ".quad"; + break; + default: + assert (0 && "Can't handle printing this type of thing"); + break; + } + O << "\t"; + emitConstantValueOnly(CV); + O << "\n"; +} + +/// printConstantPool - Print to the current output stream assembly +/// representations of the constants in the constant pool MCP. This is +/// used to print out constants which have been "spilled to memory" by +/// the code generator. +/// +void V8Printer::printConstantPool(MachineConstantPool *MCP) { + const std::vector &CP = MCP->getConstants(); + const TargetData &TD = TM.getTargetData(); + + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.section .rodata\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) + << "\n"; + O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t#" + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); + } +} + +/// runOnMachineFunction - This uses the printMachineInstruction() +/// method to print assembly for each instruction. +/// +bool V8Printer::runOnMachineFunction(MachineFunction &MF) { + // BBNumber is used here so that a given Printer will never give two + // BBs the same name. (If you have a better way, please let me know!) + static unsigned BBNumber = 0; + + O << "\n\n"; + // What's my mangled name? + CurrentFnName = Mang->getValueName(MF.getFunction()); + + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool()); + + // Print out labels for the function. + O << "\t.text\n"; + O << "\t.align 16\n"; + O << "\t.globl\t" << CurrentFnName << "\n"; + O << "\t.type\t" << CurrentFnName << ", @function\n"; + O << CurrentFnName << ":\n"; + + // Number each basic block so that we can consistently refer to them + // in PC-relative references. + NumberForBB.clear(); + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + NumberForBB[I->getBasicBlock()] = BBNumber++; + } + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + O << ".LBB" << NumberForBB[I->getBasicBlock()] << ":\t# " + << I->getBasicBlock()->getName() << "\n"; + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printMachineInstruction(II); + } + } + + // We didn't modify anything. + return false; +} + +/// printMachineInstruction -- Print out a single SparcV8 LLVM instruction +/// MI in GAS syntax to the current output stream. +/// +void V8Printer::printMachineInstruction(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + const TargetInstrInfo &TII = TM.getInstrInfo(); + const TargetInstrDescriptor &Desc = TII.get(Opcode); + O << Desc.Name << "\n"; // not yet done +} + +bool V8Printer::doInitialization(Module &M) { + Mang = new Mangler(M); + return false; // success +} + +// SwitchSection - Switch to the specified section of the executable if we are +// not already in it! +// +static void SwitchSection(std::ostream &OS, std::string &CurSection, + const char *NewSection) { + if (CurSection != NewSection) { + CurSection = NewSection; + if (!CurSection.empty()) + OS << "\t" << NewSection << "\n"; + } +} + +bool V8Printer::doFinalization(Module &M) { + const TargetData &TD = TM.getTargetData(); + std::string CurSection; + + // Print out module-level global variables here. + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) + if (I->hasInitializer()) { // External global require no code + O << "\n\n"; + std::string name = Mang->getValueName(I); + Constant *C = I->getInitializer(); + unsigned Size = TD.getTypeSize(C->getType()); + unsigned Align = TD.getTypeAlignment(C->getType()); + + if (C->isNullValue() && + (I->hasLinkOnceLinkage() || I->hasInternalLinkage() || + I->hasWeakLinkage() /* FIXME: Verify correct */)) { + SwitchSection(O, CurSection, ".data"); + if (I->hasInternalLinkage()) + O << "\t.local " << name << "\n"; + + O << "\t.comm " << name << "," << TD.getTypeSize(C->getType()) + << "," << (unsigned)TD.getTypeAlignment(C->getType()); + O << "\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << "\n"; + } else { + switch (I->getLinkage()) { + case GlobalValue::LinkOnceLinkage: + case GlobalValue::WeakLinkage: // FIXME: Verify correct for weak. + // Nonnull linkonce -> weak + O << "\t.weak " << name << "\n"; + SwitchSection(O, CurSection, ""); + O << "\t.section\t.llvm.linkonce.d." << name << ",\"aw\",@progbits\n"; + break; + + case GlobalValue::AppendingLinkage: + // FIXME: appending linkage variables should go into a section of + // their name or something. For now, just emit them as external. + case GlobalValue::ExternalLinkage: + // If external or appending, declare as a global symbol + O << "\t.globl " << name << "\n"; + // FALL THROUGH + case GlobalValue::InternalLinkage: + if (C->isNullValue()) + SwitchSection(O, CurSection, ".bss"); + else + SwitchSection(O, CurSection, ".data"); + break; + } + + O << "\t.align " << Align << "\n"; + O << "\t.type " << name << ",@object\n"; + O << "\t.size " << name << "," << Size << "\n"; + O << name << ":\t\t\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << " = "; + WriteAsOperand(O, C, false, false, &M); + O << "\n"; + emitGlobalConstant(C); + } + } + + delete Mang; + return false; // success +} diff --git a/lib/Target/SparcV8/SparcV8TargetMachine.cpp b/lib/Target/SparcV8/SparcV8TargetMachine.cpp index f9a499dca43..581c535ccb2 100644 --- a/lib/Target/SparcV8/SparcV8TargetMachine.cpp +++ b/lib/Target/SparcV8/SparcV8TargetMachine.cpp @@ -53,6 +53,8 @@ bool SparcV8TargetMachine::addPassesToEmitAssembly(PassManager &PM, // are producing. PM.add(createMachineFunctionPrinterPass(&Out)); + PM.add(createSparcV8CodePrinterPass(Out, *this)); + PM.add(createMachineCodeDeleter()); return false; }