Start creating the infrastructure for producing valid assembly for ORCA/M or Merlin.

This commit is contained in:
Jeremy Rand 2016-04-19 23:39:53 -04:00
parent 2253ae62fc
commit f0e0e4ec4a
8 changed files with 92 additions and 292 deletions

View File

@ -1,6 +1,7 @@
add_llvm_library(LLVMWDC65816Desc
WDC65816MCTargetDesc.cpp
WDC65816MCAsmInfo.cpp
WDC65816TargetStreamer.cpp
)
add_dependencies(LLVMWDC65816Desc WDC65816CommonTableGen)

View File

@ -16,14 +16,17 @@
using namespace llvm;
void WDC65816ELFMCAsmInfo::anchor() { }
void WDC65816MCAsmInfo::anchor() { }
WDC65816ELFMCAsmInfo::WDC65816ELFMCAsmInfo(StringRef TT) {
WDC65816MCAsmInfo::WDC65816MCAsmInfo(StringRef TT) {
IsLittleEndian = true;
Triple TheTriple(TT);
PointerSize = CalleeSaveStackSlotSize = 4;
// Disable the ".file <filename>" parameter
HasSingleParameterDotFile = false;
#if 0 // WDC_TODO - Do I need any of this?
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";

View File

@ -14,15 +14,15 @@
#ifndef WDC65816TARGETASMINFO_H
#define WDC65816TARGETASMINFO_H
#include "llvm/MC/MCAsmInfoELF.h"
#include "llvm/MC/MCAsmInfo.h"
namespace llvm {
class StringRef;
class WDC65816ELFMCAsmInfo : public MCAsmInfoELF {
class WDC65816MCAsmInfo : public MCAsmInfo {
virtual void anchor();
public:
explicit WDC65816ELFMCAsmInfo(StringRef TT);
explicit WDC65816MCAsmInfo(StringRef TT);
};
} // namespace llvm

View File

@ -13,6 +13,7 @@
#include "WDC65816MCTargetDesc.h"
#include "WDC65816MCAsmInfo.h"
#include "WDC65816TargetStreamer.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
@ -65,9 +66,22 @@ static MCCodeGenInfo *createWDC65816MCCodeGenInfo(StringRef TT, Reloc::Model RM,
}
static MCStreamer *
createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
bool isVerboseAsm, bool useLoc, bool useCFI,
bool useDwarfDirectory, MCInstPrinter *InstPrint,
MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) {
WDC65816TargetStreamer *S = new WDC65816TargetAsmStreamer(OS);
return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI,
useDwarfDirectory, InstPrint, CE, TAB,
ShowInst);
}
extern "C" void LLVMInitializeWDC65816TargetMC() {
// Register the MC asm info.
RegisterMCAsmInfo<WDC65816ELFMCAsmInfo> X(TheWDC65816Target);
RegisterMCAsmInfo<WDC65816MCAsmInfo> X(TheWDC65816Target);
// Register the MC codegen info.
TargetRegistry::RegisterMCCodeGenInfo(TheWDC65816Target,
@ -82,4 +96,7 @@ extern "C" void LLVMInitializeWDC65816TargetMC() {
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(TheWDC65816Target,
createWDC65816MCSubtargetInfo);
// Register the asm streamer.
TargetRegistry::RegisterAsmStreamer(TheWDC65816Target, createMCAsmStreamer);
}

View File

@ -0,0 +1,22 @@
//
// WDC65816TargetAsmStreamer.cpp
// llvm
//
// Created by Jeremy Rand on 2016-04-11.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#include "WDC65816TargetStreamer.h"
using namespace llvm;
// pin vtable to this file
void WDC65816TargetStreamer::anchor() {}
WDC65816TargetAsmStreamer::~WDC65816TargetAsmStreamer()
{
}

View File

@ -0,0 +1,34 @@
//
// WDC65816TargetAsmStreamer.h
// llvm
//
// Created by Jeremy Rand on 2016-04-11.
// Copyright © 2016 Jeremy Rand. All rights reserved.
//
#ifndef WDC65816TargetStreamer_h
#define WDC65816TargetStreamer_h
#include "llvm/MC/MCStreamer.h"
namespace llvm {
class WDC65816TargetStreamer : public MCTargetStreamer {
virtual void anchor();
public:
// Add pure virtual functions here to the base class...
};
class WDC65816TargetAsmStreamer : public WDC65816TargetStreamer {
formatted_raw_ostream &OS;
public:
WDC65816TargetAsmStreamer(formatted_raw_ostream &OS) : OS(OS) {}
virtual ~WDC65816TargetAsmStreamer();
};
}
#endif /* WDC65816TargetStreamer_h */

View File

@ -54,30 +54,6 @@ namespace {
printInstruction(MI, OS);
OutStreamer.EmitRawText(OS.str());
}
#if 0 // WDC_TODO - How much of this do we need?
void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
virtual void EmitFunctionBodyStart();
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O);
virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
const;
void EmitGlobalRegisterDecl(unsigned reg) {
SmallString<128> Str;
raw_svector_ostream OS(Str);
OS << "\t.register "
<< "%" << StringRef(getRegisterName(reg)).lower()
<< ", "
<< ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch");
OutStreamer.EmitRawText(OS.str());
}
#endif
};
} // end of anonymous namespace
@ -94,7 +70,7 @@ void WDC65816AsmPrinter::printOperand(const MachineInstr *MI, int opNum,
O << StringRef(getRegisterName(MO.getReg()));
return;
case MachineOperand::MO_Immediate:
O << MO.getImm();
O << "#" << MO.getImm();
return;
case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
@ -123,259 +99,6 @@ bool WDC65816AsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum,
return true;
}
#if 0 // WDC_TODO - How much of this do we need?
void WDC65816AsmPrinter::EmitFunctionBodyStart() {
const MachineRegisterInfo &MRI = MF->getRegInfo();
const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
for (unsigned i = 0; globalRegs[i] != 0; ++i) {
unsigned reg = globalRegs[i];
if (MRI.use_empty(reg))
continue;
EmitGlobalRegisterDecl(reg);
}
}
void WDC65816AsmPrinter::printOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand (opNum);
unsigned TF = MO.getTargetFlags();
#ifndef NDEBUG
// Verify the target flags.
if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
if (MI->getOpcode() == SP::CALL)
assert(TF == SPII::MO_NO_FLAG &&
"Cannot handle target flags on call address");
else if (MI->getOpcode() == SP::SETHIi)
assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
|| TF == SPII::MO_TLS_GD_HI22
|| TF == SPII::MO_TLS_LDM_HI22
|| TF == SPII::MO_TLS_LDO_HIX22
|| TF == SPII::MO_TLS_IE_HI22
|| TF == SPII::MO_TLS_LE_HIX22) &&
"Invalid target flags for address operand on sethi");
else if (MI->getOpcode() == SP::TLS_CALL)
assert((TF == SPII::MO_NO_FLAG
|| TF == SPII::MO_TLS_GD_CALL
|| TF == SPII::MO_TLS_LDM_CALL) &&
"Cannot handle target flags on tls call address");
else if (MI->getOpcode() == SP::TLS_ADDrr)
assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD
|| TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) &&
"Cannot handle target flags on add for TLS");
else if (MI->getOpcode() == SP::TLS_LDrr)
assert(TF == SPII::MO_TLS_IE_LD &&
"Cannot handle target flags on ld for TLS");
else if (MI->getOpcode() == SP::TLS_LDXrr)
assert(TF == SPII::MO_TLS_IE_LDX &&
"Cannot handle target flags on ldx for TLS");
else if (MI->getOpcode() == SP::XORri)
assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
"Cannot handle target flags on xor for TLS");
else
assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44
|| TF == SPII::MO_HM
|| TF == SPII::MO_TLS_GD_LO10
|| TF == SPII::MO_TLS_LDM_LO10
|| TF == SPII::MO_TLS_IE_LO10 ) &&
"Invalid target flags for small address operand");
}
#endif
bool CloseParen = true;
switch (TF) {
default:
llvm_unreachable("Unknown target flags on operand");
case SPII::MO_NO_FLAG:
CloseParen = false;
break;
case SPII::MO_LO: O << "%lo("; break;
case SPII::MO_HI: O << "%hi("; break;
case SPII::MO_H44: O << "%h44("; break;
case SPII::MO_M44: O << "%m44("; break;
case SPII::MO_L44: O << "%l44("; break;
case SPII::MO_HH: O << "%hh("; break;
case SPII::MO_HM: O << "%hm("; break;
case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break;
case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break;
case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break;
case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break;
case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break;
case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break;
case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break;
case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break;
case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break;
case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break;
case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break;
case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break;
case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break;
case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break;
case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break;
case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break;
case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break;
case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break;
}
switch (MO.getType()) {
case MachineOperand::MO_Register:
O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
break;
case MachineOperand::MO_Immediate:
O << (int)MO.getImm();
break;
case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
return;
case MachineOperand::MO_GlobalAddress:
O << *getSymbol(MO.getGlobal());
break;
case MachineOperand::MO_BlockAddress:
O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();
break;
case MachineOperand::MO_ExternalSymbol:
O << MO.getSymbolName();
break;
case MachineOperand::MO_ConstantPoolIndex:
O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
<< MO.getIndex();
break;
default:
llvm_unreachable("<unknown operand type>");
}
if (CloseParen) O << ")";
}
void WDC65816AsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
raw_ostream &O, const char *Modifier) {
printOperand(MI, opNum, O);
// If this is an ADD operand, emit it like normal operands.
if (Modifier && !strcmp(Modifier, "arith")) {
O << ", ";
printOperand(MI, opNum+1, O);
return;
}
if (MI->getOperand(opNum+1).isReg() &&
MI->getOperand(opNum+1).getReg() == SP::G0)
return; // don't print "+%g0"
if (MI->getOperand(opNum+1).isImm() &&
MI->getOperand(opNum+1).getImm() == 0)
return; // don't print "+0"
O << "+";
printOperand(MI, opNum+1, O);
}
bool WDC65816AsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum,
raw_ostream &O) {
std::string operand = "";
const MachineOperand &MO = MI->getOperand(opNum);
switch (MO.getType()) {
default: llvm_unreachable("Operand is not a register");
case MachineOperand::MO_Register:
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
"Operand is not a physical register ");
assert(MO.getReg() != SP::O7 &&
"%o7 is assigned as destination for getpcx!");
operand = "%" + StringRef(getRegisterName(MO.getReg())).lower();
break;
}
unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber();
unsigned bbNum = MI->getParent()->getNumber();
O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n";
O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ;
O << "\t sethi\t"
<< "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
<< ")), " << operand << '\n' ;
O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ;
O << "\tor\t" << operand
<< ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
<< ")), " << operand << '\n';
O << "\tadd\t" << operand << ", %o7, " << operand << '\n';
return true;
}
void WDC65816AsmPrinter::printCCOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
int CC = (int)MI->getOperand(opNum).getImm();
O << SPARCCondCodeToString((SPCC::CondCodes)CC);
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool WDC65816AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode,
raw_ostream &O) {
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
default:
// See if this is a generic print operand
return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
case 'r':
break;
}
}
printOperand(MI, OpNo, O);
return false;
}
bool WDC65816AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo, unsigned AsmVariant,
const char *ExtraCode,
raw_ostream &O) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier
O << '[';
printMemOperand(MI, OpNo, O);
O << ']';
return false;
}
/// isBlockOnlyReachableByFallthough - Return true if the basic block has
/// exactly one predecessor and the control transfer mechanism between
/// the predecessor and this block is a fall-through.
///
/// This overrides AsmPrinter's implementation to handle delay slots.
bool WDC65816AsmPrinter::
isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
// If this is a landing pad, it isn't a fall through. If it has no preds,
// then nothing falls through to it.
if (MBB->isLandingPad() || MBB->pred_empty())
return false;
// If there isn't exactly one predecessor, it can't be a fall through.
MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
++PI2;
if (PI2 != MBB->pred_end())
return false;
// The predecessor has to be immediately before this block.
const MachineBasicBlock *Pred = *PI;
if (!Pred->isLayoutSuccessor(MBB))
return false;
// Check if the last terminator is an unconditional branch.
MachineBasicBlock::const_iterator I = Pred->end();
while (I != Pred->begin() && !(--I)->isTerminator())
; // Noop
return I == Pred->end() || !I->isBarrier();
}
#endif
// Force static initialization.
extern "C" void LLVMInitializeWDC65816AsmPrinter() {

View File

@ -110,7 +110,7 @@ def WDCRET : SDNode<"WDCISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNP
def ADCimm : Group1<OpGrp1ADC, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins AccRegs:$src1, i16imm:$src2),
"ADC #>$src2",
"ADC $src2",
[(set AccRegs:$dst, (add AccRegs:$src1, imm:$src2))]>;
def ADCabs : Group1<OpGrp1ADC, AddrModeGrp1Abs,
@ -185,7 +185,7 @@ def ADCsrindir : Group1<OpGrp1ADC, AddrModeGrp1StackRelIndirIdxY,
def ANDimm : Group1<OpGrp1AND, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins AccRegs:$src1, i16imm:$src2),
"AND #>$src2",
"AND $src2",
[(set AccRegs:$dst, (and AccRegs:$src1, imm:$src2))]>;
def ANDabs : Group1<OpGrp1AND, AddrModeGrp1Abs,
@ -260,7 +260,7 @@ def ANDsrindir : Group1<OpGrp1AND, AddrModeGrp1StackRelIndirIdxY,
def CMPimm : Group1<OpGrp1CMP, AddrModeGrp1Imm,
(outs ), (ins AccRegs:$src1, i16imm:$src2),
"CMP #>$src2",
"CMP $src2",
[]>;
def CMPabs : Group1<OpGrp1CMP, AddrModeGrp1Abs,
@ -335,7 +335,7 @@ def CMPsrindir : Group1<OpGrp1CMP, AddrModeGrp1StackRelIndirIdxY,
def EORimm : Group1<OpGrp1EOR, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins AccRegs:$src1, i16imm:$src2),
"EOR #>$src2",
"EOR $src2",
[(set AccRegs:$dst, (xor AccRegs:$src1, imm:$src2))]>;
def EORabs : Group1<OpGrp1EOR, AddrModeGrp1Abs,
@ -410,7 +410,7 @@ def EORsrindir : Group1<OpGrp1EOR, AddrModeGrp1StackRelIndirIdxY,
def LDAimm : Group1<OpGrp1LDA, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins i16imm:$src),
"LDA #>$src",
"LDA $src",
[(set AccRegs:$dst, imm:$src)]>;
def LDAabs : Group1<OpGrp1LDA, AddrModeGrp1Abs,
@ -485,7 +485,7 @@ def LDAsrindir : Group1<OpGrp1LDA, AddrModeGrp1StackRelIndirIdxY,
def ORAimm : Group1<OpGrp1ORA, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins AccRegs:$src1, i16imm:$src2),
"ORA #>$src2",
"ORA $src2",
[(set AccRegs:$dst, (or AccRegs:$src1, imm:$src2))]>;
def ORAabs : Group1<OpGrp1ORA, AddrModeGrp1Abs,
@ -560,7 +560,7 @@ def ORAsrindir : Group1<OpGrp1ORA, AddrModeGrp1StackRelIndirIdxY,
def SBCimm : Group1<OpGrp1SBC, AddrModeGrp1Imm,
(outs AccRegs:$dst), (ins AccRegs:$src1, i16imm:$src2),
"SBC #>$src2",
"SBC $src2",
[(set AccRegs:$dst, (sub AccRegs:$src1, imm:$src2))]>;
def SBCabs : Group1<OpGrp1SBC, AddrModeGrp1Abs,
@ -968,7 +968,7 @@ def BEQ : Group3<OpGrp3BEQ,
def BITimm : Group3<OpGrp3BITImm,
(outs ), (ins AccRegs:$src1, i16imm:$src2),
"BIT #>$src2",
"BIT $src2",
[]>;
def BITabs : Group3<OpGrp3BITAbs,