mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-07 01:54:50 +00:00
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@96942 91177308-0d34-0410-b5e6-96231b3b80d8
343 lines
11 KiB
C++
343 lines
11 KiB
C++
//===-- 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 "XCoreMCAsmInfo.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/CodeGen/MachineJumpTableInfo.h"
|
|
#include "llvm/MC/MCStreamer.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Target/TargetLoweringObjectFile.h"
|
|
#include "llvm/Target/TargetRegistry.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
using namespace llvm;
|
|
|
|
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 {
|
|
class XCoreAsmPrinter : public AsmPrinter {
|
|
const XCoreSubtarget &Subtarget;
|
|
public:
|
|
explicit XCoreAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
|
|
MCContext &Ctx, MCStreamer &Streamer,
|
|
const MCAsmInfo *T)
|
|
: AsmPrinter(O, TM, Ctx, Streamer, T),
|
|
Subtarget(TM.getSubtarget<XCoreSubtarget>()) {}
|
|
|
|
virtual const char *getPassName() const {
|
|
return "XCore Assembly Printer";
|
|
}
|
|
|
|
void printMemOperand(const MachineInstr *MI, int opNum);
|
|
void printInlineJT(const MachineInstr *MI, int opNum,
|
|
const std::string &directive = ".jmptable");
|
|
void printInlineJT32(const MachineInstr *MI, int opNum) {
|
|
printInlineJT(MI, opNum, ".jmptable32");
|
|
}
|
|
void printOperand(const MachineInstr *MI, int opNum);
|
|
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
|
unsigned AsmVariant, const char *ExtraCode);
|
|
|
|
void emitGlobalDirective(const MCSymbol *Sym);
|
|
|
|
void emitArrayBound(const MCSymbol *Sym, const GlobalVariable *GV);
|
|
virtual void EmitGlobalVariable(const GlobalVariable *GV);
|
|
|
|
void emitFunctionStart(MachineFunction &MF);
|
|
|
|
void printInstruction(const MachineInstr *MI); // autogenerated.
|
|
static const char *getRegisterName(unsigned RegNo);
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF);
|
|
void EmitInstruction(const MachineInstr *MI);
|
|
void EmitFunctionBodyEnd();
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AsmPrinter::getAnalysisUsage(AU);
|
|
AU.setPreservesAll();
|
|
AU.addRequired<MachineModuleInfo>();
|
|
AU.addRequired<DwarfWriter>();
|
|
}
|
|
};
|
|
} // end of anonymous namespace
|
|
|
|
#include "XCoreGenAsmWriter.inc"
|
|
|
|
void XCoreAsmPrinter::emitGlobalDirective(const MCSymbol *Sym) {
|
|
O << MAI->getGlobalDirective() << *Sym << "\n";
|
|
}
|
|
|
|
void XCoreAsmPrinter::emitArrayBound(const MCSymbol *Sym,
|
|
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 << MAI->getGlobalDirective() << *Sym;
|
|
O << ".globound" << "\n";
|
|
O << "\t.set\t" << *Sym;
|
|
O << ".globound" << "," << ATy->getNumElements() << "\n";
|
|
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
|
|
// TODO Use COMDAT groups for LinkOnceLinkage
|
|
O << MAI->getWeakDefDirective() << *Sym << ".globound" << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
|
// Check to see if this is a special global used by LLVM, if so, emit it.
|
|
if (!GV->hasInitializer() ||
|
|
EmitSpecialLLVMGlobal(GV))
|
|
return;
|
|
|
|
const TargetData *TD = TM.getTargetData();
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM));
|
|
|
|
|
|
MCSymbol *GVSym = GetGlobalValueSymbol(GV);
|
|
Constant *C = GV->getInitializer();
|
|
unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
|
|
|
|
// Mark the start of the global
|
|
O << "\t.cc_top " << *GVSym << ".data," << *GVSym << "\n";
|
|
|
|
switch (GV->getLinkage()) {
|
|
case GlobalValue::AppendingLinkage:
|
|
llvm_report_error("AppendingLinkage is not supported by this target!");
|
|
case GlobalValue::LinkOnceAnyLinkage:
|
|
case GlobalValue::LinkOnceODRLinkage:
|
|
case GlobalValue::WeakAnyLinkage:
|
|
case GlobalValue::WeakODRLinkage:
|
|
case GlobalValue::ExternalLinkage:
|
|
emitArrayBound(GVSym, GV);
|
|
emitGlobalDirective(GVSym);
|
|
// TODO Use COMDAT groups for LinkOnceLinkage
|
|
if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())
|
|
O << MAI->getWeakDefDirective() << *GVSym << "\n";
|
|
// FALL THROUGH
|
|
case GlobalValue::InternalLinkage:
|
|
case GlobalValue::PrivateLinkage:
|
|
case GlobalValue::LinkerPrivateLinkage:
|
|
break;
|
|
case GlobalValue::DLLImportLinkage:
|
|
llvm_unreachable("DLLImport linkage is not supported by this target!");
|
|
case GlobalValue::DLLExportLinkage:
|
|
llvm_unreachable("DLLExport linkage is not supported by this target!");
|
|
default:
|
|
llvm_unreachable("Unknown linkage type!");
|
|
}
|
|
|
|
EmitAlignment(Align, GV, 2);
|
|
|
|
unsigned Size = TD->getTypeAllocSize(C->getType());
|
|
if (GV->isThreadLocal()) {
|
|
Size *= MaxThreads;
|
|
}
|
|
if (MAI->hasDotTypeDotSizeDirective()) {
|
|
O << "\t.type " << *GVSym << ",@object\n";
|
|
O << "\t.size " << *GVSym << "," << Size << "\n";
|
|
}
|
|
O << *GVSym << ":\n";
|
|
|
|
EmitGlobalConstant(C);
|
|
if (GV->isThreadLocal()) {
|
|
for (unsigned i = 1; i < MaxThreads; ++i)
|
|
EmitGlobalConstant(C);
|
|
}
|
|
// The ABI requires that unsigned scalar types smaller than 32 bits
|
|
// are padded to 32 bits.
|
|
if (Size < 4)
|
|
OutStreamer.EmitZeros(4 - Size, 0);
|
|
|
|
// Mark the end of the global
|
|
O << "\t.cc_bottom " << *GVSym << ".data\n";
|
|
}
|
|
|
|
/// 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();
|
|
|
|
OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(F, Mang, TM));
|
|
|
|
// Mark the start of the function
|
|
O << "\t.cc_top " << *CurrentFnSym << ".function," << *CurrentFnSym << "\n";
|
|
|
|
switch (F->getLinkage()) {
|
|
default: llvm_unreachable("Unknown linkage type!");
|
|
case Function::InternalLinkage: // Symbols default to internal.
|
|
case Function::PrivateLinkage:
|
|
case Function::LinkerPrivateLinkage:
|
|
break;
|
|
case Function::ExternalLinkage:
|
|
emitGlobalDirective(CurrentFnSym);
|
|
break;
|
|
case Function::LinkOnceAnyLinkage:
|
|
case Function::LinkOnceODRLinkage:
|
|
case Function::WeakAnyLinkage:
|
|
case Function::WeakODRLinkage:
|
|
// TODO Use COMDAT groups for LinkOnceLinkage
|
|
O << MAI->getGlobalDirective() << *CurrentFnSym << "\n";
|
|
O << MAI->getWeakDefDirective() << *CurrentFnSym << "\n";
|
|
break;
|
|
}
|
|
// (1 << 1) byte aligned
|
|
EmitAlignment(MF.getAlignment(), F, 1);
|
|
if (MAI->hasDotTypeDotSizeDirective())
|
|
O << "\t.type " << *CurrentFnSym << ",@function\n";
|
|
|
|
O << *CurrentFnSym << ":\n";
|
|
}
|
|
|
|
|
|
/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
|
|
/// the last basic block in the function.
|
|
void XCoreAsmPrinter::EmitFunctionBodyEnd() {
|
|
// Emit function end directives
|
|
O << "\t.cc_bottom " << *CurrentFnSym << ".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();
|
|
|
|
// Emit the function start directives
|
|
emitFunctionStart(MF);
|
|
|
|
// Emit pre-function debug information.
|
|
DW->BeginFunction(&MF);
|
|
|
|
EmitFunctionBody();
|
|
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::
|
|
printInlineJT(const MachineInstr *MI, int opNum, const std::string &directive)
|
|
{
|
|
unsigned JTI = MI->getOperand(opNum).getIndex();
|
|
const MachineFunction *MF = MI->getParent()->getParent();
|
|
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
|
|
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
|
|
const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
|
|
O << "\t" << directive << " ";
|
|
for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
|
|
MachineBasicBlock *MBB = JTBBs[i];
|
|
if (i > 0)
|
|
O << ",";
|
|
O << *MBB->getSymbol(OutContext);
|
|
}
|
|
}
|
|
|
|
void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
|
switch (MO.getType()) {
|
|
case MachineOperand::MO_Register:
|
|
O << getRegisterName(MO.getReg());
|
|
break;
|
|
case MachineOperand::MO_Immediate:
|
|
O << MO.getImm();
|
|
break;
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
O << *MO.getMBB()->getSymbol(OutContext);
|
|
break;
|
|
case MachineOperand::MO_GlobalAddress:
|
|
O << *GetGlobalValueSymbol(MO.getGlobal());
|
|
break;
|
|
case MachineOperand::MO_ExternalSymbol:
|
|
O << MO.getSymbolName();
|
|
break;
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
|
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
|
<< '_' << MO.getIndex();
|
|
break;
|
|
case MachineOperand::MO_JumpTableIndex:
|
|
O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
|
<< '_' << MO.getIndex();
|
|
break;
|
|
case MachineOperand::MO_BlockAddress:
|
|
O << *GetBlockAddressSymbol(MO.getBlockAddress());
|
|
break;
|
|
default:
|
|
llvm_unreachable("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::EmitInstruction(const MachineInstr *MI) {
|
|
// Check for mov mnemonic
|
|
unsigned src, dst, srcSR, dstSR;
|
|
if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst, srcSR, dstSR)) {
|
|
O << "\tmov " << getRegisterName(dst) << ", ";
|
|
O << getRegisterName(src);
|
|
OutStreamer.AddBlankLine();
|
|
return;
|
|
}
|
|
printInstruction(MI);
|
|
OutStreamer.AddBlankLine();
|
|
}
|
|
|
|
// Force static initialization.
|
|
extern "C" void LLVMInitializeXCoreAsmPrinter() {
|
|
RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
|
|
}
|