mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-17 21:29:20 +00:00
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@55092 91177308-0d34-0410-b5e6-96231b3b80d8
538 lines
16 KiB
C++
538 lines
16 KiB
C++
//===-- PIC16AsmPrinter.cpp - PIC16 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 PIC16 assembly language.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
#include "PIC16.h"
|
|
#include "PIC16TargetMachine.h"
|
|
#include "PIC16ConstantPoolValue.h"
|
|
#include "PIC16InstrInfo.h"
|
|
#include "llvm/Constants.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/Module.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/CodeGen/AsmPrinter.h"
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/Mangler.h"
|
|
#include "llvm/Support/MathExtras.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Target/TargetAsmInfo.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include <cctype>
|
|
|
|
using namespace llvm;
|
|
|
|
STATISTIC(EmittedInsts, "Number of machine instrs printed");
|
|
|
|
namespace {
|
|
struct VISIBILITY_HIDDEN PIC16AsmPrinter : public AsmPrinter {
|
|
PIC16AsmPrinter(raw_ostream &O, TargetMachine &TM, const TargetAsmInfo *T)
|
|
: AsmPrinter(O, TM, T) {
|
|
}
|
|
|
|
|
|
/// 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<const Value *, unsigned> ValueMapTy;
|
|
ValueMapTy NumberForBB;
|
|
|
|
/// Keeps the set of GlobalValues that require non-lazy-pointers for
|
|
/// indirect access.
|
|
std::set<std::string> GVNonLazyPtrs;
|
|
|
|
/// Keeps the set of external function GlobalAddresses that the asm
|
|
/// printer should generate stubs for.
|
|
std::set<std::string> FnStubs;
|
|
|
|
/// True if asm printer is printing a series of CONSTPOOL_ENTRY.
|
|
bool InCPMode;
|
|
|
|
virtual const char *getPassName() const {
|
|
return "PIC16 Assembly Printer";
|
|
}
|
|
|
|
void printOperand(const MachineInstr *MI, int opNum,
|
|
const char *Modifier = 0);
|
|
|
|
void printSOImmOperand(const MachineInstr *MI, int opNum);
|
|
|
|
void printAddrModeOperand(const MachineInstr *MI, int OpNo);
|
|
|
|
void printRegisterList(const MachineInstr *MI, int opNum);
|
|
void printCPInstOperand(const MachineInstr *MI, int opNum,
|
|
const char *Modifier);
|
|
|
|
|
|
bool printInstruction(const MachineInstr *MI); // autogenerated.
|
|
void emitFunctionStart(MachineFunction &F);
|
|
bool runOnMachineFunction(MachineFunction &F);
|
|
bool doInitialization(Module &M);
|
|
bool doFinalization(Module &M);
|
|
|
|
virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV);
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const;
|
|
|
|
public:
|
|
void SwitchToTextSection(const char *NewSection,
|
|
const GlobalValue *GV = NULL);
|
|
void SwitchToDataSection(const char *NewSection,
|
|
const GlobalValue *GV = NULL);
|
|
void SwitchToDataOvrSection(const char *NewSection,
|
|
const GlobalValue *GV = NULL);
|
|
};
|
|
} // end of anonymous namespace
|
|
|
|
#include "PIC16GenAsmWriter.inc"
|
|
|
|
/// createPIC16CodePrinterPass - Returns a pass that prints the PIC16
|
|
/// 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::createPIC16CodePrinterPass(raw_ostream &o,
|
|
PIC16TargetMachine &tm) {
|
|
return new PIC16AsmPrinter(o, tm, tm.getTargetAsmInfo());
|
|
}
|
|
|
|
void PIC16AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const
|
|
{
|
|
// FIXME: Currently unimplemented.
|
|
}
|
|
|
|
|
|
void PIC16AsmPrinter ::
|
|
EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV)
|
|
{
|
|
printDataDirective(MCPV->getType());
|
|
|
|
PIC16ConstantPoolValue *ACPV = (PIC16ConstantPoolValue*)MCPV;
|
|
GlobalValue *GV = ACPV->getGV();
|
|
std::string Name = GV ? Mang->getValueName(GV) : TAI->getGlobalPrefix();
|
|
if (!GV)
|
|
Name += ACPV->getSymbol();
|
|
if (ACPV->isNonLazyPointer()) {
|
|
GVNonLazyPtrs.insert(Name);
|
|
O << TAI->getPrivateGlobalPrefix() << Name << "$non_lazy_ptr";
|
|
} else if (ACPV->isStub()) {
|
|
FnStubs.insert(Name);
|
|
O << TAI->getPrivateGlobalPrefix() << Name << "$stub";
|
|
} else {
|
|
O << Name;
|
|
}
|
|
|
|
if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")";
|
|
|
|
if (ACPV->getPCAdjustment() != 0) {
|
|
O << "-(" << TAI->getPrivateGlobalPrefix() << "PC"
|
|
<< utostr(ACPV->getLabelId())
|
|
<< "+" << (unsigned)ACPV->getPCAdjustment();
|
|
|
|
if (ACPV->mustAddCurrentAddress())
|
|
O << "-.";
|
|
|
|
O << ")";
|
|
}
|
|
O << "\n";
|
|
|
|
// If the constant pool value is a extern weak symbol, remember to emit
|
|
// the weak reference.
|
|
if (GV && GV->hasExternalWeakLinkage())
|
|
ExtWeakSymbols.insert(GV);
|
|
}
|
|
|
|
/// emitFunctionStart - Emit the directives used by ASM on the start of
|
|
/// functions.
|
|
void PIC16AsmPrinter::emitFunctionStart(MachineFunction &MF)
|
|
{
|
|
// Print out the label for the function.
|
|
const Function *F = MF.getFunction();
|
|
MachineFrameInfo *FrameInfo = MF.getFrameInfo();
|
|
if (FrameInfo->hasStackObjects()) {
|
|
int indexBegin = FrameInfo->getObjectIndexBegin();
|
|
int indexEnd = FrameInfo->getObjectIndexEnd();
|
|
while (indexBegin < indexEnd) {
|
|
if (indexBegin == 0)
|
|
SwitchToDataOvrSection(F->getParent()->getModuleIdentifier().c_str(),
|
|
F);
|
|
|
|
O << "\t\t" << CurrentFnName << "_" << indexBegin << " " << "RES"
|
|
<< " " << FrameInfo->getObjectSize(indexBegin) << "\n" ;
|
|
indexBegin++;
|
|
}
|
|
}
|
|
SwitchToTextSection(CurrentFnName.c_str(), F);
|
|
O << "_" << CurrentFnName << ":" ;
|
|
O << "\n";
|
|
}
|
|
|
|
|
|
/// runOnMachineFunction - This uses the printInstruction()
|
|
/// method to print assembly for each instruction.
|
|
///
|
|
bool PIC16AsmPrinter::runOnMachineFunction(MachineFunction &MF)
|
|
{
|
|
SetupMachineFunction(MF);
|
|
O << "\n";
|
|
|
|
// What's my mangled name?
|
|
CurrentFnName = Mang->getValueName(MF.getFunction());
|
|
|
|
// Emit the function start directives
|
|
emitFunctionStart(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);
|
|
O << '\n';
|
|
}
|
|
for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
|
|
II != E; ++II) {
|
|
// Print the assembly for the instruction.
|
|
O << '\t';
|
|
printInstruction(II);
|
|
++EmittedInsts;
|
|
}
|
|
}
|
|
|
|
// We didn't modify anything.
|
|
return false;
|
|
}
|
|
|
|
void PIC16AsmPrinter::
|
|
printOperand(const MachineInstr *MI, int opNum, const char *Modifier)
|
|
{
|
|
const MachineOperand &MO = MI->getOperand(opNum);
|
|
const TargetRegisterInfo &RI = *TM.getRegisterInfo();
|
|
|
|
switch (MO.getType()) {
|
|
case MachineOperand::MO_Register:
|
|
if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
|
|
O << RI.get(MO.getReg()).Name;
|
|
else
|
|
assert(0 && "not implemented");
|
|
break;
|
|
|
|
case MachineOperand::MO_Immediate:
|
|
if (!Modifier || strcmp(Modifier, "no_hash") != 0)
|
|
O << "#";
|
|
O << (int)MO.getImm();
|
|
break;
|
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
printBasicBlockLabel(MO.getMBB());
|
|
return;
|
|
|
|
case MachineOperand::MO_GlobalAddress:
|
|
O << Mang->getValueName(MO.getGlobal())<<'+'<<MO.getOffset();
|
|
break;
|
|
|
|
case MachineOperand::MO_ExternalSymbol:
|
|
O << MO.getSymbolName();
|
|
break;
|
|
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
|
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
|
<< '_' << MO.getIndex();
|
|
break;
|
|
|
|
case MachineOperand::MO_FrameIndex:
|
|
O << "_" << CurrentFnName
|
|
<< '+' << MO.getIndex();
|
|
break;
|
|
|
|
case MachineOperand::MO_JumpTableIndex:
|
|
O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
|
|
<< '_' << MO.getIndex();
|
|
break;
|
|
|
|
default:
|
|
O << "<unknown operand type>"; abort ();
|
|
break;
|
|
} // end switch.
|
|
}
|
|
|
|
static void
|
|
printSOImm(raw_ostream &O, int64_t V, const TargetAsmInfo *TAI)
|
|
{
|
|
assert(V < (1 << 12) && "Not a valid so_imm value!");
|
|
|
|
O << (unsigned) V;
|
|
}
|
|
|
|
/// printSOImmOperand - SOImm is 4-bit rotated amount in bits 8-11 with 8-bit
|
|
/// immediate in bits 0-7.
|
|
void PIC16AsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum)
|
|
{
|
|
const MachineOperand &MO = MI->getOperand(OpNum);
|
|
assert(MO.isImmediate() && "Not a valid so_imm value!");
|
|
printSOImm(O, MO.getImm(), TAI);
|
|
}
|
|
|
|
|
|
void PIC16AsmPrinter::printAddrModeOperand(const MachineInstr *MI, int Op)
|
|
{
|
|
const MachineOperand &MO1 = MI->getOperand(Op);
|
|
const MachineOperand &MO2 = MI->getOperand(Op+1);
|
|
|
|
if (MO2.isFrameIndex ()) {
|
|
printOperand(MI, Op+1);
|
|
return;
|
|
}
|
|
|
|
if (!MO1.isRegister()) {
|
|
// FIXME: This is for CP entries, but isn't right.
|
|
printOperand(MI, Op);
|
|
return;
|
|
}
|
|
|
|
// If this is Stack Slot
|
|
if (MO1.isRegister()) {
|
|
if (strcmp(TM.getRegisterInfo()->get(MO1.getReg()).Name, "SP") == 0) {
|
|
O << CurrentFnName <<"_"<< MO2.getImm();
|
|
return;
|
|
}
|
|
O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name;
|
|
O << "+";
|
|
O << MO2.getImm();
|
|
O << "]";
|
|
return;
|
|
}
|
|
|
|
O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name;
|
|
O << "]";
|
|
}
|
|
|
|
|
|
void PIC16AsmPrinter::printRegisterList(const MachineInstr *MI, int opNum)
|
|
{
|
|
O << "{";
|
|
for (unsigned i = opNum, e = MI->getNumOperands(); i != e; ++i) {
|
|
printOperand(MI, i);
|
|
if (i != e-1) O << ", ";
|
|
}
|
|
O << "}";
|
|
}
|
|
|
|
void PIC16AsmPrinter::
|
|
printCPInstOperand(const MachineInstr *MI, int OpNo, const char *Modifier)
|
|
{
|
|
assert(Modifier && "This operand only works with a modifier!");
|
|
|
|
// There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the
|
|
// data itself.
|
|
if (!strcmp(Modifier, "label")) {
|
|
unsigned ID = MI->getOperand(OpNo).getImm();
|
|
O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
|
|
<< '_' << ID << ":\n";
|
|
} else {
|
|
assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE");
|
|
unsigned CPI = MI->getOperand(OpNo).getIndex();
|
|
|
|
const MachineConstantPoolEntry &MCPE = // Chasing pointers is fun?
|
|
MI->getParent()->getParent()->getConstantPool()->getConstants()[CPI];
|
|
|
|
if (MCPE.isMachineConstantPoolEntry())
|
|
EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
|
|
else {
|
|
EmitGlobalConstant(MCPE.Val.ConstVal);
|
|
// remember to emit the weak reference
|
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(MCPE.Val.ConstVal))
|
|
if (GV->hasExternalWeakLinkage())
|
|
ExtWeakSymbols.insert(GV);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool PIC16AsmPrinter::doInitialization(Module &M)
|
|
{
|
|
bool Result = AsmPrinter::doInitialization(M);
|
|
return Result;
|
|
}
|
|
|
|
bool PIC16AsmPrinter::doFinalization(Module &M)
|
|
{
|
|
const TargetData *TD = TM.getTargetData();
|
|
|
|
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
|
|
I != E; ++I) {
|
|
if (!I->hasInitializer()) // External global require no code
|
|
continue;
|
|
|
|
if (EmitSpecialLLVMGlobal(I)) {
|
|
continue;
|
|
}
|
|
|
|
std::string name = Mang->getValueName(I);
|
|
Constant *C = I->getInitializer();
|
|
const Type *Ty = C->getType();
|
|
unsigned Size = TD->getABITypeSize(Ty);
|
|
unsigned Align = TD->getPreferredAlignmentLog(I);
|
|
|
|
const char *VisibilityDirective = NULL;
|
|
if (I->hasHiddenVisibility())
|
|
VisibilityDirective = TAI->getHiddenDirective();
|
|
else if (I->hasProtectedVisibility())
|
|
VisibilityDirective = TAI->getProtectedDirective();
|
|
|
|
if (VisibilityDirective)
|
|
O << VisibilityDirective << name << "\n";
|
|
|
|
if (C->isNullValue()) {
|
|
if (I->hasExternalLinkage()) {
|
|
if (const char *Directive = TAI->getZeroFillDirective()) {
|
|
O << "\t.globl\t" << name << "\n";
|
|
O << Directive << "__DATA__, __common, " << name << ", "
|
|
<< Size << ", " << Align << "\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!I->hasSection() &&
|
|
(I->hasInternalLinkage() || I->hasWeakLinkage() ||
|
|
I->hasLinkOnceLinkage() || I->hasCommonLinkage())) {
|
|
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
|
|
if (!NoZerosInBSS && TAI->getBSSSection())
|
|
SwitchToDataSection(M.getModuleIdentifier().c_str(), I);
|
|
else
|
|
SwitchToDataSection(TAI->getDataSection(), I);
|
|
if (TAI->getLCOMMDirective() != NULL) {
|
|
if (I->hasInternalLinkage()) {
|
|
O << TAI->getLCOMMDirective() << name << "," << Size;
|
|
} else
|
|
O << TAI->getCOMMDirective() << name << "," << Size;
|
|
} else {
|
|
if (I->hasInternalLinkage())
|
|
O << "\t.local\t" << name << "\n";
|
|
|
|
O << TAI->getCOMMDirective() <<"\t" << name << " " <<"RES"<< " "
|
|
<< Size;
|
|
O << "\n\t\tGLOBAL" <<" "<< name;
|
|
if (TAI->getCOMMDirectiveTakesAlignment())
|
|
O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (I->getLinkage()) {
|
|
case GlobalValue::AppendingLinkage:
|
|
// FIXME: appending linkage variables should go into a section of
|
|
// their name or something. For now, just emit them as external.
|
|
// FALL THROUGH
|
|
|
|
case GlobalValue::ExternalLinkage:
|
|
O << "\t.globl " << name << "\n";
|
|
// FALL THROUGH
|
|
|
|
case GlobalValue::InternalLinkage:
|
|
if (I->isConstant()) {
|
|
const ConstantArray *CVA = dyn_cast<ConstantArray>(C);
|
|
if (TAI->getCStringSection() && CVA && CVA->isCString()) {
|
|
SwitchToDataSection(TAI->getCStringSection(), I);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(0 && "Unknown linkage type!");
|
|
break;
|
|
} // end switch.
|
|
|
|
EmitAlignment(Align, I);
|
|
O << name << ":\t\t\t\t" << TAI->getCommentString() << " " << I->getName()
|
|
<< "\n";
|
|
|
|
// If the initializer is a extern weak symbol, remember to emit the weak
|
|
// reference!
|
|
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
|
|
if (GV->hasExternalWeakLinkage())
|
|
ExtWeakSymbols.insert(GV);
|
|
|
|
EmitGlobalConstant(C);
|
|
O << '\n';
|
|
} // end for.
|
|
|
|
O << "\n "<< "END";
|
|
return AsmPrinter::doFinalization(M);
|
|
}
|
|
|
|
void PIC16AsmPrinter::
|
|
SwitchToTextSection(const char *NewSection, const GlobalValue *GV)
|
|
{
|
|
O << "\n";
|
|
if (NewSection && *NewSection) {
|
|
std::string codeSection = "code_";
|
|
codeSection += NewSection;
|
|
codeSection += " ";
|
|
codeSection += "CODE";
|
|
AsmPrinter::SwitchToTextSection(codeSection.c_str(), GV);
|
|
}
|
|
else
|
|
AsmPrinter::SwitchToTextSection(NewSection, GV);
|
|
}
|
|
|
|
void PIC16AsmPrinter::
|
|
SwitchToDataSection(const char *NewSection, const GlobalValue *GV)
|
|
{
|
|
// Need to append index for page.
|
|
O << "\n";
|
|
if (NewSection && *NewSection) {
|
|
std::string dataSection = "udata_";
|
|
dataSection += NewSection;
|
|
if (dataSection.substr(dataSection.length() - 2).compare(".o") == 0) {
|
|
dataSection = dataSection.substr(0, dataSection.length() - 2);
|
|
}
|
|
dataSection += " ";
|
|
dataSection += "UDATA";
|
|
AsmPrinter::SwitchToDataSection(dataSection.c_str(), GV);
|
|
}
|
|
else
|
|
AsmPrinter::SwitchToDataSection(NewSection, GV);
|
|
}
|
|
|
|
void PIC16AsmPrinter::
|
|
SwitchToDataOvrSection(const char *NewSection, const GlobalValue *GV)
|
|
{
|
|
O << "\n";
|
|
if (NewSection && *NewSection) {
|
|
std::string dataSection = "frame_";
|
|
dataSection += NewSection;
|
|
if (dataSection.substr(dataSection.length() - 2).compare(".o") == 0) {
|
|
dataSection = dataSection.substr(0, dataSection.length() - 2);
|
|
}
|
|
dataSection += "_";
|
|
dataSection += CurrentFnName;
|
|
dataSection += " ";
|
|
dataSection += "UDATA_OVR";
|
|
AsmPrinter::SwitchToDataSection(dataSection.c_str(), GV);
|
|
}
|
|
else
|
|
AsmPrinter::SwitchToDataSection(NewSection, GV);
|
|
}
|