summaryrefslogtreecommitdiff
path: root/lib/Target/XCore/XCoreAsmPrinter.cpp
diff options
context:
space:
mode:
authorRichard Osborne <richard@xmos.com>2008-11-07 10:59:00 +0000
committerRichard Osborne <richard@xmos.com>2008-11-07 10:59:00 +0000
commitb25baef26f03b9909b65dd5f762b38f93000445d (patch)
treef03bc8e40b55feab99b0f32e4428d215fa45f988 /lib/Target/XCore/XCoreAsmPrinter.cpp
parent4df60f5491ff35c8a48c2cf14e18a33c9793b3bb (diff)
downloadllvm-b25baef26f03b9909b65dd5f762b38f93000445d.tar.gz
llvm-b25baef26f03b9909b65dd5f762b38f93000445d.tar.bz2
llvm-b25baef26f03b9909b65dd5f762b38f93000445d.tar.xz
Add XCore backend.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@58838 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/XCore/XCoreAsmPrinter.cpp')
-rw-r--r--lib/Target/XCore/XCoreAsmPrinter.cpp459
1 files changed, 459 insertions, 0 deletions
diff --git a/lib/Target/XCore/XCoreAsmPrinter.cpp b/lib/Target/XCore/XCoreAsmPrinter.cpp
new file mode 100644
index 0000000000..519b38bdfa
--- /dev/null
+++ b/lib/Target/XCore/XCoreAsmPrinter.cpp
@@ -0,0 +1,459 @@
+//===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file 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 the XAS-format XCore assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "asm-printer"
+#include "XCore.h"
+#include "XCoreInstrInfo.h"
+#include "XCoreSubtarget.h"
+#include "XCoreTargetMachine.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Module.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DwarfWriter.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/Target/TargetAsmInfo.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Support/Mangler.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cctype>
+using namespace llvm;
+
+STATISTIC(EmittedInsts, "Number of machine instrs printed");
+
+static cl::opt<std::string> FileDirective("xcore-file-directive", cl::Optional,
+ cl::desc("Output a file directive into the assembly file"),
+ cl::Hidden,
+ cl::value_desc("filename"),
+ cl::init(""));
+
+static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
+ cl::desc("Maximum number of threads (for emulation thread-local storage)"),
+ cl::Hidden,
+ cl::value_desc("number"),
+ cl::init(8));
+
+namespace {
+ struct VISIBILITY_HIDDEN XCoreAsmPrinter : public AsmPrinter {
+ XCoreAsmPrinter(raw_ostream &O, XCoreTargetMachine &TM,
+ const TargetAsmInfo *T)
+ : AsmPrinter(O, TM, T), DW(O, this, T),
+ Subtarget(*TM.getSubtargetImpl()) { }
+
+ DwarfWriter DW;
+ const XCoreSubtarget &Subtarget;
+
+ virtual const char *getPassName() const {
+ return "XCore Assembly Printer";
+ }
+
+ void printMemOperand(const MachineInstr *MI, int opNum);
+ void printOperand(const MachineInstr *MI, int opNum);
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode);
+
+ void emitFileDirective(const std::string &filename);
+ void emitGlobalDirective(const std::string &name);
+ void emitExternDirective(const std::string &name);
+
+ void emitArrayBound(const std::string &name, const GlobalVariable *GV);
+ void emitGlobal(const GlobalVariable *GV);
+
+ void emitFunctionStart(MachineFunction &MF);
+ void emitFunctionEnd(MachineFunction &MF);
+
+ bool printInstruction(const MachineInstr *MI); // autogenerated.
+ void printMachineInstruction(const MachineInstr *MI);
+ bool runOnMachineFunction(MachineFunction &F);
+ bool doInitialization(Module &M);
+ bool doFinalization(Module &M);
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ AsmPrinter::getAnalysisUsage(AU);
+ AU.setPreservesAll();
+ AU.addRequired<MachineModuleInfo>();
+ }
+ };
+} // end of anonymous namespace
+
+#include "XCoreGenAsmWriter.inc"
+
+/// createXCoreCodePrinterPass - Returns a pass that prints the XCore
+/// 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::createXCoreCodePrinterPass(raw_ostream &o,
+ XCoreTargetMachine &tm) {
+ return new XCoreAsmPrinter(o, tm, tm.getTargetAsmInfo());
+}
+
+// PrintEscapedString - Print each character of the specified string, escaping
+// it if it is not printable or if it is an escape char.
+static void PrintEscapedString(const std::string &Str, raw_ostream &Out) {
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ unsigned char C = Str[i];
+ if (isprint(C) && C != '"' && C != '\\') {
+ Out << C;
+ } else {
+ Out << '\\'
+ << (char) ((C/16 < 10) ? ( C/16 +'0') : ( C/16 -10+'A'))
+ << (char)(((C&15) < 10) ? ((C&15)+'0') : ((C&15)-10+'A'));
+ }
+ }
+}
+
+void XCoreAsmPrinter::
+emitFileDirective(const std::string &name)
+{
+ O << "\t.file\t\"";
+ PrintEscapedString(name, O);
+ O << "\"\n";
+}
+
+void XCoreAsmPrinter::
+emitGlobalDirective(const std::string &name)
+{
+ O << TAI->getGlobalDirective() << name;
+ O << "\n";
+}
+
+void XCoreAsmPrinter::
+emitExternDirective(const std::string &name)
+{
+ O << "\t.extern\t" << name;
+ O << '\n';
+}
+
+void XCoreAsmPrinter::
+emitArrayBound(const std::string &name, const GlobalVariable *GV)
+{
+ assert((GV->hasExternalLinkage() ||
+ GV->hasWeakLinkage()) ||
+ GV->hasLinkOnceLinkage() && "Unexpected linkage");
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(
+ cast<PointerType>(GV->getType())->getElementType()))
+ {
+ O << TAI->getGlobalDirective() << name << ".globound" << "\n";
+ O << TAI->getSetDirective() << name << ".globound" << ","
+ << ATy->getNumElements() << "\n";
+ if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ O << TAI->getWeakDefDirective() << name << ".globound" << "\n";
+ }
+ }
+}
+
+void XCoreAsmPrinter::
+emitGlobal(const GlobalVariable *GV)
+{
+ const TargetData *TD = TM.getTargetData();
+
+ if (GV->hasInitializer()) {
+ // Check to see if this is a special global used by LLVM, if so, emit it.
+ if (EmitSpecialLLVMGlobal(GV))
+ return;
+
+ SwitchToSection(TAI->SectionForGlobal(GV));
+
+ std::string name = Mang->getValueName(GV);
+ Constant *C = GV->getInitializer();
+ unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
+
+ // Mark the start of the global
+ O << "\t.cc_top " << name << ".data," << name << "\n";
+
+ switch (GV->getLinkage()) {
+ case GlobalValue::AppendingLinkage:
+ cerr << "AppendingLinkage is not supported by this target!\n";
+ abort();
+ case GlobalValue::LinkOnceLinkage:
+ case GlobalValue::WeakLinkage:
+ case GlobalValue::ExternalLinkage:
+ emitArrayBound(name, GV);
+ emitGlobalDirective(name);
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
+ O << TAI->getWeakDefDirective() << name << "\n";
+ }
+ // FALL THROUGH
+ case GlobalValue::InternalLinkage:
+ break;
+ case GlobalValue::GhostLinkage:
+ cerr << "Should not have any unmaterialized functions!\n";
+ abort();
+ case GlobalValue::DLLImportLinkage:
+ cerr << "DLLImport linkage is not supported by this target!\n";
+ abort();
+ case GlobalValue::DLLExportLinkage:
+ cerr << "DLLExport linkage is not supported by this target!\n";
+ abort();
+ default:
+ assert(0 && "Unknown linkage type!");
+ }
+
+ EmitAlignment(Align, GV, 2);
+
+ unsigned Size = TD->getABITypeSize(C->getType());
+ if (GV->isThreadLocal()) {
+ Size *= MaxThreads;
+ }
+ if (TAI->hasDotTypeDotSizeDirective()) {
+ O << "\t.type " << name << ",@object\n";
+ O << "\t.size " << name << "," << Size << "\n";
+ }
+ O << name << ":\n";
+
+ EmitGlobalConstant(C);
+ if (GV->isThreadLocal()) {
+ for (unsigned i = 1; i < MaxThreads; ++i) {
+ EmitGlobalConstant(C);
+ }
+ }
+ if (Size < 4) {
+ // The ABI requires that unsigned scalar types smaller than 32 bits
+ // are are padded to 32 bits.
+ EmitZeros(4 - Size);
+ }
+
+ // Mark the end of the global
+ O << "\t.cc_bottom " << name << ".data\n";
+ } else {
+ if (GV->hasExternalWeakLinkage())
+ ExtWeakSymbols.insert(GV);
+ }
+}
+
+/// Emit the directives on the start of functions
+void XCoreAsmPrinter::
+emitFunctionStart(MachineFunction &MF)
+{
+ // Print out the label for the function.
+ const Function *F = MF.getFunction();
+
+ SwitchToSection(TAI->SectionForGlobal(F));
+
+ // Mark the start of the function
+ O << "\t.cc_top " << CurrentFnName << ".function," << CurrentFnName << "\n";
+
+ switch (F->getLinkage()) {
+ default: assert(0 && "Unknown linkage type!");
+ case Function::InternalLinkage: // Symbols default to internal.
+ break;
+ case Function::ExternalLinkage:
+ emitGlobalDirective(CurrentFnName);
+ break;
+ case Function::LinkOnceLinkage:
+ case Function::WeakLinkage:
+ // TODO Use COMDAT groups for LinkOnceLinkage
+ O << TAI->getGlobalDirective() << CurrentFnName << "\n";
+ O << TAI->getWeakDefDirective() << CurrentFnName << "\n";
+ break;
+ }
+ // (1 << 1) byte aligned
+ EmitAlignment(1, F, 1);
+ if (TAI->hasDotTypeDotSizeDirective()) {
+ O << "\t.type " << CurrentFnName << ",@function\n";
+ }
+ O << CurrentFnName << ":\n";
+}
+
+/// Emit the directives on the end of functions
+void XCoreAsmPrinter::
+emitFunctionEnd(MachineFunction &MF)
+{
+ // Mark the end of the function
+ O << "\t.cc_bottom " << CurrentFnName << ".function\n";
+}
+
+/// runOnMachineFunction - This uses the printMachineInstruction()
+/// method to print assembly for each instruction.
+///
+bool XCoreAsmPrinter::runOnMachineFunction(MachineFunction &MF)
+{
+ SetupMachineFunction(MF);
+
+ // Print out constants referenced by the function
+ EmitConstantPool(MF.getConstantPool());
+
+ // Print out jump tables referenced by the function
+ EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
+
+ // What's my mangled name?
+ CurrentFnName = Mang->getValueName(MF.getFunction());
+
+ // Emit the function start directives
+ emitFunctionStart(MF);
+
+ // Emit pre-function debug information.
+ DW.BeginFunction(&MF);
+
+ // 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.
+ if (I != MF.begin()) {
+ printBasicBlockLabel(I, true , true);
+ O << '\n';
+ }
+
+ for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
+ II != E; ++II) {
+ // Print the assembly for the instruction.
+ O << "\t";
+ printMachineInstruction(II);
+ }
+
+ // Each Basic Block is separated by a newline
+ O << '\n';
+ }
+
+ // Emit function end directives
+ emitFunctionEnd(MF);
+
+ // Emit post-function debug information.
+ DW.EndFunction(&MF);
+
+ // We didn't modify anything.
+ return false;
+}
+
+void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum)
+{
+ printOperand(MI, opNum);
+
+ if (MI->getOperand(opNum+1).isImm()
+ && MI->getOperand(opNum+1).getImm() == 0)
+ return;
+
+ O << "+";
+ printOperand(MI, opNum+1);
+}
+
+void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
+ const MachineOperand &MO = MI->getOperand(opNum);
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
+ O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
+ else
+ assert(0 && "not implemented");
+ break;
+ case MachineOperand::MO_Immediate:
+ O << MO.getImm();
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ printBasicBlockLabel(MO.getMBB());
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ O << Mang->getValueName(MO.getGlobal());
+ if (MO.getGlobal()->hasExternalWeakLinkage())
+ ExtWeakSymbols.insert(MO.getGlobal());
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ O << MO.getSymbolName();
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
+ << '_' << MO.getIndex();
+ break;
+ case MachineOperand::MO_JumpTableIndex:
+ O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
+ << '_' << MO.getIndex();
+ break;
+ default:
+ assert(0 && "not implemented");
+ }
+}
+
+/// PrintAsmOperand - Print out an operand for an inline asm expression.
+///
+bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode) {
+ printOperand(MI, OpNo);
+ return false;
+}
+
+void XCoreAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
+ ++EmittedInsts;
+
+ // Check for mov mnemonic
+ unsigned src, dst;
+ if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst)) {
+ O << "\tmov ";
+ O << TM.getRegisterInfo()->get(dst).AsmName;
+ O << ", ";
+ O << TM.getRegisterInfo()->get(src).AsmName;
+ O << "\n";
+ return;
+ }
+ if (printInstruction(MI)) {
+ return;
+ }
+ assert(0 && "Unhandled instruction in asm writer!");
+}
+
+bool XCoreAsmPrinter::doInitialization(Module &M) {
+ bool Result = AsmPrinter::doInitialization(M);
+
+ if (!FileDirective.empty()) {
+ emitFileDirective(FileDirective);
+ }
+
+ // Print out type strings for external functions here
+ for (Module::const_iterator I = M.begin(), E = M.end();
+ I != E; ++I) {
+ if (I->isDeclaration() && !I->isIntrinsic()) {
+ switch (I->getLinkage()) {
+ default:
+ assert(0 && "Unexpected linkage");
+ case Function::ExternalWeakLinkage:
+ ExtWeakSymbols.insert(I);
+ // fallthrough
+ case Function::ExternalLinkage:
+ break;
+ }
+ }
+ }
+
+ // Emit initial debug information.
+ DW.BeginModule(&M);
+
+ DW.SetModuleInfo(getAnalysisToUpdate<MachineModuleInfo>());
+ return Result;
+}
+
+bool XCoreAsmPrinter::doFinalization(Module &M) {
+
+ // Print out module-level global variables.
+ for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
+ I != E; ++I) {
+ emitGlobal(I);
+ }
+
+ // Emit final debug information.
+ DW.EndModule();
+
+ return AsmPrinter::doFinalization(M);
+}