Clone "Sparc" target as "Mos6502"

All string occurences for "sparc", "Sparc" and "SPARC" were already
replaced, with the exception of ELF constans in the object file
descriptor as it will get removed later on (we won't be building ELF
object files for the 6502).
This commit is contained in:
Damián Silvani 2015-08-02 20:11:14 -03:00
parent 5bb95798bc
commit 642eccbb21
64 changed files with 13622 additions and 0 deletions

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMMos6502AsmParser
Mos6502AsmParser.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/Mos6502/AsmParser/LLVMBuild.txt ---------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Mos6502AsmParser
parent = Mos6502
required_libraries = MC MCParser Mos6502Desc Mos6502Info Support
add_to_library_groups = Mos6502

View File

@ -0,0 +1,15 @@
##===- lib/Target/Mos6502/AsmParser/Makefile ------------------*- Makefile-*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMMos6502AsmParser
# Hack: we need to include 'main' Mos6502 target directory to grab private headers
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
set(LLVM_TARGET_DEFINITIONS Mos6502.td)
tablegen(LLVM Mos6502GenRegisterInfo.inc -gen-register-info)
tablegen(LLVM Mos6502GenInstrInfo.inc -gen-instr-info)
tablegen(LLVM Mos6502GenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM Mos6502GenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM Mos6502GenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM Mos6502GenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM Mos6502GenDAGISel.inc -gen-dag-isel)
tablegen(LLVM Mos6502GenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM Mos6502GenCallingConv.inc -gen-callingconv)
add_public_tablegen_target(Mos6502CommonTableGen)
add_llvm_target(Mos6502CodeGen
DelaySlotFiller.cpp
Mos6502AsmPrinter.cpp
Mos6502InstrInfo.cpp
Mos6502ISelDAGToDAG.cpp
Mos6502ISelLowering.cpp
Mos6502FrameLowering.cpp
Mos6502MachineFunctionInfo.cpp
Mos6502RegisterInfo.cpp
Mos6502Subtarget.cpp
Mos6502TargetMachine.cpp
Mos6502MCInstLower.cpp
Mos6502TargetObjectFile.cpp
)
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(InstPrinter)
add_subdirectory(AsmParser)
add_subdirectory(Disassembler)

View File

@ -0,0 +1,495 @@
//===-- DelaySlotFiller.cpp - MOS6502 delay slot filler ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a simple local pass that attempts to fill delay slots with useful
// instructions. If no instructions can be moved into the delay slot, then a
// NOP is placed.
//===----------------------------------------------------------------------===//
#include "Mos6502.h"
#include "Mos6502Subtarget.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;
#define DEBUG_TYPE "delay-slot-filler"
STATISTIC(FilledSlots, "Number of delay slots filled");
static cl::opt<bool> DisableDelaySlotFiller(
"disable-mos6502-delay-filler",
cl::init(false),
cl::desc("Disable the Mos6502 delay slot filler."),
cl::Hidden);
namespace {
struct Filler : public MachineFunctionPass {
/// Target machine description which we query for reg. names, data
/// layout, etc.
///
TargetMachine &TM;
const Mos6502Subtarget *Subtarget;
static char ID;
Filler(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) {}
const char *getPassName() const override {
return "MOS6502 Delay Slot Filler";
}
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
bool runOnMachineFunction(MachineFunction &F) override {
bool Changed = false;
Subtarget = &F.getSubtarget<Mos6502Subtarget>();
// This pass invalidates liveness information when it reorders
// instructions to fill delay slot.
F.getRegInfo().invalidateLiveness();
for (MachineFunction::iterator FI = F.begin(), FE = F.end();
FI != FE; ++FI)
Changed |= runOnMachineBasicBlock(*FI);
return Changed;
}
void insertCallDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses);
void insertDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses);
bool IsRegInSet(SmallSet<unsigned, 32>& RegSet,
unsigned Reg);
bool delayHasHazard(MachineBasicBlock::iterator candidate,
bool &sawLoad, bool &sawStore,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses);
MachineBasicBlock::iterator
findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot);
bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize);
bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI);
};
char Filler::ID = 0;
} // end of anonymous namespace
/// createMos6502DelaySlotFillerPass - Returns a pass that fills in delay
/// slots in Mos6502 MachineFunctions
///
FunctionPass *llvm::createMos6502DelaySlotFillerPass(TargetMachine &tm) {
return new Filler(tm);
}
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
/// We assume there is only one delay slot per delayed instruction.
///
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
bool Changed = false;
Subtarget = &MBB.getParent()->getSubtarget<Mos6502Subtarget>();
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
MachineBasicBlock::iterator MI = I;
++I;
// If MI is restore, try combining it with previous inst.
if (!DisableDelaySlotFiller &&
(MI->getOpcode() == SP::RESTORErr
|| MI->getOpcode() == SP::RESTOREri)) {
Changed |= tryCombineRestoreWithPrevInst(MBB, MI);
continue;
}
if (!Subtarget->isV9() &&
(MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD
|| MI->getOpcode() == SP::FCMPQ)) {
BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
Changed = true;
continue;
}
// If MI has no delay slot, skip.
if (!MI->hasDelaySlot())
continue;
MachineBasicBlock::iterator D = MBB.end();
if (!DisableDelaySlotFiller)
D = findDelayInstr(MBB, MI);
++FilledSlots;
Changed = true;
if (D == MBB.end())
BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
else
MBB.splice(I, &MBB, D);
unsigned structSize = 0;
if (needsUnimp(MI, structSize)) {
MachineBasicBlock::iterator J = MI;
++J; // skip the delay filler.
assert (J != MBB.end() && "MI needs a delay instruction.");
BuildMI(MBB, ++J, MI->getDebugLoc(),
TII->get(SP::UNIMP)).addImm(structSize);
// Bundle the delay filler and unimp with the instruction.
MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J);
} else {
MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I);
}
}
return Changed;
}
MachineBasicBlock::iterator
Filler::findDelayInstr(MachineBasicBlock &MBB,
MachineBasicBlock::iterator slot)
{
SmallSet<unsigned, 32> RegDefs;
SmallSet<unsigned, 32> RegUses;
bool sawLoad = false;
bool sawStore = false;
if (slot == MBB.begin())
return MBB.end();
if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL)
return MBB.end();
if (slot->getOpcode() == SP::RETL) {
MachineBasicBlock::iterator J = slot;
--J;
if (J->getOpcode() == SP::RESTORErr
|| J->getOpcode() == SP::RESTOREri) {
// change retl to ret.
slot->setDesc(Subtarget->getInstrInfo()->get(SP::RET));
return J;
}
}
// Call's delay filler can def some of call's uses.
if (slot->isCall())
insertCallDefsUses(slot, RegDefs, RegUses);
else
insertDefsUses(slot, RegDefs, RegUses);
bool done = false;
MachineBasicBlock::iterator I = slot;
while (!done) {
done = (I == MBB.begin());
if (!done)
--I;
// skip debug value
if (I->isDebugValue())
continue;
if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() ||
I->hasDelaySlot() || I->isBundledWithSucc())
break;
if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
insertDefsUses(I, RegDefs, RegUses);
continue;
}
return I;
}
return MBB.end();
}
bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate,
bool &sawLoad,
bool &sawStore,
SmallSet<unsigned, 32> &RegDefs,
SmallSet<unsigned, 32> &RegUses)
{
if (candidate->isImplicitDef() || candidate->isKill())
return true;
if (candidate->mayLoad()) {
sawLoad = true;
if (sawStore)
return true;
}
if (candidate->mayStore()) {
if (sawStore)
return true;
sawStore = true;
if (sawLoad)
return true;
}
for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) {
const MachineOperand &MO = candidate->getOperand(i);
if (!MO.isReg())
continue; // skip
unsigned Reg = MO.getReg();
if (MO.isDef()) {
// check whether Reg is defined or used before delay slot.
if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg))
return true;
}
if (MO.isUse()) {
// check whether Reg is defined before delay slot.
if (IsRegInSet(RegDefs, Reg))
return true;
}
}
return false;
}
void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses)
{
// Call defines o7, which is visible to the instruction in delay slot.
RegDefs.insert(SP::O7);
switch(MI->getOpcode()) {
default: llvm_unreachable("Unknown opcode.");
case SP::CALL: break;
case SP::CALLrr:
case SP::CALLri:
assert(MI->getNumOperands() >= 2);
const MachineOperand &Reg = MI->getOperand(0);
assert(Reg.isReg() && "CALL first operand is not a register.");
assert(Reg.isUse() && "CALL first operand is not a use.");
RegUses.insert(Reg.getReg());
const MachineOperand &RegOrImm = MI->getOperand(1);
if (RegOrImm.isImm())
break;
assert(RegOrImm.isReg() && "CALLrr second operand is not a register.");
assert(RegOrImm.isUse() && "CALLrr second operand is not a use.");
RegUses.insert(RegOrImm.getReg());
break;
}
}
// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
SmallSet<unsigned, 32>& RegDefs,
SmallSet<unsigned, 32>& RegUses)
{
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
if (Reg == 0)
continue;
if (MO.isDef())
RegDefs.insert(Reg);
if (MO.isUse()) {
// Implicit register uses of retl are return values and
// retl does not use them.
if (MO.isImplicit() && MI->getOpcode() == SP::RETL)
continue;
RegUses.insert(Reg);
}
}
}
// returns true if the Reg or its alias is in the RegSet.
bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg)
{
// Check Reg and all aliased Registers.
for (MCRegAliasIterator AI(Reg, Subtarget->getRegisterInfo(), true);
AI.isValid(); ++AI)
if (RegSet.count(*AI))
return true;
return false;
}
bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
{
if (!I->isCall())
return false;
unsigned structSizeOpNum = 0;
switch (I->getOpcode()) {
default: llvm_unreachable("Unknown call opcode.");
case SP::CALL: structSizeOpNum = 1; break;
case SP::CALLrr:
case SP::CALLri: structSizeOpNum = 2; break;
case SP::TLS_CALL: return false;
}
const MachineOperand &MO = I->getOperand(structSizeOpNum);
if (!MO.isImm())
return false;
StructSize = MO.getImm();
return true;
}
static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
MachineBasicBlock::iterator AddMI,
const TargetInstrInfo *TII)
{
// Before: add <op0>, <op1>, %i[0-7]
// restore %g0, %g0, %i[0-7]
//
// After : restore <op0>, <op1>, %o[0-7]
unsigned reg = AddMI->getOperand(0).getReg();
if (reg < SP::I0 || reg > SP::I7)
return false;
// Erase RESTORE.
RestoreMI->eraseFromParent();
// Change ADD to RESTORE.
AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr)
? SP::RESTORErr
: SP::RESTOREri));
// Map the destination register.
AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
return true;
}
static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
MachineBasicBlock::iterator OrMI,
const TargetInstrInfo *TII)
{
// Before: or <op0>, <op1>, %i[0-7]
// restore %g0, %g0, %i[0-7]
// and <op0> or <op1> is zero,
//
// After : restore <op0>, <op1>, %o[0-7]
unsigned reg = OrMI->getOperand(0).getReg();
if (reg < SP::I0 || reg > SP::I7)
return false;
// check whether it is a copy.
if (OrMI->getOpcode() == SP::ORrr
&& OrMI->getOperand(1).getReg() != SP::G0
&& OrMI->getOperand(2).getReg() != SP::G0)
return false;
if (OrMI->getOpcode() == SP::ORri
&& OrMI->getOperand(1).getReg() != SP::G0
&& (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
return false;
// Erase RESTORE.
RestoreMI->eraseFromParent();
// Change OR to RESTORE.
OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr)
? SP::RESTORErr
: SP::RESTOREri));
// Map the destination register.
OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
return true;
}
static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,
MachineBasicBlock::iterator SetHiMI,
const TargetInstrInfo *TII)
{
// Before: sethi imm3, %i[0-7]
// restore %g0, %g0, %g0
//
// After : restore %g0, (imm3<<10), %o[0-7]
unsigned reg = SetHiMI->getOperand(0).getReg();
if (reg < SP::I0 || reg > SP::I7)
return false;
if (!SetHiMI->getOperand(1).isImm())
return false;
int64_t imm = SetHiMI->getOperand(1).getImm();
// Is it a 3 bit immediate?
if (!isInt<3>(imm))
return false;
// Make it a 13 bit immediate.
imm = (imm << 10) & 0x1FFF;
assert(RestoreMI->getOpcode() == SP::RESTORErr);
RestoreMI->setDesc(TII->get(SP::RESTOREri));
RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
RestoreMI->getOperand(1).setReg(SP::G0);
RestoreMI->getOperand(2).ChangeToImmediate(imm);
// Erase the original SETHI.
SetHiMI->eraseFromParent();
return true;
}
bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI)
{
// No previous instruction.
if (MBBI == MBB.begin())
return false;
// assert that MBBI is a "restore %g0, %g0, %g0".
assert(MBBI->getOpcode() == SP::RESTORErr
&& MBBI->getOperand(0).getReg() == SP::G0
&& MBBI->getOperand(1).getReg() == SP::G0
&& MBBI->getOperand(2).getReg() == SP::G0);
MachineBasicBlock::iterator PrevInst = std::prev(MBBI);
// It cannot be combined with a bundled instruction.
if (PrevInst->isBundledWithSucc())
return false;
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
switch (PrevInst->getOpcode()) {
default: break;
case SP::ADDrr:
case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
case SP::ORrr:
case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break;
case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
}
// It cannot combine with the previous instruction.
return false;
}

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMMos6502Disassembler
Mos6502Disassembler.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/Mos6502/Disassembler/LLVMBuild.txt ------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Mos6502Disassembler
parent = Mos6502
required_libraries = MCDisassembler Mos6502Info Support
add_to_library_groups = Mos6502

View File

@ -0,0 +1,16 @@
##===- lib/Target/Mos6502/Disassembler/Makefile --------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMMos6502Disassembler
# Hack: we need to include 'main' Mos6502 target directory to grab private headers
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,497 @@
//===- Mos6502Disassembler.cpp - Disassembler for Mos6502 -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is part of the Mos6502 Disassembler.
//
//===----------------------------------------------------------------------===//
#include "Mos6502.h"
#include "Mos6502RegisterInfo.h"
#include "Mos6502Subtarget.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
#define DEBUG_TYPE "mos6502-disassembler"
typedef MCDisassembler::DecodeStatus DecodeStatus;
namespace {
/// A disassembler class for Mos6502.
class Mos6502Disassembler : public MCDisassembler {
public:
Mos6502Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
: MCDisassembler(STI, Ctx) {}
virtual ~Mos6502Disassembler() {}
DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes, uint64_t Address,
raw_ostream &VStream,
raw_ostream &CStream) const override;
};
}
namespace llvm {
extern Target TheMos6502Target, TheMos6502V9Target, TheMos6502elTarget;
}
static MCDisassembler *createMos6502Disassembler(const Target &T,
const MCSubtargetInfo &STI,
MCContext &Ctx) {
return new Mos6502Disassembler(STI, Ctx);
}
extern "C" void LLVMInitializeMos6502Disassembler() {
// Register the disassembler.
TargetRegistry::RegisterMCDisassembler(TheMos6502Target,
createMos6502Disassembler);
TargetRegistry::RegisterMCDisassembler(TheMos6502V9Target,
createMos6502Disassembler);
TargetRegistry::RegisterMCDisassembler(TheMos6502elTarget,
createMos6502Disassembler);
}
static const unsigned IntRegDecoderTable[] = {
SP::G0, SP::G1, SP::G2, SP::G3,
SP::G4, SP::G5, SP::G6, SP::G7,
SP::O0, SP::O1, SP::O2, SP::O3,
SP::O4, SP::O5, SP::O6, SP::O7,
SP::L0, SP::L1, SP::L2, SP::L3,
SP::L4, SP::L5, SP::L6, SP::L7,
SP::I0, SP::I1, SP::I2, SP::I3,
SP::I4, SP::I5, SP::I6, SP::I7 };
static const unsigned FPRegDecoderTable[] = {
SP::F0, SP::F1, SP::F2, SP::F3,
SP::F4, SP::F5, SP::F6, SP::F7,
SP::F8, SP::F9, SP::F10, SP::F11,
SP::F12, SP::F13, SP::F14, SP::F15,
SP::F16, SP::F17, SP::F18, SP::F19,
SP::F20, SP::F21, SP::F22, SP::F23,
SP::F24, SP::F25, SP::F26, SP::F27,
SP::F28, SP::F29, SP::F30, SP::F31 };
static const unsigned DFPRegDecoderTable[] = {
SP::D0, SP::D16, SP::D1, SP::D17,
SP::D2, SP::D18, SP::D3, SP::D19,
SP::D4, SP::D20, SP::D5, SP::D21,
SP::D6, SP::D22, SP::D7, SP::D23,
SP::D8, SP::D24, SP::D9, SP::D25,
SP::D10, SP::D26, SP::D11, SP::D27,
SP::D12, SP::D28, SP::D13, SP::D29,
SP::D14, SP::D30, SP::D15, SP::D31 };
static const unsigned QFPRegDecoderTable[] = {
SP::Q0, SP::Q8, ~0U, ~0U,
SP::Q1, SP::Q9, ~0U, ~0U,
SP::Q2, SP::Q10, ~0U, ~0U,
SP::Q3, SP::Q11, ~0U, ~0U,
SP::Q4, SP::Q12, ~0U, ~0U,
SP::Q5, SP::Q13, ~0U, ~0U,
SP::Q6, SP::Q14, ~0U, ~0U,
SP::Q7, SP::Q15, ~0U, ~0U } ;
static const unsigned FCCRegDecoderTable[] = {
SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 };
static const unsigned ASRRegDecoderTable[] = {
SP::Y, SP::ASR1, SP::ASR2, SP::ASR3,
SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7,
SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11,
SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = IntRegDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = IntRegDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = FPRegDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
static DecodeStatus DecodeDFPRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = DFPRegDecoderTable[RegNo];
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst,
unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
unsigned Reg = QFPRegDecoderTable[RegNo];
if (Reg == ~0U)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}
static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 3)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(FCCRegDecoderTable[RegNo]));
return MCDisassembler::Success;
}
static DecodeStatus DecodeASRRegsRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
if (RegNo > 31)
return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createReg(ASRRegDecoderTable[RegNo]));
return MCDisassembler::Success;
}
static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeCall(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeSIMM13(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeJMPL(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeSWAP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder);
#include "Mos6502GenDisassemblerTables.inc"
/// Read four bytes from the ArrayRef and return 32 bit word.
static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
uint64_t &Size, uint32_t &Insn,
bool IsLittleEndian) {
// We want to read exactly 4 Bytes of data.
if (Bytes.size() < 4) {
Size = 0;
return MCDisassembler::Fail;
}
Insn = IsLittleEndian
? (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) |
(Bytes[3] << 24)
: (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) |
(Bytes[0] << 24);
return MCDisassembler::Success;
}
DecodeStatus Mos6502Disassembler::getInstruction(MCInst &Instr, uint64_t &Size,
ArrayRef<uint8_t> Bytes,
uint64_t Address,
raw_ostream &VStream,
raw_ostream &CStream) const {
uint32_t Insn;
bool isLittleEndian = getContext().getAsmInfo()->isLittleEndian();
DecodeStatus Result =
readInstruction32(Bytes, Address, Size, Insn, isLittleEndian);
if (Result == MCDisassembler::Fail)
return MCDisassembler::Fail;
// Calling the auto-generated decoder function.
Result =
decodeInstruction(DecoderTableMos650232, Instr, Insn, Address, this, STI);
if (Result != MCDisassembler::Fail) {
Size = 4;
return Result;
}
return MCDisassembler::Fail;
}
typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder);
static DecodeStatus DecodeMem(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder,
bool isLoad, DecodeFunc DecodeRD) {
unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
bool isImm = fieldFromInstruction(insn, 13, 1);
bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
unsigned asi = fieldFromInstruction(insn, 5, 8);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);
DecodeStatus status;
if (isLoad) {
status = DecodeRD(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
// Decode rs1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode imm|rs2.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
if (hasAsi)
MI.addOperand(MCOperand::createImm(asi));
if (!isLoad) {
status = DecodeRD(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}
static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeIntRegsRegisterClass);
}
static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeFPRegsRegisterClass);
}
static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeDFPRegsRegisterClass);
}
static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, true,
DecodeQFPRegsRegisterClass);
}
static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeIntRegsRegisterClass);
}
static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address,
const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeFPRegsRegisterClass);
}
static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeDFPRegsRegisterClass);
}
static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn,
uint64_t Address, const void *Decoder) {
return DecodeMem(Inst, insn, Address, Decoder, false,
DecodeQFPRegsRegisterClass);
}
static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
uint64_t Address, uint64_t Offset,
uint64_t Width, MCInst &MI,
const void *Decoder) {
const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);
return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch,
Offset, Width);
}
static DecodeStatus DecodeCall(MCInst &MI, unsigned insn,
uint64_t Address, const void *Decoder) {
unsigned tgt = fieldFromInstruction(insn, 0, 30);
tgt <<= 2;
if (!tryAddingSymbolicOperand(tgt+Address, false, Address,
0, 30, MI, Decoder))
MI.addOperand(MCOperand::createImm(tgt));
return MCDisassembler::Success;
}
static DecodeStatus DecodeSIMM13(MCInst &MI, unsigned insn,
uint64_t Address, const void *Decoder) {
unsigned tgt = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
MI.addOperand(MCOperand::createImm(tgt));
return MCDisassembler::Success;
}
static DecodeStatus DecodeJMPL(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder) {
unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);
// Decode RD.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode RS1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode RS1 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}
static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder) {
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);
// Decode RS1.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode RS2 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
return MCDisassembler::Success;
}
static DecodeStatus DecodeSWAP(MCInst &MI, unsigned insn, uint64_t Address,
const void *Decoder) {
unsigned rd = fieldFromInstruction(insn, 25, 5);
unsigned rs1 = fieldFromInstruction(insn, 14, 5);
unsigned isImm = fieldFromInstruction(insn, 13, 1);
bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
unsigned asi = fieldFromInstruction(insn, 5, 8);
unsigned rs2 = 0;
unsigned simm13 = 0;
if (isImm)
simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
else
rs2 = fieldFromInstruction(insn, 0, 5);
// Decode RD.
DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode RS1.
status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
// Decode RS1 | SIMM13.
if (isImm)
MI.addOperand(MCOperand::createImm(simm13));
else {
status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
if (status != MCDisassembler::Success)
return status;
}
if (hasAsi)
MI.addOperand(MCOperand::createImm(asi));
return MCDisassembler::Success;
}

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMMos6502AsmPrinter
Mos6502InstPrinter.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/Mos6502/InstPrinter/LLVMBuild.txt -------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Mos6502AsmPrinter
parent = Mos6502
required_libraries = MC Support
add_to_library_groups = Mos6502

View File

@ -0,0 +1,16 @@
##===- lib/Target/Mos6502/InstPrinter/Makefile ---------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMMos6502AsmPrinter
# Hack: we need to include 'main' target directory to grab private headers
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,178 @@
//===-- Mos6502InstPrinter.cpp - Convert Mos6502 MCInst to assembly syntax -----==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class prints an Mos6502 MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#include "Mos6502InstPrinter.h"
#include "Mos6502.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
// The generated AsmMatcher Mos6502GenAsmWriter uses "Mos6502" as the target
// namespace. But MOS6502 backend uses "SP" as its namespace.
namespace llvm {
namespace Mos6502 {
using namespace SP;
}
}
#define GET_INSTRUCTION_NAME
#define PRINT_ALIAS_INSTR
#include "Mos6502GenAsmWriter.inc"
bool Mos6502InstPrinter::isV9(const MCSubtargetInfo &STI) const {
return (STI.getFeatureBits()[Mos6502::FeatureV9]) != 0;
}
void Mos6502InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
{
OS << '%' << StringRef(getRegisterName(RegNo)).lower();
}
void Mos6502InstPrinter::printInst(const MCInst *MI, raw_ostream &O,
StringRef Annot, const MCSubtargetInfo &STI) {
if (!printAliasInstr(MI, STI, O) && !printMos6502AliasInstr(MI, STI, O))
printInstruction(MI, STI, O);
printAnnotation(O, Annot);
}
bool Mos6502InstPrinter::printMos6502AliasInstr(const MCInst *MI,
const MCSubtargetInfo &STI,
raw_ostream &O) {
switch (MI->getOpcode()) {
default: return false;
case SP::JMPLrr:
case SP::JMPLri: {
if (MI->getNumOperands() != 3)
return false;
if (!MI->getOperand(0).isReg())
return false;
switch (MI->getOperand(0).getReg()) {
default: return false;
case SP::G0: // jmp $addr | ret | retl
if (MI->getOperand(2).isImm() &&
MI->getOperand(2).getImm() == 8) {
switch(MI->getOperand(1).getReg()) {
default: break;
case SP::I7: O << "\tret"; return true;
case SP::O7: O << "\tretl"; return true;
}
}
O << "\tjmp "; printMemOperand(MI, 1, STI, O);
return true;
case SP::O7: // call $addr
O << "\tcall "; printMemOperand(MI, 1, STI, O);
return true;
}
}
case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ:
case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: {
if (isV9(STI)
|| (MI->getNumOperands() != 3)
|| (!MI->getOperand(0).isReg())
|| (MI->getOperand(0).getReg() != SP::FCC0))
return false;
// if V8, skip printing %fcc0.
switch(MI->getOpcode()) {
default:
case SP::V9FCMPS: O << "\tfcmps "; break;
case SP::V9FCMPD: O << "\tfcmpd "; break;
case SP::V9FCMPQ: O << "\tfcmpq "; break;
case SP::V9FCMPES: O << "\tfcmpes "; break;
case SP::V9FCMPED: O << "\tfcmped "; break;
case SP::V9FCMPEQ: O << "\tfcmpeq "; break;
}
printOperand(MI, 1, STI, O);
O << ", ";
printOperand(MI, 2, STI, O);
return true;
}
}
}
void Mos6502InstPrinter::printOperand(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
const MCOperand &MO = MI->getOperand (opNum);
if (MO.isReg()) {
printRegName(O, MO.getReg());
return ;
}
if (MO.isImm()) {
O << (int)MO.getImm();
return;
}
assert(MO.isExpr() && "Unknown operand kind in printOperand");
MO.getExpr()->print(O, &MAI);
}
void Mos6502InstPrinter::printMemOperand(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI,
raw_ostream &O, const char *Modifier) {
printOperand(MI, opNum, STI, O);
// If this is an ADD operand, emit it like normal operands.
if (Modifier && !strcmp(Modifier, "arith")) {
O << ", ";
printOperand(MI, opNum+1, STI, O);
return;
}
const MCOperand &MO = MI->getOperand(opNum+1);
if (MO.isReg() && MO.getReg() == SP::G0)
return; // don't print "+%g0"
if (MO.isImm() && MO.getImm() == 0)
return; // don't print "+0"
O << "+";
printOperand(MI, opNum+1, STI, O);
}
void Mos6502InstPrinter::printCCOperand(const MCInst *MI, int opNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
int CC = (int)MI->getOperand(opNum).getImm();
switch (MI->getOpcode()) {
default: break;
case SP::FBCOND:
case SP::FBCONDA:
case SP::BPFCC:
case SP::BPFCCA:
case SP::BPFCCNT:
case SP::BPFCCANT:
case SP::MOVFCCrr: case SP::V9MOVFCCrr:
case SP::MOVFCCri: case SP::V9MOVFCCri:
case SP::FMOVS_FCC: case SP::V9FMOVS_FCC:
case SP::FMOVD_FCC: case SP::V9FMOVD_FCC:
case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC:
// Make sure CC is a fp conditional flag.
CC = (CC < 16) ? (CC + 16) : CC;
break;
}
O << MOS6502CondCodeToString((SPCC::CondCodes)CC);
}
bool Mos6502InstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
llvm_unreachable("FIXME: Implement Mos6502InstPrinter::printGetPCX.");
return true;
}

View File

@ -0,0 +1,58 @@
//===-- Mos6502InstPrinter.h - Convert Mos6502 MCInst to assembly syntax ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class prints an Mos6502 MCInst to a .s file.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_INSTPRINTER_MOS6502INSTPRINTER_H
#define LLVM_LIB_TARGET_MOS6502_INSTPRINTER_MOS6502INSTPRINTER_H
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCSubtargetInfo.h"
namespace llvm {
class MCOperand;
class Mos6502InstPrinter : public MCInstPrinter {
public:
Mos6502InstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI)
: MCInstPrinter(MAI, MII, MRI) {}
void printRegName(raw_ostream &OS, unsigned RegNo) const override;
void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
const MCSubtargetInfo &STI) override;
bool printMos6502AliasInstr(const MCInst *MI, const MCSubtargetInfo &STI,
raw_ostream &OS);
bool isV9(const MCSubtargetInfo &STI) const;
// Autogenerated by tblgen.
void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI,
raw_ostream &O);
bool printAliasInstr(const MCInst *MI, const MCSubtargetInfo &STI,
raw_ostream &O);
void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
unsigned PrintMethodIdx,
const MCSubtargetInfo &STI, raw_ostream &O);
static const char *getRegisterName(unsigned RegNo);
void printOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &OS);
void printMemOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &OS, const char *Modifier = nullptr);
void printCCOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
raw_ostream &OS);
bool printGetPCX(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &OS);
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,36 @@
;===- ./lib/Target/Mos6502/LLVMBuild.tx-------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[common]
subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo
[component_0]
type = TargetGroup
name = Mos6502
parent = Target
has_asmparser = 1
has_asmprinter = 1
has_disassembler = 1
has_jit = 1
[component_1]
type = Library
name = Mos6502CodeGen
parent = Mos6502
required_libraries = AsmPrinter CodeGen Core MC SelectionDAG Mos6502AsmPrinter
Mos6502Desc Mos6502Info Support Target
add_to_library_groups = Mos6502

View File

@ -0,0 +1,9 @@
add_llvm_library(LLVMMos6502Desc
Mos6502AsmBackend.cpp
Mos6502ELFObjectWriter.cpp
Mos6502MCAsmInfo.cpp
Mos6502MCCodeEmitter.cpp
Mos6502MCTargetDesc.cpp
Mos6502MCExpr.cpp
Mos6502TargetStreamer.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/Mos6502/MCTargetDesc/LLVMBuild.txt ------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Mos6502Desc
parent = Mos6502
required_libraries = MC Mos6502AsmPrinter Mos6502Info Support
add_to_library_groups = Mos6502

View File

@ -0,0 +1,16 @@
##===- lib/Target/Mos6502/TargetDesc/Makefile ----------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMMos6502Desc
# Hack: we need to include 'main' target directory to grab private headers
CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,304 @@
//===-- Mos6502AsmBackend.cpp - Mos6502 Assembler Backend ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCAsmBackend.h"
#include "MCTargetDesc/Mos6502FixupKinds.h"
#include "MCTargetDesc/Mos6502MCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
switch (Kind) {
default:
llvm_unreachable("Unknown fixup kind!");
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
return Value;
case Mos6502::fixup_mos6502_wplt30:
case Mos6502::fixup_mos6502_call30:
return (Value >> 2) & 0x3fffffff;
case Mos6502::fixup_mos6502_br22:
return (Value >> 2) & 0x3fffff;
case Mos6502::fixup_mos6502_br19:
return (Value >> 2) & 0x7ffff;
case Mos6502::fixup_mos6502_br16_2:
return (Value >> 2) & 0xc000;
case Mos6502::fixup_mos6502_br16_14:
return (Value >> 2) & 0x3fff;
case Mos6502::fixup_mos6502_pc22:
case Mos6502::fixup_mos6502_got22:
case Mos6502::fixup_mos6502_tls_gd_hi22:
case Mos6502::fixup_mos6502_tls_ldm_hi22:
case Mos6502::fixup_mos6502_tls_ie_hi22:
case Mos6502::fixup_mos6502_hi22:
return (Value >> 10) & 0x3fffff;
case Mos6502::fixup_mos6502_pc10:
case Mos6502::fixup_mos6502_got10:
case Mos6502::fixup_mos6502_tls_gd_lo10:
case Mos6502::fixup_mos6502_tls_ldm_lo10:
case Mos6502::fixup_mos6502_tls_ie_lo10:
case Mos6502::fixup_mos6502_lo10:
return Value & 0x3ff;
case Mos6502::fixup_mos6502_tls_ldo_hix22:
case Mos6502::fixup_mos6502_tls_le_hix22:
return (~Value >> 10) & 0x3fffff;
case Mos6502::fixup_mos6502_tls_ldo_lox10:
case Mos6502::fixup_mos6502_tls_le_lox10:
return (~(~Value & 0x3ff)) & 0x1fff;
case Mos6502::fixup_mos6502_h44:
return (Value >> 22) & 0x3fffff;
case Mos6502::fixup_mos6502_m44:
return (Value >> 12) & 0x3ff;
case Mos6502::fixup_mos6502_l44:
return Value & 0xfff;
case Mos6502::fixup_mos6502_hh:
return (Value >> 42) & 0x3fffff;
case Mos6502::fixup_mos6502_hm:
return (Value >> 32) & 0x3ff;
case Mos6502::fixup_mos6502_tls_gd_add:
case Mos6502::fixup_mos6502_tls_gd_call:
case Mos6502::fixup_mos6502_tls_ldm_add:
case Mos6502::fixup_mos6502_tls_ldm_call:
case Mos6502::fixup_mos6502_tls_ldo_add:
case Mos6502::fixup_mos6502_tls_ie_ld:
case Mos6502::fixup_mos6502_tls_ie_ldx:
case Mos6502::fixup_mos6502_tls_ie_add:
return 0;
}
}
namespace {
class Mos6502AsmBackend : public MCAsmBackend {
protected:
const Target &TheTarget;
bool IsLittleEndian;
bool Is64Bit;
public:
Mos6502AsmBackend(const Target &T)
: MCAsmBackend(), TheTarget(T),
IsLittleEndian(StringRef(TheTarget.getName()) == "mos6502el"),
Is64Bit(StringRef(TheTarget.getName()) == "mos6502v9") {}
unsigned getNumFixupKinds() const override {
return Mos6502::NumTargetFixupKinds;
}
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
const static MCFixupKindInfo InfosBE[Mos6502::NumTargetFixupKinds] = {
// name offset bits flags
{ "fixup_mos6502_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br16_2", 10, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br16_14", 18, 14, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_hi22", 10, 22, 0 },
{ "fixup_mos6502_lo10", 22, 10, 0 },
{ "fixup_mos6502_h44", 10, 22, 0 },
{ "fixup_mos6502_m44", 22, 10, 0 },
{ "fixup_mos6502_l44", 20, 12, 0 },
{ "fixup_mos6502_hh", 10, 22, 0 },
{ "fixup_mos6502_hm", 22, 10, 0 },
{ "fixup_mos6502_pc22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_got22", 10, 22, 0 },
{ "fixup_mos6502_got10", 22, 10, 0 },
{ "fixup_mos6502_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_tls_gd_hi22", 10, 22, 0 },
{ "fixup_mos6502_tls_gd_lo10", 22, 10, 0 },
{ "fixup_mos6502_tls_gd_add", 0, 0, 0 },
{ "fixup_mos6502_tls_gd_call", 0, 0, 0 },
{ "fixup_mos6502_tls_ldm_hi22", 10, 22, 0 },
{ "fixup_mos6502_tls_ldm_lo10", 22, 10, 0 },
{ "fixup_mos6502_tls_ldm_add", 0, 0, 0 },
{ "fixup_mos6502_tls_ldm_call", 0, 0, 0 },
{ "fixup_mos6502_tls_ldo_hix22", 10, 22, 0 },
{ "fixup_mos6502_tls_ldo_lox10", 22, 10, 0 },
{ "fixup_mos6502_tls_ldo_add", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_hi22", 10, 22, 0 },
{ "fixup_mos6502_tls_ie_lo10", 22, 10, 0 },
{ "fixup_mos6502_tls_ie_ld", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_ldx", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_add", 0, 0, 0 },
{ "fixup_mos6502_tls_le_hix22", 0, 0, 0 },
{ "fixup_mos6502_tls_le_lox10", 0, 0, 0 }
};
const static MCFixupKindInfo InfosLE[Mos6502::NumTargetFixupKinds] = {
// name offset bits flags
{ "fixup_mos6502_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br16_2", 20, 2, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_br16_14", 0, 14, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_hi22", 0, 22, 0 },
{ "fixup_mos6502_lo10", 0, 10, 0 },
{ "fixup_mos6502_h44", 0, 22, 0 },
{ "fixup_mos6502_m44", 0, 10, 0 },
{ "fixup_mos6502_l44", 0, 12, 0 },
{ "fixup_mos6502_hh", 0, 22, 0 },
{ "fixup_mos6502_hm", 0, 10, 0 },
{ "fixup_mos6502_pc22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_pc10", 0, 10, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_got22", 0, 22, 0 },
{ "fixup_mos6502_got10", 0, 10, 0 },
{ "fixup_mos6502_wplt30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_mos6502_tls_gd_hi22", 0, 22, 0 },
{ "fixup_mos6502_tls_gd_lo10", 0, 10, 0 },
{ "fixup_mos6502_tls_gd_add", 0, 0, 0 },
{ "fixup_mos6502_tls_gd_call", 0, 0, 0 },
{ "fixup_mos6502_tls_ldm_hi22", 0, 22, 0 },
{ "fixup_mos6502_tls_ldm_lo10", 0, 10, 0 },
{ "fixup_mos6502_tls_ldm_add", 0, 0, 0 },
{ "fixup_mos6502_tls_ldm_call", 0, 0, 0 },
{ "fixup_mos6502_tls_ldo_hix22", 0, 22, 0 },
{ "fixup_mos6502_tls_ldo_lox10", 0, 10, 0 },
{ "fixup_mos6502_tls_ldo_add", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_hi22", 0, 22, 0 },
{ "fixup_mos6502_tls_ie_lo10", 0, 10, 0 },
{ "fixup_mos6502_tls_ie_ld", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_ldx", 0, 0, 0 },
{ "fixup_mos6502_tls_ie_add", 0, 0, 0 },
{ "fixup_mos6502_tls_le_hix22", 0, 0, 0 },
{ "fixup_mos6502_tls_le_lox10", 0, 0, 0 }
};
if (Kind < FirstTargetFixupKind)
return MCAsmBackend::getFixupKindInfo(Kind);
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
"Invalid kind!");
if (IsLittleEndian)
return InfosLE[Kind - FirstTargetFixupKind];
return InfosBE[Kind - FirstTargetFixupKind];
}
void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
const MCValue &Target, uint64_t &Value,
bool &IsResolved) override {
switch ((Mos6502::Fixups)Fixup.getKind()) {
default: break;
case Mos6502::fixup_mos6502_wplt30:
if (Target.getSymA()->getSymbol().isTemporary())
return;
case Mos6502::fixup_mos6502_tls_gd_hi22:
case Mos6502::fixup_mos6502_tls_gd_lo10:
case Mos6502::fixup_mos6502_tls_gd_add:
case Mos6502::fixup_mos6502_tls_gd_call:
case Mos6502::fixup_mos6502_tls_ldm_hi22:
case Mos6502::fixup_mos6502_tls_ldm_lo10:
case Mos6502::fixup_mos6502_tls_ldm_add:
case Mos6502::fixup_mos6502_tls_ldm_call:
case Mos6502::fixup_mos6502_tls_ldo_hix22:
case Mos6502::fixup_mos6502_tls_ldo_lox10:
case Mos6502::fixup_mos6502_tls_ldo_add:
case Mos6502::fixup_mos6502_tls_ie_hi22:
case Mos6502::fixup_mos6502_tls_ie_lo10:
case Mos6502::fixup_mos6502_tls_ie_ld:
case Mos6502::fixup_mos6502_tls_ie_ldx:
case Mos6502::fixup_mos6502_tls_ie_add:
case Mos6502::fixup_mos6502_tls_le_hix22:
case Mos6502::fixup_mos6502_tls_le_lox10: IsResolved = false; break;
}
}
bool mayNeedRelaxation(const MCInst &Inst) const override {
// FIXME.
return false;
}
/// fixupNeedsRelaxation - Target specific predicate for whether a given
/// fixup requires the associated instruction to be relaxed.
bool fixupNeedsRelaxation(const MCFixup &Fixup,
uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override {
// FIXME.
llvm_unreachable("fixupNeedsRelaxation() unimplemented");
return false;
}
void relaxInstruction(const MCInst &Inst, MCInst &Res) const override {
// FIXME.
llvm_unreachable("relaxInstruction() unimplemented");
}
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override {
// Cannot emit NOP with size not multiple of 32 bits.
if (Count % 4 != 0)
return false;
uint64_t NumNops = Count / 4;
for (uint64_t i = 0; i != NumNops; ++i)
OW->write32(0x01000000);
return true;
}
};
class ELFMos6502AsmBackend : public Mos6502AsmBackend {
Triple::OSType OSType;
public:
ELFMos6502AsmBackend(const Target &T, Triple::OSType OSType) :
Mos6502AsmBackend(T), OSType(OSType) { }
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value, bool IsPCRel) const override {
Value = adjustFixupValue(Fixup.getKind(), Value);
if (!Value) return; // Doesn't change encoding.
unsigned Offset = Fixup.getOffset();
// For each byte of the fragment that the fixup touches, mask in the bits
// from the fixup value. The Value has been "split up" into the
// appropriate bitfields above.
for (unsigned i = 0; i != 4; ++i) {
unsigned Idx = IsLittleEndian ? i : 3 - i;
Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
}
}
MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
return createMos6502ELFObjectWriter(OS, Is64Bit, IsLittleEndian, OSABI);
}
};
} // end anonymous namespace
MCAsmBackend *llvm::createMos6502AsmBackend(const Target &T,
const MCRegisterInfo &MRI,
const Triple &TT, StringRef CPU) {
return new ELFMos6502AsmBackend(T, TT.getOS());
}

View File

@ -0,0 +1,139 @@
//===-- Mos6502ELFObjectWriter.cpp - Mos6502 ELF Writer -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/Mos6502FixupKinds.h"
#include "MCTargetDesc/Mos6502MCExpr.h"
#include "MCTargetDesc/Mos6502MCTargetDesc.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
namespace {
class Mos6502ELFObjectWriter : public MCELFObjectTargetWriter {
public:
Mos6502ELFObjectWriter(bool Is64Bit, uint8_t OSABI)
: MCELFObjectTargetWriter(Is64Bit, OSABI,
Is64Bit ? ELF::EM_SPARCV9 : ELF::EM_SPARC,
/*HasRelocationAddend*/ true) {}
~Mos6502ELFObjectWriter() override {}
protected:
unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel) const override;
bool needsRelocateWithSymbol(const MCSymbol &Sym,
unsigned Type) const override;
};
}
unsigned Mos6502ELFObjectWriter::GetRelocType(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
if (const Mos6502MCExpr *SExpr = dyn_cast<Mos6502MCExpr>(Fixup.getValue())) {
if (SExpr->getKind() == Mos6502MCExpr::VK_Mos6502_R_DISP32)
return ELF::R_SPARC_DISP32;
}
if (IsPCRel) {
switch((unsigned)Fixup.getKind()) {
default:
llvm_unreachable("Unimplemented fixup -> relocation");
case FK_Data_1: return ELF::R_SPARC_DISP8;
case FK_Data_2: return ELF::R_SPARC_DISP16;
case FK_Data_4: return ELF::R_SPARC_DISP32;
case FK_Data_8: return ELF::R_SPARC_DISP64;
case Mos6502::fixup_mos6502_call30: return ELF::R_SPARC_WDISP30;
case Mos6502::fixup_mos6502_br22: return ELF::R_SPARC_WDISP22;
case Mos6502::fixup_mos6502_br19: return ELF::R_SPARC_WDISP19;
case Mos6502::fixup_mos6502_pc22: return ELF::R_SPARC_PC22;
case Mos6502::fixup_mos6502_pc10: return ELF::R_SPARC_PC10;
case Mos6502::fixup_mos6502_wplt30: return ELF::R_SPARC_WPLT30;
}
}
switch((unsigned)Fixup.getKind()) {
default:
llvm_unreachable("Unimplemented fixup -> relocation");
case FK_Data_1: return ELF::R_SPARC_8;
case FK_Data_2: return ((Fixup.getOffset() % 2)
? ELF::R_SPARC_UA16
: ELF::R_SPARC_16);
case FK_Data_4: return ((Fixup.getOffset() % 4)
? ELF::R_SPARC_UA32
: ELF::R_SPARC_32);
case FK_Data_8: return ((Fixup.getOffset() % 8)
? ELF::R_SPARC_UA64
: ELF::R_SPARC_64);
case Mos6502::fixup_mos6502_hi22: return ELF::R_SPARC_HI22;
case Mos6502::fixup_mos6502_lo10: return ELF::R_SPARC_LO10;
case Mos6502::fixup_mos6502_h44: return ELF::R_SPARC_H44;
case Mos6502::fixup_mos6502_m44: return ELF::R_SPARC_M44;
case Mos6502::fixup_mos6502_l44: return ELF::R_SPARC_L44;
case Mos6502::fixup_mos6502_hh: return ELF::R_SPARC_HH22;
case Mos6502::fixup_mos6502_hm: return ELF::R_SPARC_HM10;
case Mos6502::fixup_mos6502_got22: return ELF::R_SPARC_GOT22;
case Mos6502::fixup_mos6502_got10: return ELF::R_SPARC_GOT10;
case Mos6502::fixup_mos6502_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22;
case Mos6502::fixup_mos6502_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10;
case Mos6502::fixup_mos6502_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD;
case Mos6502::fixup_mos6502_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL;
case Mos6502::fixup_mos6502_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22;
case Mos6502::fixup_mos6502_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10;
case Mos6502::fixup_mos6502_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD;
case Mos6502::fixup_mos6502_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL;
case Mos6502::fixup_mos6502_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22;
case Mos6502::fixup_mos6502_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10;
case Mos6502::fixup_mos6502_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD;
case Mos6502::fixup_mos6502_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22;
case Mos6502::fixup_mos6502_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10;
case Mos6502::fixup_mos6502_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD;
case Mos6502::fixup_mos6502_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX;
case Mos6502::fixup_mos6502_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD;
case Mos6502::fixup_mos6502_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22;
case Mos6502::fixup_mos6502_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10;
}
return ELF::R_SPARC_NONE;
}
bool Mos6502ELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
unsigned Type) const {
switch (Type) {
default:
return false;
// All relocations that use a GOT need a symbol, not an offset, as
// the offset of the symbol within the section is irrelevant to
// where the GOT entry is. Don't need to list all the TLS entries,
// as they're all marked as requiring a symbol anyways.
case ELF::R_SPARC_GOT10:
case ELF::R_SPARC_GOT13:
case ELF::R_SPARC_GOT22:
case ELF::R_SPARC_GOTDATA_HIX22:
case ELF::R_SPARC_GOTDATA_LOX10:
case ELF::R_SPARC_GOTDATA_OP_HIX22:
case ELF::R_SPARC_GOTDATA_OP_LOX10:
return true;
}
}
MCObjectWriter *llvm::createMos6502ELFObjectWriter(raw_pwrite_stream &OS,
bool Is64Bit,
bool IsLittleEndian,
uint8_t OSABI) {
MCELFObjectTargetWriter *MOTW = new Mos6502ELFObjectWriter(Is64Bit, OSABI);
return createELFObjectWriter(MOTW, OS, IsLittleEndian);
}

View File

@ -0,0 +1,97 @@
//===-- Mos6502FixupKinds.h - Mos6502 Specific Fixup Entries --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502FIXUPKINDS_H
#define LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502FIXUPKINDS_H
#include "llvm/MC/MCFixup.h"
namespace llvm {
namespace Mos6502 {
enum Fixups {
// fixup_mos6502_call30 - 30-bit PC relative relocation for call
fixup_mos6502_call30 = FirstTargetFixupKind,
/// fixup_mos6502_br22 - 22-bit PC relative relocation for
/// branches
fixup_mos6502_br22,
/// fixup_mos6502_br19 - 19-bit PC relative relocation for
/// branches on icc/xcc
fixup_mos6502_br19,
/// fixup_mos6502_bpr - 16-bit fixup for bpr
fixup_mos6502_br16_2,
fixup_mos6502_br16_14,
/// fixup_mos6502_hi22 - 22-bit fixup corresponding to %hi(foo)
/// for sethi
fixup_mos6502_hi22,
/// fixup_mos6502_lo10 - 10-bit fixup corresponding to %lo(foo)
fixup_mos6502_lo10,
/// fixup_mos6502_h44 - 22-bit fixup corresponding to %h44(foo)
fixup_mos6502_h44,
/// fixup_mos6502_m44 - 10-bit fixup corresponding to %m44(foo)
fixup_mos6502_m44,
/// fixup_mos6502_l44 - 12-bit fixup corresponding to %l44(foo)
fixup_mos6502_l44,
/// fixup_mos6502_hh - 22-bit fixup corresponding to %hh(foo)
fixup_mos6502_hh,
/// fixup_mos6502_hm - 10-bit fixup corresponding to %hm(foo)
fixup_mos6502_hm,
/// fixup_mos6502_pc22 - 22-bit fixup corresponding to %pc22(foo)
fixup_mos6502_pc22,
/// fixup_mos6502_pc10 - 10-bit fixup corresponding to %pc10(foo)
fixup_mos6502_pc10,
/// fixup_mos6502_got22 - 22-bit fixup corresponding to %got22(foo)
fixup_mos6502_got22,
/// fixup_mos6502_got10 - 10-bit fixup corresponding to %got10(foo)
fixup_mos6502_got10,
/// fixup_mos6502_wplt30
fixup_mos6502_wplt30,
/// fixups for Thread Local Storage
fixup_mos6502_tls_gd_hi22,
fixup_mos6502_tls_gd_lo10,
fixup_mos6502_tls_gd_add,
fixup_mos6502_tls_gd_call,
fixup_mos6502_tls_ldm_hi22,
fixup_mos6502_tls_ldm_lo10,
fixup_mos6502_tls_ldm_add,
fixup_mos6502_tls_ldm_call,
fixup_mos6502_tls_ldo_hix22,
fixup_mos6502_tls_ldo_lox10,
fixup_mos6502_tls_ldo_add,
fixup_mos6502_tls_ie_hi22,
fixup_mos6502_tls_ie_lo10,
fixup_mos6502_tls_ie_ld,
fixup_mos6502_tls_ie_ldx,
fixup_mos6502_tls_ie_add,
fixup_mos6502_tls_le_hix22,
fixup_mos6502_tls_le_lox10,
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
};
}
}
#endif

View File

@ -0,0 +1,70 @@
//===-- Mos6502MCAsmInfo.cpp - Mos6502 asm properties -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declarations of the Mos6502MCAsmInfo properties.
//
//===----------------------------------------------------------------------===//
#include "Mos6502MCAsmInfo.h"
#include "Mos6502MCExpr.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCStreamer.h"
using namespace llvm;
void Mos6502ELFMCAsmInfo::anchor() {}
Mos6502ELFMCAsmInfo::Mos6502ELFMCAsmInfo(const Triple &TheTriple) {
bool isV9 = (TheTriple.getArch() == Triple::mos6502v9);
IsLittleEndian = (TheTriple.getArch() == Triple::mos6502el);
if (isV9) {
PointerSize = CalleeSaveStackSlotSize = 8;
}
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
// .xword is only supported by V9.
Data64bitsDirective = (isV9) ? "\t.xword\t" : nullptr;
ZeroDirective = "\t.skip\t";
CommentString = "!";
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::DwarfCFI;
SunStyleELFSectionSwitchSyntax = true;
UsesELFSectionDirectiveForBSS = true;
UseIntegratedAssembler = true;
}
const MCExpr*
Mos6502ELFMCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym,
unsigned Encoding,
MCStreamer &Streamer) const {
if (Encoding & dwarf::DW_EH_PE_pcrel) {
MCContext &Ctx = Streamer.getContext();
return Mos6502MCExpr::create(Mos6502MCExpr::VK_Mos6502_R_DISP32,
MCSymbolRefExpr::create(Sym, Ctx), Ctx);
}
return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer);
}
const MCExpr*
Mos6502ELFMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
unsigned Encoding,
MCStreamer &Streamer) const {
if (Encoding & dwarf::DW_EH_PE_pcrel) {
MCContext &Ctx = Streamer.getContext();
return Mos6502MCExpr::create(Mos6502MCExpr::VK_Mos6502_R_DISP32,
MCSymbolRefExpr::create(Sym, Ctx), Ctx);
}
return MCAsmInfo::getExprForFDESymbol(Sym, Encoding, Streamer);
}

View File

@ -0,0 +1,37 @@
//===-- Mos6502MCAsmInfo.h - Mos6502 asm properties ----------------*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the declaration of the Mos6502MCAsmInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCASMINFO_H
#define LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCASMINFO_H
#include "llvm/MC/MCAsmInfoELF.h"
namespace llvm {
class Triple;
class Mos6502ELFMCAsmInfo : public MCAsmInfoELF {
void anchor() override;
public:
explicit Mos6502ELFMCAsmInfo(const Triple &TheTriple);
const MCExpr*
getExprForPersonalitySymbol(const MCSymbol *Sym, unsigned Encoding,
MCStreamer &Streamer) const override;
const MCExpr* getExprForFDESymbol(const MCSymbol *Sym,
unsigned Encoding,
MCStreamer &Streamer) const override;
};
} // namespace llvm
#endif

View File

@ -0,0 +1,219 @@
//===-- Mos6502MCCodeEmitter.cpp - Convert Mos6502 code to machine code -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Mos6502MCCodeEmitter class.
//
//===----------------------------------------------------------------------===//
#include "Mos6502MCExpr.h"
#include "MCTargetDesc/Mos6502FixupKinds.h"
#include "Mos6502MCTargetDesc.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "mccodeemitter"
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
namespace {
class Mos6502MCCodeEmitter : public MCCodeEmitter {
Mos6502MCCodeEmitter(const Mos6502MCCodeEmitter &) = delete;
void operator=(const Mos6502MCCodeEmitter &) = delete;
MCContext &Ctx;
public:
Mos6502MCCodeEmitter(MCContext &ctx): Ctx(ctx) {}
~Mos6502MCCodeEmitter() override {}
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const override;
// getBinaryCodeForInstr - TableGen'erated function for getting the
// binary encoding for an instruction.
uint64_t getBinaryCodeForInstr(const MCInst &MI,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
/// getMachineOpValue - Return binary encoding of operand. If the machine
/// operand requires relocation, record the relocation and return zero.
unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
unsigned getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
};
} // end anonymous namespace
MCCodeEmitter *llvm::createMos6502MCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx) {
return new Mos6502MCCodeEmitter(Ctx);
}
void Mos6502MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI);
if (Ctx.getAsmInfo()->isLittleEndian()) {
// Output the bits in little-endian byte order.
support::endian::Writer<support::little>(OS).write<uint32_t>(Bits);
} else {
// Output the bits in big-endian byte order.
support::endian::Writer<support::big>(OS).write<uint32_t>(Bits);
}
unsigned tlsOpNo = 0;
switch (MI.getOpcode()) {
default: break;
case SP::TLS_CALL: tlsOpNo = 1; break;
case SP::TLS_ADDrr:
case SP::TLS_ADDXrr:
case SP::TLS_LDrr:
case SP::TLS_LDXrr: tlsOpNo = 3; break;
}
if (tlsOpNo != 0) {
const MCOperand &MO = MI.getOperand(tlsOpNo);
uint64_t op = getMachineOpValue(MI, MO, Fixups, STI);
assert(op == 0 && "Unexpected operand value!");
(void)op; // suppress warning.
}
++MCNumEmitted; // Keep track of the # of mi's emitted.
}
unsigned Mos6502MCCodeEmitter::
getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
if (MO.isReg())
return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
if (MO.isImm())
return MO.getImm();
assert(MO.isExpr());
const MCExpr *Expr = MO.getExpr();
if (const Mos6502MCExpr *SExpr = dyn_cast<Mos6502MCExpr>(Expr)) {
MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind();
Fixups.push_back(MCFixup::create(0, Expr, Kind));
return 0;
}
int64_t Res;
if (Expr->evaluateAsAbsolute(Res))
return Res;
llvm_unreachable("Unhandled expression!");
return 0;
}
unsigned Mos6502MCCodeEmitter::
getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
if (MI.getOpcode() == SP::TLS_CALL) {
// No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in
// encodeInstruction.
#ifndef NDEBUG
// Verify that the callee is actually __tls_get_addr.
const Mos6502MCExpr *SExpr = dyn_cast<Mos6502MCExpr>(MO.getExpr());
assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef &&
"Unexpected expression in TLS_CALL");
const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr());
assert(SymExpr->getSymbol().getName() == "__tls_get_addr" &&
"Unexpected function for TLS_CALL");
#endif
return 0;
}
MCFixupKind fixupKind = (MCFixupKind)Mos6502::fixup_mos6502_call30;
if (const Mos6502MCExpr *SExpr = dyn_cast<Mos6502MCExpr>(MO.getExpr())) {
if (SExpr->getKind() == Mos6502MCExpr::VK_Mos6502_WPLT30)
fixupKind = (MCFixupKind)Mos6502::fixup_mos6502_wplt30;
}
Fixups.push_back(MCFixup::create(0, MO.getExpr(), fixupKind));
return 0;
}
unsigned Mos6502MCCodeEmitter::
getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Mos6502::fixup_mos6502_br22));
return 0;
}
unsigned Mos6502MCCodeEmitter::
getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Mos6502::fixup_mos6502_br19));
return 0;
}
unsigned Mos6502MCCodeEmitter::
getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(OpNo);
if (MO.isReg() || MO.isImm())
return getMachineOpValue(MI, MO, Fixups, STI);
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Mos6502::fixup_mos6502_br16_2));
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
(MCFixupKind)Mos6502::fixup_mos6502_br16_14));
return 0;
}
#include "Mos6502GenMCCodeEmitter.inc"

View File

@ -0,0 +1,221 @@
//===-- Mos6502MCExpr.cpp - Mos6502 specific MC expression classes --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the implementation of the assembly expression modifiers
// accepted by the Mos6502 architecture (e.g. "%hi", "%lo", ...).
//
//===----------------------------------------------------------------------===//
#include "Mos6502MCExpr.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCObjectStreamer.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/Object/ELF.h"
using namespace llvm;
#define DEBUG_TYPE "mos6502mcexpr"
const Mos6502MCExpr*
Mos6502MCExpr::create(VariantKind Kind, const MCExpr *Expr,
MCContext &Ctx) {
return new (Ctx) Mos6502MCExpr(Kind, Expr);
}
void Mos6502MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
bool closeParen = printVariantKind(OS, Kind);
const MCExpr *Expr = getSubExpr();
Expr->print(OS, MAI);
if (closeParen)
OS << ')';
}
bool Mos6502MCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind)
{
bool closeParen = true;
switch (Kind) {
case VK_Mos6502_None: closeParen = false; break;
case VK_Mos6502_LO: OS << "%lo("; break;
case VK_Mos6502_HI: OS << "%hi("; break;
case VK_Mos6502_H44: OS << "%h44("; break;
case VK_Mos6502_M44: OS << "%m44("; break;
case VK_Mos6502_L44: OS << "%l44("; break;
case VK_Mos6502_HH: OS << "%hh("; break;
case VK_Mos6502_HM: OS << "%hm("; break;
// FIXME: use %pc22/%pc10, if system assembler supports them.
case VK_Mos6502_PC22: OS << "%hi("; break;
case VK_Mos6502_PC10: OS << "%lo("; break;
// FIXME: use %got22/%got10, if system assembler supports them.
case VK_Mos6502_GOT22: OS << "%hi("; break;
case VK_Mos6502_GOT10: OS << "%lo("; break;
case VK_Mos6502_WPLT30: closeParen = false; break;
case VK_Mos6502_R_DISP32: OS << "%r_disp32("; break;
case VK_Mos6502_TLS_GD_HI22: OS << "%tgd_hi22("; break;
case VK_Mos6502_TLS_GD_LO10: OS << "%tgd_lo10("; break;
case VK_Mos6502_TLS_GD_ADD: OS << "%tgd_add("; break;
case VK_Mos6502_TLS_GD_CALL: OS << "%tgd_call("; break;
case VK_Mos6502_TLS_LDM_HI22: OS << "%tldm_hi22("; break;
case VK_Mos6502_TLS_LDM_LO10: OS << "%tldm_lo10("; break;
case VK_Mos6502_TLS_LDM_ADD: OS << "%tldm_add("; break;
case VK_Mos6502_TLS_LDM_CALL: OS << "%tldm_call("; break;
case VK_Mos6502_TLS_LDO_HIX22: OS << "%tldo_hix22("; break;
case VK_Mos6502_TLS_LDO_LOX10: OS << "%tldo_lox10("; break;
case VK_Mos6502_TLS_LDO_ADD: OS << "%tldo_add("; break;
case VK_Mos6502_TLS_IE_HI22: OS << "%tie_hi22("; break;
case VK_Mos6502_TLS_IE_LO10: OS << "%tie_lo10("; break;
case VK_Mos6502_TLS_IE_LD: OS << "%tie_ld("; break;
case VK_Mos6502_TLS_IE_LDX: OS << "%tie_ldx("; break;
case VK_Mos6502_TLS_IE_ADD: OS << "%tie_add("; break;
case VK_Mos6502_TLS_LE_HIX22: OS << "%tle_hix22("; break;
case VK_Mos6502_TLS_LE_LOX10: OS << "%tle_lox10("; break;
}
return closeParen;
}
Mos6502MCExpr::VariantKind Mos6502MCExpr::parseVariantKind(StringRef name)
{
return StringSwitch<Mos6502MCExpr::VariantKind>(name)
.Case("lo", VK_Mos6502_LO)
.Case("hi", VK_Mos6502_HI)
.Case("h44", VK_Mos6502_H44)
.Case("m44", VK_Mos6502_M44)
.Case("l44", VK_Mos6502_L44)
.Case("hh", VK_Mos6502_HH)
.Case("hm", VK_Mos6502_HM)
.Case("pc22", VK_Mos6502_PC22)
.Case("pc10", VK_Mos6502_PC10)
.Case("got22", VK_Mos6502_GOT22)
.Case("got10", VK_Mos6502_GOT10)
.Case("r_disp32", VK_Mos6502_R_DISP32)
.Case("tgd_hi22", VK_Mos6502_TLS_GD_HI22)
.Case("tgd_lo10", VK_Mos6502_TLS_GD_LO10)
.Case("tgd_add", VK_Mos6502_TLS_GD_ADD)
.Case("tgd_call", VK_Mos6502_TLS_GD_CALL)
.Case("tldm_hi22", VK_Mos6502_TLS_LDM_HI22)
.Case("tldm_lo10", VK_Mos6502_TLS_LDM_LO10)
.Case("tldm_add", VK_Mos6502_TLS_LDM_ADD)
.Case("tldm_call", VK_Mos6502_TLS_LDM_CALL)
.Case("tldo_hix22", VK_Mos6502_TLS_LDO_HIX22)
.Case("tldo_lox10", VK_Mos6502_TLS_LDO_LOX10)
.Case("tldo_add", VK_Mos6502_TLS_LDO_ADD)
.Case("tie_hi22", VK_Mos6502_TLS_IE_HI22)
.Case("tie_lo10", VK_Mos6502_TLS_IE_LO10)
.Case("tie_ld", VK_Mos6502_TLS_IE_LD)
.Case("tie_ldx", VK_Mos6502_TLS_IE_LDX)
.Case("tie_add", VK_Mos6502_TLS_IE_ADD)
.Case("tle_hix22", VK_Mos6502_TLS_LE_HIX22)
.Case("tle_lox10", VK_Mos6502_TLS_LE_LOX10)
.Default(VK_Mos6502_None);
}
Mos6502::Fixups Mos6502MCExpr::getFixupKind(Mos6502MCExpr::VariantKind Kind) {
switch (Kind) {
default: llvm_unreachable("Unhandled Mos6502MCExpr::VariantKind");
case VK_Mos6502_LO: return Mos6502::fixup_mos6502_lo10;
case VK_Mos6502_HI: return Mos6502::fixup_mos6502_hi22;
case VK_Mos6502_H44: return Mos6502::fixup_mos6502_h44;
case VK_Mos6502_M44: return Mos6502::fixup_mos6502_m44;
case VK_Mos6502_L44: return Mos6502::fixup_mos6502_l44;
case VK_Mos6502_HH: return Mos6502::fixup_mos6502_hh;
case VK_Mos6502_HM: return Mos6502::fixup_mos6502_hm;
case VK_Mos6502_PC22: return Mos6502::fixup_mos6502_pc22;
case VK_Mos6502_PC10: return Mos6502::fixup_mos6502_pc10;
case VK_Mos6502_GOT22: return Mos6502::fixup_mos6502_got22;
case VK_Mos6502_GOT10: return Mos6502::fixup_mos6502_got10;
case VK_Mos6502_WPLT30: return Mos6502::fixup_mos6502_wplt30;
case VK_Mos6502_TLS_GD_HI22: return Mos6502::fixup_mos6502_tls_gd_hi22;
case VK_Mos6502_TLS_GD_LO10: return Mos6502::fixup_mos6502_tls_gd_lo10;
case VK_Mos6502_TLS_GD_ADD: return Mos6502::fixup_mos6502_tls_gd_add;
case VK_Mos6502_TLS_GD_CALL: return Mos6502::fixup_mos6502_tls_gd_call;
case VK_Mos6502_TLS_LDM_HI22: return Mos6502::fixup_mos6502_tls_ldm_hi22;
case VK_Mos6502_TLS_LDM_LO10: return Mos6502::fixup_mos6502_tls_ldm_lo10;
case VK_Mos6502_TLS_LDM_ADD: return Mos6502::fixup_mos6502_tls_ldm_add;
case VK_Mos6502_TLS_LDM_CALL: return Mos6502::fixup_mos6502_tls_ldm_call;
case VK_Mos6502_TLS_LDO_HIX22: return Mos6502::fixup_mos6502_tls_ldo_hix22;
case VK_Mos6502_TLS_LDO_LOX10: return Mos6502::fixup_mos6502_tls_ldo_lox10;
case VK_Mos6502_TLS_LDO_ADD: return Mos6502::fixup_mos6502_tls_ldo_add;
case VK_Mos6502_TLS_IE_HI22: return Mos6502::fixup_mos6502_tls_ie_hi22;
case VK_Mos6502_TLS_IE_LO10: return Mos6502::fixup_mos6502_tls_ie_lo10;
case VK_Mos6502_TLS_IE_LD: return Mos6502::fixup_mos6502_tls_ie_ld;
case VK_Mos6502_TLS_IE_LDX: return Mos6502::fixup_mos6502_tls_ie_ldx;
case VK_Mos6502_TLS_IE_ADD: return Mos6502::fixup_mos6502_tls_ie_add;
case VK_Mos6502_TLS_LE_HIX22: return Mos6502::fixup_mos6502_tls_le_hix22;
case VK_Mos6502_TLS_LE_LOX10: return Mos6502::fixup_mos6502_tls_le_lox10;
}
}
bool
Mos6502MCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const {
return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
}
static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
switch (Expr->getKind()) {
case MCExpr::Target:
llvm_unreachable("Can't handle nested target expr!");
break;
case MCExpr::Constant:
break;
case MCExpr::Binary: {
const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
break;
}
case MCExpr::SymbolRef: {
const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
break;
}
case MCExpr::Unary:
fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
break;
}
}
void Mos6502MCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
switch(getKind()) {
default: return;
case VK_Mos6502_TLS_GD_HI22:
case VK_Mos6502_TLS_GD_LO10:
case VK_Mos6502_TLS_GD_ADD:
case VK_Mos6502_TLS_GD_CALL:
case VK_Mos6502_TLS_LDM_HI22:
case VK_Mos6502_TLS_LDM_LO10:
case VK_Mos6502_TLS_LDM_ADD:
case VK_Mos6502_TLS_LDM_CALL:
case VK_Mos6502_TLS_LDO_HIX22:
case VK_Mos6502_TLS_LDO_LOX10:
case VK_Mos6502_TLS_LDO_ADD:
case VK_Mos6502_TLS_IE_HI22:
case VK_Mos6502_TLS_IE_LO10:
case VK_Mos6502_TLS_IE_LD:
case VK_Mos6502_TLS_IE_LDX:
case VK_Mos6502_TLS_IE_ADD:
case VK_Mos6502_TLS_LE_HIX22:
case VK_Mos6502_TLS_LE_LOX10: break;
}
fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
}
void Mos6502MCExpr::visitUsedExpr(MCStreamer &Streamer) const {
Streamer.visitUsedExpr(*getSubExpr());
}

View File

@ -0,0 +1,112 @@
//====- Mos6502MCExpr.h - Mos6502 specific MC expression classes --*- C++ -*-=====//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes Mos6502-specific MCExprs, used for modifiers like
// "%hi" or "%lo" etc.,
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCEXPR_H
#define LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCEXPR_H
#include "Mos6502FixupKinds.h"
#include "llvm/MC/MCExpr.h"
namespace llvm {
class StringRef;
class Mos6502MCExpr : public MCTargetExpr {
public:
enum VariantKind {
VK_Mos6502_None,
VK_Mos6502_LO,
VK_Mos6502_HI,
VK_Mos6502_H44,
VK_Mos6502_M44,
VK_Mos6502_L44,
VK_Mos6502_HH,
VK_Mos6502_HM,
VK_Mos6502_PC22,
VK_Mos6502_PC10,
VK_Mos6502_GOT22,
VK_Mos6502_GOT10,
VK_Mos6502_WPLT30,
VK_Mos6502_R_DISP32,
VK_Mos6502_TLS_GD_HI22,
VK_Mos6502_TLS_GD_LO10,
VK_Mos6502_TLS_GD_ADD,
VK_Mos6502_TLS_GD_CALL,
VK_Mos6502_TLS_LDM_HI22,
VK_Mos6502_TLS_LDM_LO10,
VK_Mos6502_TLS_LDM_ADD,
VK_Mos6502_TLS_LDM_CALL,
VK_Mos6502_TLS_LDO_HIX22,
VK_Mos6502_TLS_LDO_LOX10,
VK_Mos6502_TLS_LDO_ADD,
VK_Mos6502_TLS_IE_HI22,
VK_Mos6502_TLS_IE_LO10,
VK_Mos6502_TLS_IE_LD,
VK_Mos6502_TLS_IE_LDX,
VK_Mos6502_TLS_IE_ADD,
VK_Mos6502_TLS_LE_HIX22,
VK_Mos6502_TLS_LE_LOX10
};
private:
const VariantKind Kind;
const MCExpr *Expr;
explicit Mos6502MCExpr(VariantKind Kind, const MCExpr *Expr)
: Kind(Kind), Expr(Expr) {}
public:
/// @name Construction
/// @{
static const Mos6502MCExpr *create(VariantKind Kind, const MCExpr *Expr,
MCContext &Ctx);
/// @}
/// @name Accessors
/// @{
/// getOpcode - Get the kind of this expression.
VariantKind getKind() const { return Kind; }
/// getSubExpr - Get the child of this expression.
const MCExpr *getSubExpr() const { return Expr; }
/// getFixupKind - Get the fixup kind of this expression.
Mos6502::Fixups getFixupKind() const { return getFixupKind(Kind); }
/// @}
void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
bool evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;
MCSection *findAssociatedSection() const override {
return getSubExpr()->findAssociatedSection();
}
void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override;
static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Target;
}
static bool classof(const Mos6502MCExpr *) { return true; }
static VariantKind parseVariantKind(StringRef name);
static bool printVariantKind(raw_ostream &OS, VariantKind Kind);
static Mos6502::Fixups getFixupKind(VariantKind Kind);
};
} // end namespace llvm.
#endif

View File

@ -0,0 +1,184 @@
//===-- Mos6502MCTargetDesc.cpp - Mos6502 Target Descriptions -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Mos6502 specific target descriptions.
//
//===----------------------------------------------------------------------===//
#include "Mos6502MCTargetDesc.h"
#include "InstPrinter/Mos6502InstPrinter.h"
#include "Mos6502MCAsmInfo.h"
#include "Mos6502TargetStreamer.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
#define GET_INSTRINFO_MC_DESC
#include "Mos6502GenInstrInfo.inc"
#define GET_SUBTARGETINFO_MC_DESC
#include "Mos6502GenSubtargetInfo.inc"
#define GET_REGINFO_MC_DESC
#include "Mos6502GenRegisterInfo.inc"
static MCAsmInfo *createMos6502MCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT) {
MCAsmInfo *MAI = new Mos6502ELFMCAsmInfo(TT);
unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, Reg, 0);
MAI->addInitialFrameState(Inst);
return MAI;
}
static MCAsmInfo *createMos6502V9MCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT) {
MCAsmInfo *MAI = new Mos6502ELFMCAsmInfo(TT);
unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, Reg, 2047);
MAI->addInitialFrameState(Inst);
return MAI;
}
static MCInstrInfo *createMos6502MCInstrInfo() {
MCInstrInfo *X = new MCInstrInfo();
InitMos6502MCInstrInfo(X);
return X;
}
static MCRegisterInfo *createMos6502MCRegisterInfo(const Triple &TT) {
MCRegisterInfo *X = new MCRegisterInfo();
InitMos6502MCRegisterInfo(X, SP::O7);
return X;
}
static MCSubtargetInfo *
createMos6502MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
if (CPU.empty())
CPU = (TT.getArch() == Triple::mos6502v9) ? "v9" : "v8";
return createMos6502MCSubtargetInfoImpl(TT, CPU, FS);
}
// Code models. Some only make sense for 64-bit code.
//
// SunCC Reloc CodeModel Constraints
// abs32 Static Small text+data+bss linked below 2^32 bytes
// abs44 Static Medium text+data+bss linked below 2^44 bytes
// abs64 Static Large text smaller than 2^31 bytes
// pic13 PIC_ Small GOT < 2^13 bytes
// pic32 PIC_ Medium GOT < 2^32 bytes
//
// All code models require that the text segment is smaller than 2GB.
static MCCodeGenInfo *createMos6502MCCodeGenInfo(const Triple &TT,
Reloc::Model RM,
CodeModel::Model CM,
CodeGenOpt::Level OL) {
MCCodeGenInfo *X = new MCCodeGenInfo();
// The default 32-bit code model is abs32/pic32 and the default 32-bit
// code model for JIT is abs32.
switch (CM) {
default: break;
case CodeModel::Default:
case CodeModel::JITDefault: CM = CodeModel::Small; break;
}
X->initMCCodeGenInfo(RM, CM, OL);
return X;
}
static MCCodeGenInfo *createMos6502V9MCCodeGenInfo(const Triple &TT,
Reloc::Model RM,
CodeModel::Model CM,
CodeGenOpt::Level OL) {
MCCodeGenInfo *X = new MCCodeGenInfo();
// The default 64-bit code model is abs44/pic32 and the default 64-bit
// code model for JIT is abs64.
switch (CM) {
default: break;
case CodeModel::Default:
CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
break;
case CodeModel::JITDefault:
CM = CodeModel::Large;
break;
}
X->initMCCodeGenInfo(RM, CM, OL);
return X;
}
static MCTargetStreamer *
createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
return new Mos6502TargetELFStreamer(S);
}
static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint,
bool isVerboseAsm) {
return new Mos6502TargetAsmStreamer(S, OS);
}
static MCInstPrinter *createMos6502MCInstPrinter(const Triple &T,
unsigned SyntaxVariant,
const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI) {
return new Mos6502InstPrinter(MAI, MII, MRI);
}
extern "C" void LLVMInitializeMos6502TargetMC() {
// Register the MC asm info.
RegisterMCAsmInfoFn X(TheMos6502Target, createMos6502MCAsmInfo);
RegisterMCAsmInfoFn Y(TheMos6502V9Target, createMos6502V9MCAsmInfo);
RegisterMCAsmInfoFn Z(TheMos6502elTarget, createMos6502MCAsmInfo);
for (Target *T : {&TheMos6502Target, &TheMos6502V9Target, &TheMos6502elTarget}) {
// Register the MC instruction info.
TargetRegistry::RegisterMCInstrInfo(*T, createMos6502MCInstrInfo);
// Register the MC register info.
TargetRegistry::RegisterMCRegInfo(*T, createMos6502MCRegisterInfo);
// Register the MC subtarget info.
TargetRegistry::RegisterMCSubtargetInfo(*T, createMos6502MCSubtargetInfo);
// Register the MC Code Emitter.
TargetRegistry::RegisterMCCodeEmitter(*T, createMos6502MCCodeEmitter);
// Register the asm backend.
TargetRegistry::RegisterMCAsmBackend(*T, createMos6502AsmBackend);
// Register the object target streamer.
TargetRegistry::RegisterObjectTargetStreamer(*T,
createObjectTargetStreamer);
// Register the asm streamer.
TargetRegistry::RegisterAsmTargetStreamer(*T, createTargetAsmStreamer);
// Register the MCInstPrinter
TargetRegistry::RegisterMCInstPrinter(*T, createMos6502MCInstPrinter);
}
// Register the MC codegen info.
TargetRegistry::RegisterMCCodeGenInfo(TheMos6502Target,
createMos6502MCCodeGenInfo);
TargetRegistry::RegisterMCCodeGenInfo(TheMos6502V9Target,
createMos6502V9MCCodeGenInfo);
TargetRegistry::RegisterMCCodeGenInfo(TheMos6502elTarget,
createMos6502MCCodeGenInfo);
}

View File

@ -0,0 +1,60 @@
//===-- Mos6502MCTargetDesc.h - Mos6502 Target Descriptions ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Mos6502 specific target descriptions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCTARGETDESC_H
#define LLVM_LIB_TARGET_MOS6502_MCTARGETDESC_MOS6502MCTARGETDESC_H
#include "llvm/Support/DataTypes.h"
namespace llvm {
class MCAsmBackend;
class MCCodeEmitter;
class MCContext;
class MCInstrInfo;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
class Target;
class Triple;
class StringRef;
class raw_pwrite_stream;
class raw_ostream;
extern Target TheMos6502Target;
extern Target TheMos6502V9Target;
extern Target TheMos6502elTarget;
MCCodeEmitter *createMos6502MCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
MCAsmBackend *createMos6502AsmBackend(const Target &T, const MCRegisterInfo &MRI,
const Triple &TT, StringRef CPU);
MCObjectWriter *createMos6502ELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit,
bool IsLIttleEndian, uint8_t OSABI);
} // End llvm namespace
// Defines symbolic names for Mos6502 registers. This defines a mapping from
// register name to register number.
//
#define GET_REGINFO_ENUM
#include "Mos6502GenRegisterInfo.inc"
// Defines symbolic names for the Mos6502 instructions.
//
#define GET_INSTRINFO_ENUM
#include "Mos6502GenInstrInfo.inc"
#define GET_SUBTARGETINFO_ENUM
#include "Mos6502GenSubtargetInfo.inc"
#endif

View File

@ -0,0 +1,46 @@
//===-- Mos6502TargetStreamer.cpp - Mos6502 Target Streamer Methods -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file provides Mos6502 specific target streamer methods.
//
//===----------------------------------------------------------------------===//
#include "Mos6502TargetStreamer.h"
#include "InstPrinter/Mos6502InstPrinter.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
// pin vtable to this file
Mos6502TargetStreamer::Mos6502TargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
void Mos6502TargetStreamer::anchor() {}
Mos6502TargetAsmStreamer::Mos6502TargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS)
: Mos6502TargetStreamer(S), OS(OS) {}
void Mos6502TargetAsmStreamer::emitMos6502RegisterIgnore(unsigned reg) {
OS << "\t.register "
<< "%" << StringRef(Mos6502InstPrinter::getRegisterName(reg)).lower()
<< ", #ignore\n";
}
void Mos6502TargetAsmStreamer::emitMos6502RegisterScratch(unsigned reg) {
OS << "\t.register "
<< "%" << StringRef(Mos6502InstPrinter::getRegisterName(reg)).lower()
<< ", #scratch\n";
}
Mos6502TargetELFStreamer::Mos6502TargetELFStreamer(MCStreamer &S)
: Mos6502TargetStreamer(S) {}
MCELFStreamer &Mos6502TargetELFStreamer::getStreamer() {
return static_cast<MCELFStreamer &>(Streamer);
}

View File

@ -0,0 +1,24 @@
##===- lib/Target/Mos6502/Makefile -------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../..
LIBRARYNAME = LLVMMos6502CodeGen
TARGET = Mos6502
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = Mos6502GenRegisterInfo.inc Mos6502GenInstrInfo.inc \
Mos6502GenAsmWriter.inc Mos6502GenAsmMatcher.inc \
Mos6502GenDAGISel.inc Mos6502GenDisassemblerTables.inc \
Mos6502GenSubtargetInfo.inc Mos6502GenCallingConv.inc \
Mos6502GenMCCodeEmitter.inc
DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,134 @@
//===-- Mos6502.h - Top-level interface for Mos6502 representation --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the entry points for global functions defined in the LLVM
// Mos6502 back-end.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502_H
#include "MCTargetDesc/Mos6502MCTargetDesc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class FunctionPass;
class Mos6502TargetMachine;
class formatted_raw_ostream;
class AsmPrinter;
class MCInst;
class MachineInstr;
FunctionPass *createMos6502ISelDag(Mos6502TargetMachine &TM);
FunctionPass *createMos6502DelaySlotFillerPass(TargetMachine &TM);
void LowerMos6502MachineInstrToMCInst(const MachineInstr *MI,
MCInst &OutMI,
AsmPrinter &AP);
} // end namespace llvm;
namespace llvm {
// Enums corresponding to Mos6502 condition codes, both icc's and fcc's. These
// values must be kept in sync with the ones in the .td file.
namespace SPCC {
enum CondCodes {
ICC_A = 8 , // Always
ICC_N = 0 , // Never
ICC_NE = 9 , // Not Equal
ICC_E = 1 , // Equal
ICC_G = 10 , // Greater
ICC_LE = 2 , // Less or Equal
ICC_GE = 11 , // Greater or Equal
ICC_L = 3 , // Less
ICC_GU = 12 , // Greater Unsigned
ICC_LEU = 4 , // Less or Equal Unsigned
ICC_CC = 13 , // Carry Clear/Great or Equal Unsigned
ICC_CS = 5 , // Carry Set/Less Unsigned
ICC_POS = 14 , // Positive
ICC_NEG = 6 , // Negative
ICC_VC = 15 , // Overflow Clear
ICC_VS = 7 , // Overflow Set
FCC_A = 8+16, // Always
FCC_N = 0+16, // Never
FCC_U = 7+16, // Unordered
FCC_G = 6+16, // Greater
FCC_UG = 5+16, // Unordered or Greater
FCC_L = 4+16, // Less
FCC_UL = 3+16, // Unordered or Less
FCC_LG = 2+16, // Less or Greater
FCC_NE = 1+16, // Not Equal
FCC_E = 9+16, // Equal
FCC_UE = 10+16, // Unordered or Equal
FCC_GE = 11+16, // Greater or Equal
FCC_UGE = 12+16, // Unordered or Greater or Equal
FCC_LE = 13+16, // Less or Equal
FCC_ULE = 14+16, // Unordered or Less or Equal
FCC_O = 15+16 // Ordered
};
}
inline static const char *MOS6502CondCodeToString(SPCC::CondCodes CC) {
switch (CC) {
case SPCC::ICC_A: return "a";
case SPCC::ICC_N: return "n";
case SPCC::ICC_NE: return "ne";
case SPCC::ICC_E: return "e";
case SPCC::ICC_G: return "g";
case SPCC::ICC_LE: return "le";
case SPCC::ICC_GE: return "ge";
case SPCC::ICC_L: return "l";
case SPCC::ICC_GU: return "gu";
case SPCC::ICC_LEU: return "leu";
case SPCC::ICC_CC: return "cc";
case SPCC::ICC_CS: return "cs";
case SPCC::ICC_POS: return "pos";
case SPCC::ICC_NEG: return "neg";
case SPCC::ICC_VC: return "vc";
case SPCC::ICC_VS: return "vs";
case SPCC::FCC_A: return "a";
case SPCC::FCC_N: return "n";
case SPCC::FCC_U: return "u";
case SPCC::FCC_G: return "g";
case SPCC::FCC_UG: return "ug";
case SPCC::FCC_L: return "l";
case SPCC::FCC_UL: return "ul";
case SPCC::FCC_LG: return "lg";
case SPCC::FCC_NE: return "ne";
case SPCC::FCC_E: return "e";
case SPCC::FCC_UE: return "ue";
case SPCC::FCC_GE: return "ge";
case SPCC::FCC_UGE: return "uge";
case SPCC::FCC_LE: return "le";
case SPCC::FCC_ULE: return "ule";
case SPCC::FCC_O: return "o";
}
llvm_unreachable("Invalid cond code");
}
inline static unsigned HI22(int64_t imm) {
return (unsigned)((imm >> 10) & ((1 << 22)-1));
}
inline static unsigned LO10(int64_t imm) {
return (unsigned)(imm & 0x3FF);
}
inline static unsigned HIX22(int64_t imm) {
return HI22(~imm);
}
inline static unsigned LOX10(int64_t imm) {
return ~LO10(~imm);
}
} // end namespace llvm
#endif

View File

@ -0,0 +1,106 @@
//===-- Mos6502.td - Describe the Mos6502 Target Machine -------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
// MOS6502 Subtarget features.
//
def FeatureV9
: SubtargetFeature<"v9", "IsV9", "true",
"Enable MOS6502-V9 instructions">;
def FeatureV8Deprecated
: SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true",
"Enable deprecated V8 instructions in V9 mode">;
def FeatureVIS
: SubtargetFeature<"vis", "IsVIS", "true",
"Enable UltraMOS6502 Visual Instruction Set extensions">;
def FeatureVIS2
: SubtargetFeature<"vis2", "IsVIS2", "true",
"Enable Visual Instruction Set extensions II">;
def FeatureVIS3
: SubtargetFeature<"vis3", "IsVIS3", "true",
"Enable Visual Instruction Set extensions III">;
def FeatureHardQuad
: SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
"Enable quad-word floating point instructions">;
def UsePopc : SubtargetFeature<"popc", "UsePopc", "true",
"Use the popc (population count) instruction">;
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//
include "Mos6502RegisterInfo.td"
include "Mos6502CallingConv.td"
include "Mos6502InstrInfo.td"
def Mos6502InstrInfo : InstrInfo;
def Mos6502AsmParser : AsmParser {
bit ShouldEmitMatchRegisterName = 0;
}
//===----------------------------------------------------------------------===//
// MOS6502 processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>;
def : Proc<"generic", []>;
def : Proc<"v7", []>;
def : Proc<"v8", []>;
def : Proc<"supermos6502", []>;
def : Proc<"mos6502lite", []>;
def : Proc<"f934", []>;
def : Proc<"hypermos6502", []>;
def : Proc<"mos6502lite86x", []>;
def : Proc<"mos6502let", []>;
def : Proc<"tsc701", []>;
def : Proc<"v9", [FeatureV9]>;
def : Proc<"ultramos6502", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
def : Proc<"ultramos65023", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
FeatureVIS2]>;
def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
FeatureVIS2]>;
def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc,
FeatureVIS, FeatureVIS2]>;
def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc,
FeatureVIS, FeatureVIS2]>;
def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc,
FeatureVIS, FeatureVIS2, FeatureVIS3]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def Mos6502AsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
int PassSubtarget = 1;
int Variant = 0;
}
def Mos6502 : Target {
// Pull in Instruction Info:
let InstructionSet = Mos6502InstrInfo;
let AssemblyParsers = [Mos6502AsmParser];
let AssemblyWriters = [Mos6502AsmWriter];
}

View File

@ -0,0 +1,449 @@
//===-- Mos6502AsmPrinter.cpp - Mos6502 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 GAS-format MOS6502 assembly language.
//
//===----------------------------------------------------------------------===//
#include "Mos6502.h"
#include "InstPrinter/Mos6502InstPrinter.h"
#include "MCTargetDesc/Mos6502MCExpr.h"
#include "Mos6502InstrInfo.h"
#include "Mos6502TargetMachine.h"
#include "Mos6502TargetStreamer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
namespace {
class Mos6502AsmPrinter : public AsmPrinter {
Mos6502TargetStreamer &getTargetStreamer() {
return static_cast<Mos6502TargetStreamer &>(
*OutStreamer->getTargetStreamer());
}
public:
explicit Mos6502AsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer)
: AsmPrinter(TM, std::move(Streamer)) {}
const char *getPassName() const override {
return "Mos6502 Assembly Printer";
}
void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
const char *Modifier = nullptr);
void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
void EmitFunctionBodyStart() override;
void EmitInstruction(const MachineInstr *MI) override;
static const char *getRegisterName(unsigned RegNo) {
return Mos6502InstPrinter::getRegisterName(RegNo);
}
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O) override;
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &O) override;
void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
const MCSubtargetInfo &STI);
};
} // end of anonymous namespace
static MCOperand createMos6502MCOperand(Mos6502MCExpr::VariantKind Kind,
MCSymbol *Sym, MCContext &OutContext) {
const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym,
OutContext);
const Mos6502MCExpr *expr = Mos6502MCExpr::create(Kind, MCSym, OutContext);
return MCOperand::createExpr(expr);
}
static MCOperand createPCXCallOP(MCSymbol *Label,
MCContext &OutContext) {
return createMos6502MCOperand(Mos6502MCExpr::VK_Mos6502_None, Label, OutContext);
}
static MCOperand createPCXRelExprOp(Mos6502MCExpr::VariantKind Kind,
MCSymbol *GOTLabel, MCSymbol *StartLabel,
MCSymbol *CurLabel,
MCContext &OutContext)
{
const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,
OutContext);
const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,
OutContext);
const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);
const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);
const Mos6502MCExpr *expr = Mos6502MCExpr::create(Kind,
Add, OutContext);
return MCOperand::createExpr(expr);
}
static void EmitCall(MCStreamer &OutStreamer,
MCOperand &Callee,
const MCSubtargetInfo &STI)
{
MCInst CallInst;
CallInst.setOpcode(SP::CALL);
CallInst.addOperand(Callee);
OutStreamer.EmitInstruction(CallInst, STI);
}
static void EmitSETHI(MCStreamer &OutStreamer,
MCOperand &Imm, MCOperand &RD,
const MCSubtargetInfo &STI)
{
MCInst SETHIInst;
SETHIInst.setOpcode(SP::SETHIi);
SETHIInst.addOperand(RD);
SETHIInst.addOperand(Imm);
OutStreamer.EmitInstruction(SETHIInst, STI);
}
static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
const MCSubtargetInfo &STI)
{
MCInst Inst;
Inst.setOpcode(Opcode);
Inst.addOperand(RD);
Inst.addOperand(RS1);
Inst.addOperand(Src2);
OutStreamer.EmitInstruction(Inst, STI);
}
static void EmitOR(MCStreamer &OutStreamer,
MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
const MCSubtargetInfo &STI) {
EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);
}
static void EmitADD(MCStreamer &OutStreamer,
MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
const MCSubtargetInfo &STI) {
EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);
}
static void EmitSHL(MCStreamer &OutStreamer,
MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
const MCSubtargetInfo &STI) {
EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);
}
static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
Mos6502MCExpr::VariantKind HiKind,
Mos6502MCExpr::VariantKind LoKind,
MCOperand &RD,
MCContext &OutContext,
const MCSubtargetInfo &STI) {
MCOperand hi = createMos6502MCOperand(HiKind, GOTSym, OutContext);
MCOperand lo = createMos6502MCOperand(LoKind, GOTSym, OutContext);
EmitSETHI(OutStreamer, hi, RD, STI);
EmitOR(OutStreamer, RD, lo, RD, STI);
}
void Mos6502AsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
const MCSubtargetInfo &STI)
{
MCSymbol *GOTLabel =
OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
const MachineOperand &MO = MI->getOperand(0);
assert(MO.getReg() != SP::O7 &&
"%o7 is assigned as destination for getpcx!");
MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
if (TM.getRelocationModel() != Reloc::PIC_) {
// Just load the address of GOT to MCRegOP.
switch(TM.getCodeModel()) {
default:
llvm_unreachable("Unsupported absolute code model");
case CodeModel::Small:
EmitHiLo(*OutStreamer, GOTLabel,
Mos6502MCExpr::VK_Mos6502_HI, Mos6502MCExpr::VK_Mos6502_LO,
MCRegOP, OutContext, STI);
break;
case CodeModel::Medium: {
EmitHiLo(*OutStreamer, GOTLabel,
Mos6502MCExpr::VK_Mos6502_H44, Mos6502MCExpr::VK_Mos6502_M44,
MCRegOP, OutContext, STI);
MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,
OutContext));
EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
MCOperand lo = createMos6502MCOperand(Mos6502MCExpr::VK_Mos6502_L44,
GOTLabel, OutContext);
EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);
break;
}
case CodeModel::Large: {
EmitHiLo(*OutStreamer, GOTLabel,
Mos6502MCExpr::VK_Mos6502_HH, Mos6502MCExpr::VK_Mos6502_HM,
MCRegOP, OutContext, STI);
MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,
OutContext));
EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
// Use register %o7 to load the lower 32 bits.
MCOperand RegO7 = MCOperand::createReg(SP::O7);
EmitHiLo(*OutStreamer, GOTLabel,
Mos6502MCExpr::VK_Mos6502_HI, Mos6502MCExpr::VK_Mos6502_LO,
RegO7, OutContext, STI);
EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
}
}
return;
}
MCSymbol *StartLabel = OutContext.createTempSymbol();
MCSymbol *EndLabel = OutContext.createTempSymbol();
MCSymbol *SethiLabel = OutContext.createTempSymbol();
MCOperand RegO7 = MCOperand::createReg(SP::O7);
// <StartLabel>:
// call <EndLabel>
// <SethiLabel>:
// sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
// <EndLabel>:
// or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
// add <MO>, %o7, <MO>
OutStreamer->EmitLabel(StartLabel);
MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
EmitCall(*OutStreamer, Callee, STI);
OutStreamer->EmitLabel(SethiLabel);
MCOperand hiImm = createPCXRelExprOp(Mos6502MCExpr::VK_Mos6502_PC22,
GOTLabel, StartLabel, SethiLabel,
OutContext);
EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);
OutStreamer->EmitLabel(EndLabel);
MCOperand loImm = createPCXRelExprOp(Mos6502MCExpr::VK_Mos6502_PC10,
GOTLabel, StartLabel, EndLabel,
OutContext);
EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);
EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
}
void Mos6502AsmPrinter::EmitInstruction(const MachineInstr *MI)
{
switch (MI->getOpcode()) {
default: break;
case TargetOpcode::DBG_VALUE:
// FIXME: Debug Value.
return;
case SP::GETPCX:
LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());
return;
}
MachineBasicBlock::const_instr_iterator I = MI;
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
do {
MCInst TmpInst;
LowerMos6502MachineInstrToMCInst(I, TmpInst, *this);
EmitToStreamer(*OutStreamer, TmpInst);
} while ((++I != E) && I->isInsideBundle()); // Delay slot check.
}
void Mos6502AsmPrinter::EmitFunctionBodyStart() {
if (!MF->getSubtarget<Mos6502Subtarget>().is64Bit())
return;
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;
if (reg == SP::G6 || reg == SP::G7)
getTargetStreamer().emitMos6502RegisterIgnore(reg);
else
getTargetStreamer().emitMos6502RegisterScratch(reg);
}
}
void Mos6502AsmPrinter::printOperand(const MachineInstr *MI, int opNum,
raw_ostream &O) {
const DataLayout &DL = getDataLayout();
const MachineOperand &MO = MI->getOperand (opNum);
Mos6502MCExpr::VariantKind TF = (Mos6502MCExpr::VariantKind) MO.getTargetFlags();
#ifndef NDEBUG
// Verify the target flags.
if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
if (MI->getOpcode() == SP::CALL)
assert(TF == Mos6502MCExpr::VK_Mos6502_None &&
"Cannot handle target flags on call address");
else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
assert((TF == Mos6502MCExpr::VK_Mos6502_HI
|| TF == Mos6502MCExpr::VK_Mos6502_H44
|| TF == Mos6502MCExpr::VK_Mos6502_HH
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_GD_HI22
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDM_HI22
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDO_HIX22
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_IE_HI22
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LE_HIX22) &&
"Invalid target flags for address operand on sethi");
else if (MI->getOpcode() == SP::TLS_CALL)
assert((TF == Mos6502MCExpr::VK_Mos6502_None
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_GD_CALL
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDM_CALL) &&
"Cannot handle target flags on tls call address");
else if (MI->getOpcode() == SP::TLS_ADDrr)
assert((TF == Mos6502MCExpr::VK_Mos6502_TLS_GD_ADD
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDM_ADD
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDO_ADD
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_IE_ADD) &&
"Cannot handle target flags on add for TLS");
else if (MI->getOpcode() == SP::TLS_LDrr)
assert(TF == Mos6502MCExpr::VK_Mos6502_TLS_IE_LD &&
"Cannot handle target flags on ld for TLS");
else if (MI->getOpcode() == SP::TLS_LDXrr)
assert(TF == Mos6502MCExpr::VK_Mos6502_TLS_IE_LDX &&
"Cannot handle target flags on ldx for TLS");
else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
assert((TF == Mos6502MCExpr::VK_Mos6502_TLS_LDO_LOX10
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LE_LOX10) &&
"Cannot handle target flags on xor for TLS");
else
assert((TF == Mos6502MCExpr::VK_Mos6502_LO
|| TF == Mos6502MCExpr::VK_Mos6502_M44
|| TF == Mos6502MCExpr::VK_Mos6502_L44
|| TF == Mos6502MCExpr::VK_Mos6502_HM
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_GD_LO10
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_LDM_LO10
|| TF == Mos6502MCExpr::VK_Mos6502_TLS_IE_LO10 ) &&
"Invalid target flags for small address operand");
}
#endif
bool CloseParen = Mos6502MCExpr::printVariantKind(O, TF);
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:
MO.getMBB()->getSymbol()->print(O, MAI);
return;
case MachineOperand::MO_GlobalAddress:
getSymbol(MO.getGlobal())->print(O, MAI);
break;
case MachineOperand::MO_BlockAddress:
O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();
break;
case MachineOperand::MO_ExternalSymbol:
O << MO.getSymbolName();
break;
case MachineOperand::MO_ConstantPoolIndex:
O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
<< MO.getIndex();
break;
default:
llvm_unreachable("<unknown operand type>");
}
if (CloseParen) O << ")";
}
void Mos6502AsmPrinter::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);
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool Mos6502AsmPrinter::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 Mos6502AsmPrinter::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;
}
// Force static initialization.
extern "C" void LLVMInitializeMos6502AsmPrinter() {
RegisterAsmPrinter<Mos6502AsmPrinter> X(TheMos6502Target);
RegisterAsmPrinter<Mos6502AsmPrinter> Y(TheMos6502V9Target);
RegisterAsmPrinter<Mos6502AsmPrinter> Z(TheMos6502elTarget);
}

View File

@ -0,0 +1,139 @@
//===-- Mos6502CallingConv.td - Calling Conventions Mos6502 ----*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This describes the calling conventions for the Mos6502 architectures.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// MOS6502 v8 32-bit.
//===----------------------------------------------------------------------===//
def CC_Mos650232 : CallingConv<[
// Custom assign SRet to [sp+64].
CCIfSRet<CCCustom<"CC_Mos6502_Assign_SRet">>,
// i32 f32 arguments get passed in integer registers if there is space.
CCIfType<[i32, f32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
// f64 arguments are split and passed through registers or through stack.
CCIfType<[f64], CCCustom<"CC_Mos6502_Assign_f64">>,
// Alternatively, they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;
def RetCC_Mos650232 : CallingConv<[
CCIfType<[i32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>,
CCIfType<[f64], CCAssignToReg<[D0, D1]>>
]>;
//===----------------------------------------------------------------------===//
// MOS6502 v9 64-bit.
//===----------------------------------------------------------------------===//
//
// The 64-bit ABI conceptually assigns all function arguments to a parameter
// array starting at [%fp+BIAS+128] in the callee's stack frame. All arguments
// occupy a multiple of 8 bytes in the array. Integer arguments are extended to
// 64 bits by the caller. Floats are right-aligned in their 8-byte slot, the
// first 4 bytes in the slot are undefined.
//
// The integer registers %i0 to %i5 shadow the first 48 bytes of the parameter
// array at fixed offsets. Integer arguments are promoted to registers when
// possible.
//
// The floating point registers %f0 to %f31 shadow the first 128 bytes of the
// parameter array at fixed offsets. Float and double parameters are promoted
// to these registers when possible.
//
// Structs up to 16 bytes in size are passed by value. They are right-aligned
// in one or two 8-byte slots in the parameter array. Struct members are
// promoted to both floating point and integer registers when possible. A
// struct containing two floats would thus be passed in %f0 and %f1, while two
// float function arguments would occupy 8 bytes each, and be passed in %f1 and
// %f3.
//
// When a struct { int, float } is passed by value, the int goes in the high
// bits of an integer register while the float goes in a floating point
// register.
//
// The difference is encoded in LLVM IR using the inreg atttribute on function
// arguments:
//
// C: void f(float, float);
// IR: declare void f(float %f1, float %f3)
//
// C: void f(struct { float f0, f1; });
// IR: declare void f(float inreg %f0, float inreg %f1)
//
// C: void f(int, float);
// IR: declare void f(int signext %i0, float %f3)
//
// C: void f(struct { int i0high; float f1; });
// IR: declare void f(i32 inreg %i0high, float inreg %f1)
//
// Two ints in a struct are simply coerced to i64:
//
// C: void f(struct { int i0high, i0low; });
// IR: declare void f(i64 %i0.coerced)
//
// The frontend and backend divide the task of producing ABI compliant code for
// C functions. The C frontend will:
//
// - Annotate integer arguments with zeroext or signext attributes.
//
// - Split structs into one or two 64-bit sized chunks, or 32-bit chunks with
// inreg attributes.
//
// - Pass structs larger than 16 bytes indirectly with an explicit pointer
// argument. The byval attribute is not used.
//
// The backend will:
//
// - Assign all arguments to 64-bit aligned stack slots, 32-bits for inreg.
//
// - Promote to integer or floating point registers depending on type.
//
// Function return values are passed exactly like function arguments, except a
// struct up to 32 bytes in size can be returned in registers.
// Function arguments AND most return values.
def CC_Mos650264 : CallingConv<[
// The frontend uses the inreg flag to indicate i32 and float arguments from
// structs. These arguments are not promoted to 64 bits, but they can still
// be assigned to integer and float registers.
CCIfInReg<CCIfType<[i32, f32], CCCustom<"CC_Mos650264_Half">>>,
// All integers are promoted to i64 by the caller.
CCIfType<[i32], CCPromoteToType<i64>>,
// Custom assignment is required because stack space is reserved for all
// arguments whether they are passed in registers or not.
CCCustom<"CC_Mos650264_Full">
]>;
def RetCC_Mos650264 : CallingConv<[
// A single f32 return value always goes in %f0. The ABI doesn't specify what
// happens to multiple f32 return values outside a struct.
CCIfType<[f32], CCCustom<"CC_Mos650264_Half">>,
// Otherwise, return values are passed exactly like arguments.
CCDelegateTo<CC_Mos650264>
]>;
// Callee-saved registers are handled by the register window mechanism.
def CSR : CalleeSavedRegs<(add)> {
let OtherPreserved = (add (sequence "I%u", 0, 7),
(sequence "L%u", 0, 7));
}
// Callee-saved registers for calls with ReturnsTwice attribute.
def RTCSR : CalleeSavedRegs<(add)> {
let OtherPreserved = (add I6, I7);
}

View File

@ -0,0 +1,258 @@
//===-- Mos6502FrameLowering.cpp - Mos6502 Frame Information ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mos6502 implementation of TargetFrameLowering class.
//
//===----------------------------------------------------------------------===//
#include "Mos6502FrameLowering.h"
#include "Mos6502InstrInfo.h"
#include "Mos6502MachineFunctionInfo.h"
#include "Mos6502Subtarget.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
static cl::opt<bool>
DisableLeafProc("disable-mos6502-leaf-proc",
cl::init(false),
cl::desc("Disable Mos6502 leaf procedure optimization."),
cl::Hidden);
Mos6502FrameLowering::Mos6502FrameLowering(const Mos6502Subtarget &ST)
: TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
ST.is64Bit() ? 16 : 8, 0, ST.is64Bit() ? 16 : 8) {}
void Mos6502FrameLowering::emitSPAdjustment(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
int NumBytes,
unsigned ADDrr,
unsigned ADDri) const {
DebugLoc dl = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
const Mos6502InstrInfo &TII =
*static_cast<const Mos6502InstrInfo *>(MF.getSubtarget().getInstrInfo());
if (NumBytes >= -4096 && NumBytes < 4096) {
BuildMI(MBB, MBBI, dl, TII.get(ADDri), SP::O6)
.addReg(SP::O6).addImm(NumBytes);
return;
}
// Emit this the hard way. This clobbers G1 which we always know is
// available here.
if (NumBytes >= 0) {
// Emit nonnegative numbers with sethi + or.
// sethi %hi(NumBytes), %g1
// or %g1, %lo(NumBytes), %g1
// add %sp, %g1, %sp
BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HI22(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1)
.addReg(SP::G1).addImm(LO10(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
.addReg(SP::O6).addReg(SP::G1);
return ;
}
// Emit negative numbers with sethi + xor.
// sethi %hix(NumBytes), %g1
// xor %g1, %lox(NumBytes), %g1
// add %sp, %g1, %sp
BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HIX22(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(SP::XORri), SP::G1)
.addReg(SP::G1).addImm(LOX10(NumBytes));
BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
.addReg(SP::O6).addReg(SP::G1);
}
void Mos6502FrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
Mos6502MachineFunctionInfo *FuncInfo = MF.getInfo<Mos6502MachineFunctionInfo>();
assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
MachineFrameInfo *MFI = MF.getFrameInfo();
const Mos6502InstrInfo &TII =
*static_cast<const Mos6502InstrInfo *>(MF.getSubtarget().getInstrInfo());
MachineBasicBlock::iterator MBBI = MBB.begin();
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
// Get the number of bytes to allocate from the FrameInfo
int NumBytes = (int) MFI->getStackSize();
unsigned SAVEri = SP::SAVEri;
unsigned SAVErr = SP::SAVErr;
if (FuncInfo->isLeafProc()) {
if (NumBytes == 0)
return;
SAVEri = SP::ADDri;
SAVErr = SP::ADDrr;
}
NumBytes = -MF.getSubtarget<Mos6502Subtarget>().getAdjustedFrameSize(NumBytes);
emitSPAdjustment(MF, MBB, MBBI, NumBytes, SAVErr, SAVEri);
MachineModuleInfo &MMI = MF.getMMI();
const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
unsigned regFP = MRI->getDwarfRegNum(SP::I6, true);
// Emit ".cfi_def_cfa_register 30".
unsigned CFIIndex =
MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// Emit ".cfi_window_save".
CFIIndex = MMI.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
unsigned regInRA = MRI->getDwarfRegNum(SP::I7, true);
unsigned regOutRA = MRI->getDwarfRegNum(SP::O7, true);
// Emit ".cfi_register 15, 31".
CFIIndex = MMI.addFrameInst(
MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
void Mos6502FrameLowering::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
if (!hasReservedCallFrame(MF)) {
MachineInstr &MI = *I;
int Size = MI.getOperand(0).getImm();
if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
Size = -Size;
if (Size)
emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri);
}
MBB.erase(I);
}
void Mos6502FrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
Mos6502MachineFunctionInfo *FuncInfo = MF.getInfo<Mos6502MachineFunctionInfo>();
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
const Mos6502InstrInfo &TII =
*static_cast<const Mos6502InstrInfo *>(MF.getSubtarget().getInstrInfo());
DebugLoc dl = MBBI->getDebugLoc();
assert(MBBI->getOpcode() == SP::RETL &&
"Can only put epilog before 'retl' instruction!");
if (!FuncInfo->isLeafProc()) {
BuildMI(MBB, MBBI, dl, TII.get(SP::RESTORErr), SP::G0).addReg(SP::G0)
.addReg(SP::G0);
return;
}
MachineFrameInfo *MFI = MF.getFrameInfo();
int NumBytes = (int) MFI->getStackSize();
if (NumBytes == 0)
return;
NumBytes = MF.getSubtarget<Mos6502Subtarget>().getAdjustedFrameSize(NumBytes);
emitSPAdjustment(MF, MBB, MBBI, NumBytes, SP::ADDrr, SP::ADDri);
}
bool Mos6502FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
// Reserve call frame if there are no variable sized objects on the stack.
return !MF.getFrameInfo()->hasVarSizedObjects();
}
// hasFP - Return true if the specified function should have a dedicated frame
// pointer register. This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
bool Mos6502FrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
return MF.getTarget().Options.DisableFramePointerElim(MF) ||
MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken();
}
static bool LLVM_ATTRIBUTE_UNUSED verifyLeafProcRegUse(MachineRegisterInfo *MRI)
{
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg)
if (!MRI->reg_nodbg_empty(reg))
return false;
for (unsigned reg = SP::L0; reg <= SP::L7; ++reg)
if (!MRI->reg_nodbg_empty(reg))
return false;
return true;
}
bool Mos6502FrameLowering::isLeafProc(MachineFunction &MF) const
{
MachineRegisterInfo &MRI = MF.getRegInfo();
MachineFrameInfo *MFI = MF.getFrameInfo();
return !(MFI->hasCalls() // has calls
|| !MRI.reg_nodbg_empty(SP::L0) // Too many registers needed
|| !MRI.reg_nodbg_empty(SP::O6) // %SP is used
|| hasFP(MF)); // need %FP
}
void Mos6502FrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
MachineRegisterInfo &MRI = MF.getRegInfo();
// Remap %i[0-7] to %o[0-7].
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
if (MRI.reg_nodbg_empty(reg))
continue;
unsigned mapped_reg = (reg - SP::I0 + SP::O0);
assert(MRI.reg_nodbg_empty(mapped_reg));
// Replace I register with O register.
MRI.replaceRegWith(reg, mapped_reg);
}
// Rewrite MBB's Live-ins.
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
MBB != E; ++MBB) {
for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
if (!MBB->isLiveIn(reg))
continue;
MBB->removeLiveIn(reg);
MBB->addLiveIn(reg - SP::I0 + SP::O0);
}
}
assert(verifyLeafProcRegUse(&MRI));
#ifdef XDEBUG
MF.verify(0, "After LeafProc Remapping");
#endif
}
void Mos6502FrameLowering::determineCalleeSaves(MachineFunction &MF,
BitVector &SavedRegs,
RegScavenger *RS) const {
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
if (!DisableLeafProc && isLeafProc(MF)) {
Mos6502MachineFunctionInfo *MFI = MF.getInfo<Mos6502MachineFunctionInfo>();
MFI->setLeafProc(true);
remapRegsForLeafProc(MF);
}
}

View File

@ -0,0 +1,60 @@
//===-- Mos6502FrameLowering.h - Define frame lowering for Mos6502 --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502FRAMELOWERING_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502FRAMELOWERING_H
#include "Mos6502.h"
#include "llvm/Target/TargetFrameLowering.h"
namespace llvm {
class Mos6502Subtarget;
class Mos6502FrameLowering : public TargetFrameLowering {
public:
explicit Mos6502FrameLowering(const Mos6502Subtarget &ST);
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
/// the function.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void
eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const override;
bool hasReservedCallFrame(const MachineFunction &MF) const override;
bool hasFP(const MachineFunction &MF) const override;
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
RegScavenger *RS = nullptr) const override;
private:
// Remap input registers to output registers for leaf procedure.
void remapRegsForLeafProc(MachineFunction &MF) const;
// Returns true if MF is a leaf procedure.
bool isLeafProc(MachineFunction &MF) const;
// Emits code for adjusting SP in function prologue/epilogue.
void emitSPAdjustment(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
int NumBytes, unsigned ADDrr, unsigned ADDri) const;
};
} // End llvm namespace
#endif

View File

@ -0,0 +1,227 @@
//===-- Mos6502ISelDAGToDAG.cpp - A dag to dag inst selector for Mos6502 ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an instruction selector for the MOS6502 target.
//
//===----------------------------------------------------------------------===//
#include "Mos6502TargetMachine.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
//===----------------------------------------------------------------------===//
// Instruction Selector Implementation
//===----------------------------------------------------------------------===//
//===--------------------------------------------------------------------===//
/// Mos6502DAGToDAGISel - MOS6502 specific code to select MOS6502 machine
/// instructions for SelectionDAG operations.
///
namespace {
class Mos6502DAGToDAGISel : public SelectionDAGISel {
/// Subtarget - Keep a pointer to the Mos6502 Subtarget around so that we can
/// make the right decision when generating code for different targets.
const Mos6502Subtarget *Subtarget;
public:
explicit Mos6502DAGToDAGISel(Mos6502TargetMachine &tm) : SelectionDAGISel(tm) {}
bool runOnMachineFunction(MachineFunction &MF) override {
Subtarget = &MF.getSubtarget<Mos6502Subtarget>();
return SelectionDAGISel::runOnMachineFunction(MF);
}
SDNode *Select(SDNode *N) override;
// Complex Pattern Selectors.
bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions.
bool SelectInlineAsmMemoryOperand(const SDValue &Op,
unsigned ConstraintID,
std::vector<SDValue> &OutOps) override;
const char *getPassName() const override {
return "MOS6502 DAG->DAG Pattern Instruction Selection";
}
// Include the pieces autogenerated from the target description.
#include "Mos6502GenDAGISel.inc"
private:
SDNode* getGlobalBaseReg();
};
} // end anonymous namespace
SDNode* Mos6502DAGToDAGISel::getGlobalBaseReg() {
unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
return CurDAG->getRegister(GlobalBaseReg,
TLI->getPointerTy(CurDAG->getDataLayout()))
.getNode();
}
bool Mos6502DAGToDAGISel::SelectADDRri(SDValue Addr,
SDValue &Base, SDValue &Offset) {
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(
FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress ||
Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
return false; // direct calls.
if (Addr.getOpcode() == ISD::ADD) {
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
if (isInt<13>(CN->getSExtValue())) {
if (FrameIndexSDNode *FIN =
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
// Constant offset from frame ref.
Base = CurDAG->getTargetFrameIndex(
FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
} else {
Base = Addr.getOperand(0);
}
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
MVT::i32);
return true;
}
}
if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
Base = Addr.getOperand(1);
Offset = Addr.getOperand(0).getOperand(0);
return true;
}
if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
Base = Addr.getOperand(0);
Offset = Addr.getOperand(1).getOperand(0);
return true;
}
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}
bool Mos6502DAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
if (Addr.getOpcode() == ISD::FrameIndex) return false;
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress ||
Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
return false; // direct calls.
if (Addr.getOpcode() == ISD::ADD) {
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
if (isInt<13>(CN->getSExtValue()))
return false; // Let the reg+imm pattern catch this!
if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
Addr.getOperand(1).getOpcode() == SPISD::Lo)
return false; // Let the reg+imm pattern catch this!
R1 = Addr.getOperand(0);
R2 = Addr.getOperand(1);
return true;
}
R1 = Addr;
R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
return true;
}
SDNode *Mos6502DAGToDAGISel::Select(SDNode *N) {
SDLoc dl(N);
if (N->isMachineOpcode()) {
N->setNodeId(-1);
return nullptr; // Already selected.
}
switch (N->getOpcode()) {
default: break;
case SPISD::GLOBAL_BASE_REG:
return getGlobalBaseReg();
case ISD::SDIV:
case ISD::UDIV: {
// sdivx / udivx handle 64-bit divides.
if (N->getValueType(0) == MVT::i64)
break;
// FIXME: should use a custom expander to expose the SRA to the dag.
SDValue DivLHS = N->getOperand(0);
SDValue DivRHS = N->getOperand(1);
// Set the Y register to the high-part.
SDValue TopPart;
if (N->getOpcode() == ISD::SDIV) {
TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
CurDAG->getTargetConstant(31, dl, MVT::i32)),
0);
} else {
TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
}
TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
SDValue())
.getValue(1);
// FIXME: Handle div by immediate.
unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS,
TopPart);
}
case ISD::MULHU:
case ISD::MULHS: {
// FIXME: Handle mul by immediate.
SDValue MulLHS = N->getOperand(0);
SDValue MulRHS = N->getOperand(1);
unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
SDNode *Mul =
CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS);
SDValue ResultHigh = SDValue(Mul, 1);
ReplaceUses(SDValue(N, 0), ResultHigh);
return nullptr;
}
}
return SelectCode(N);
}
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions.
bool
Mos6502DAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
unsigned ConstraintID,
std::vector<SDValue> &OutOps) {
SDValue Op0, Op1;
switch (ConstraintID) {
default: return true;
case InlineAsm::Constraint_i:
case InlineAsm::Constraint_m: // memory
if (!SelectADDRrr(Op, Op0, Op1))
SelectADDRri(Op, Op0, Op1);
break;
}
OutOps.push_back(Op0);
OutOps.push_back(Op1);
return false;
}
/// createMos6502ISelDag - This pass converts a legalized DAG into a
/// MOS6502-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createMos6502ISelDag(Mos6502TargetMachine &TM) {
return new Mos6502DAGToDAGISel(TM);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,182 @@
//===-- Mos6502ISelLowering.h - Mos6502 DAG Lowering Interface ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Mos6502 uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502ISELLOWERING_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502ISELLOWERING_H
#include "Mos6502.h"
#include "llvm/Target/TargetLowering.h"
namespace llvm {
class Mos6502Subtarget;
namespace SPISD {
enum NodeType : unsigned {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
CMPICC, // Compare two GPR operands, set icc+xcc.
CMPFCC, // Compare two FP operands, set fcc.
BRICC, // Branch to dest on icc condition
BRXCC, // Branch to dest on xcc condition (64-bit only).
BRFCC, // Branch to dest on fcc condition
SELECT_ICC, // Select between two values using the current ICC flags.
SELECT_XCC, // Select between two values using the current XCC flags.
SELECT_FCC, // Select between two values using the current FCC flags.
Hi, Lo, // Hi/Lo operations, typically on a global address.
FTOI, // FP to Int within a FP register.
ITOF, // Int to FP within a FP register.
FTOX, // FP to Int64 within a FP register.
XTOF, // Int64 to FP within a FP register.
CALL, // A call instruction.
RET_FLAG, // Return with a flag operand.
GLOBAL_BASE_REG, // Global base reg for PIC.
FLUSHW, // FLUSH register windows to stack.
TLS_ADD, // For Thread Local Storage (TLS).
TLS_LD,
TLS_CALL
};
}
class Mos6502TargetLowering : public TargetLowering {
const Mos6502Subtarget *Subtarget;
public:
Mos6502TargetLowering(TargetMachine &TM, const Mos6502Subtarget &STI);
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
/// computeKnownBitsForTargetNode - Determine which of the bits specified
/// in Mask are known to be either zero or one and return them in the
/// KnownZero/KnownOne bitsets.
void computeKnownBitsForTargetNode(const SDValue Op,
APInt &KnownZero,
APInt &KnownOne,
const SelectionDAG &DAG,
unsigned Depth = 0) const override;
MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *MBB) const override;
const char *getTargetNodeName(unsigned Opcode) const override;
ConstraintType getConstraintType(StringRef Constraint) const override;
ConstraintWeight
getSingleConstraintMatchWeight(AsmOperandInfo &info,
const char *constraint) const override;
void LowerAsmOperandForConstraint(SDValue Op,
std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
StringRef Constraint, MVT VT) const override;
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override {
return MVT::i32;
}
/// getSetCCResultType - Return the ISD::SETCC ValueType
EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context,
EVT VT) const override;
SDValue
LowerFormalArguments(SDValue Chain,
CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const override;
SDValue LowerFormalArguments_32(SDValue Chain,
CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
SDValue LowerFormalArguments_64(SDValue Chain,
CallingConv::ID CallConv,
bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
SDLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
SDValue
LowerCall(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const override;
SDValue LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const;
SDValue LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
SmallVectorImpl<SDValue> &InVals) const;
SDValue
LowerReturn(SDValue Chain,
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
SDLoc dl, SelectionDAG &DAG) const override;
SDValue LowerReturn_32(SDValue Chain,
CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
SDLoc DL, SelectionDAG &DAG) const;
SDValue LowerReturn_64(SDValue Chain,
CallingConv::ID CallConv, bool IsVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
SDLoc DL, SelectionDAG &DAG) const;
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
unsigned getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const;
SDValue withTargetFlags(SDValue Op, unsigned TF, SelectionDAG &DAG) const;
SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF,
SelectionDAG &DAG) const;
SDValue makeAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args,
SDValue Arg, SDLoc DL,
SelectionDAG &DAG) const;
SDValue LowerF128Op(SDValue Op, SelectionDAG &DAG,
const char *LibFuncName,
unsigned numArgs) const;
SDValue LowerF128Compare(SDValue LHS, SDValue RHS,
unsigned &SPCC,
SDLoc DL,
SelectionDAG &DAG) const;
bool ShouldShrinkFPConstant(EVT VT) const override {
// Do not shrink FP constpool if VT == MVT::f128.
// (ldd, call _Q_fdtoq) is more expensive than two ldds.
return VT != MVT::f128;
}
void ReplaceNodeResults(SDNode *N,
SmallVectorImpl<SDValue>& Results,
SelectionDAG &DAG) const override;
MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB,
unsigned BROpcode) const;
MachineBasicBlock *expandAtomicRMW(MachineInstr *MI,
MachineBasicBlock *BB,
unsigned Opcode,
unsigned CondCode = 0) const;
};
} // end namespace llvm
#endif // MOS6502_ISELLOWERING_H

View File

@ -0,0 +1,574 @@
//===-- Mos6502Instr64Bit.td - 64-bit instructions for Mos6502 Target ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains instruction definitions and patterns needed for 64-bit
// code generation on MOS6502 v9.
//
// Some MOS6502 v9 instructions are defined in Mos6502InstrInfo.td because they can
// also be used in 32-bit code running on a MOS6502 v9 CPU.
//
//===----------------------------------------------------------------------===//
let Predicates = [Is64Bit] in {
// The same integer registers are used for i32 and i64 values.
// When registers hold i32 values, the high bits are don't care.
// This give us free trunc and anyext.
def : Pat<(i64 (anyext i32:$val)), (COPY_TO_REGCLASS $val, I64Regs)>;
def : Pat<(i32 (trunc i64:$val)), (COPY_TO_REGCLASS $val, IntRegs)>;
} // Predicates = [Is64Bit]
//===----------------------------------------------------------------------===//
// 64-bit Shift Instructions.
//===----------------------------------------------------------------------===//
//
// The 32-bit shift instructions are still available. The left shift srl
// instructions shift all 64 bits, but it only accepts a 5-bit shift amount.
//
// The srl instructions only shift the low 32 bits and clear the high 32 bits.
// Finally, sra shifts the low 32 bits and sign-extends to 64 bits.
let Predicates = [Is64Bit] in {
def : Pat<(i64 (zext i32:$val)), (SRLri $val, 0)>;
def : Pat<(i64 (sext i32:$val)), (SRAri $val, 0)>;
def : Pat<(i64 (and i64:$val, 0xffffffff)), (SRLri $val, 0)>;
def : Pat<(i64 (sext_inreg i64:$val, i32)), (SRAri $val, 0)>;
defm SLLX : F3_S<"sllx", 0b100101, 1, shl, i64, I64Regs>;
defm SRLX : F3_S<"srlx", 0b100110, 1, srl, i64, I64Regs>;
defm SRAX : F3_S<"srax", 0b100111, 1, sra, i64, I64Regs>;
} // Predicates = [Is64Bit]
//===----------------------------------------------------------------------===//
// 64-bit Immediates.
//===----------------------------------------------------------------------===//
//
// All 32-bit immediates can be materialized with sethi+or, but 64-bit
// immediates may require more code. There may be a point where it is
// preferable to use a constant pool load instead, depending on the
// microarchitecture.
// Single-instruction patterns.
// The ALU instructions want their simm13 operands as i32 immediates.
def as_i32imm : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(N->getSExtValue(), SDLoc(N), MVT::i32);
}]>;
def : Pat<(i64 simm13:$val), (ORri (i64 G0), (as_i32imm $val))>;
def : Pat<(i64 SETHIimm:$val), (SETHIi (HI22 $val))>;
// Double-instruction patterns.
// All unsigned i32 immediates can be handled by sethi+or.
def uimm32 : PatLeaf<(imm), [{ return isUInt<32>(N->getZExtValue()); }]>;
def : Pat<(i64 uimm32:$val), (ORri (SETHIi (HI22 $val)), (LO10 $val))>,
Requires<[Is64Bit]>;
// All negative i33 immediates can be handled by sethi+xor.
def nimm33 : PatLeaf<(imm), [{
int64_t Imm = N->getSExtValue();
return Imm < 0 && isInt<33>(Imm);
}]>;
// Bits 10-31 inverted. Same as assembler's %hix.
def HIX22 : SDNodeXForm<imm, [{
uint64_t Val = (~N->getZExtValue() >> 10) & ((1u << 22) - 1);
return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
}]>;
// Bits 0-9 with ones in bits 10-31. Same as assembler's %lox.
def LOX10 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(~(~N->getZExtValue() & 0x3ff), SDLoc(N),
MVT::i32);
}]>;
def : Pat<(i64 nimm33:$val), (XORri (SETHIi (HIX22 $val)), (LOX10 $val))>,
Requires<[Is64Bit]>;
// More possible patterns:
//
// (sllx sethi, n)
// (sllx simm13, n)
//
// 3 instrs:
//
// (xor (sllx sethi), simm13)
// (sllx (xor sethi, simm13))
//
// 4 instrs:
//
// (or sethi, (sllx sethi))
// (xnor sethi, (sllx sethi))
//
// 5 instrs:
//
// (or (sllx sethi), (or sethi, simm13))
// (xnor (sllx sethi), (or sethi, simm13))
// (or (sllx sethi), (sllx sethi))
// (xnor (sllx sethi), (sllx sethi))
//
// Worst case is 6 instrs:
//
// (or (sllx (or sethi, simmm13)), (or sethi, simm13))
// Bits 42-63, same as assembler's %hh.
def HH22 : SDNodeXForm<imm, [{
uint64_t Val = (N->getZExtValue() >> 42) & ((1u << 22) - 1);
return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
}]>;
// Bits 32-41, same as assembler's %hm.
def HM10 : SDNodeXForm<imm, [{
uint64_t Val = (N->getZExtValue() >> 32) & ((1u << 10) - 1);
return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
}]>;
def : Pat<(i64 imm:$val),
(ORrr (SLLXri (ORri (SETHIi (HH22 $val)), (HM10 $val)), (i32 32)),
(ORri (SETHIi (HI22 $val)), (LO10 $val)))>,
Requires<[Is64Bit]>;
//===----------------------------------------------------------------------===//
// 64-bit Integer Arithmetic and Logic.
//===----------------------------------------------------------------------===//
let Predicates = [Is64Bit] in {
// Register-register instructions.
let isCodeGenOnly = 1 in {
defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>;
defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>;
defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>;
def ANDXNrr : F3_1<2, 0b000101,
(outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
"andn $b, $c, $dst",
[(set i64:$dst, (and i64:$b, (not i64:$c)))]>;
def ORXNrr : F3_1<2, 0b000110,
(outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
"orn $b, $c, $dst",
[(set i64:$dst, (or i64:$b, (not i64:$c)))]>;
def XNORXrr : F3_1<2, 0b000111,
(outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
"xnor $b, $c, $dst",
[(set i64:$dst, (not (xor i64:$b, i64:$c)))]>;
defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd),
(ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym),
"add $rs1, $rs2, $rd, $sym",
[(set i64:$rd,
(tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>;
// "LEA" form of add
def LEAX_ADDri : F3_2<2, 0b000000,
(outs I64Regs:$dst), (ins MEMri:$addr),
"add ${addr:arith}, $dst",
[(set iPTR:$dst, ADDRri:$addr)]>;
}
def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
def : Pat<(ctpop i64:$src), (POPCrr $src)>;
} // Predicates = [Is64Bit]
//===----------------------------------------------------------------------===//
// 64-bit Integer Multiply and Divide.
//===----------------------------------------------------------------------===//
let Predicates = [Is64Bit] in {
def MULXrr : F3_1<2, 0b001001,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
"mulx $rs1, $rs2, $rd",
[(set i64:$rd, (mul i64:$rs1, i64:$rs2))]>;
def MULXri : F3_2<2, 0b001001,
(outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
"mulx $rs1, $simm13, $rd",
[(set i64:$rd, (mul i64:$rs1, (i64 simm13:$simm13)))]>;
// Division can trap.
let hasSideEffects = 1 in {
def SDIVXrr : F3_1<2, 0b101101,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
"sdivx $rs1, $rs2, $rd",
[(set i64:$rd, (sdiv i64:$rs1, i64:$rs2))]>;
def SDIVXri : F3_2<2, 0b101101,
(outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
"sdivx $rs1, $simm13, $rd",
[(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$simm13)))]>;
def UDIVXrr : F3_1<2, 0b001101,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
"udivx $rs1, $rs2, $rd",
[(set i64:$rd, (udiv i64:$rs1, i64:$rs2))]>;
def UDIVXri : F3_2<2, 0b001101,
(outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
"udivx $rs1, $simm13, $rd",
[(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$simm13)))]>;
} // hasSideEffects = 1
} // Predicates = [Is64Bit]
//===----------------------------------------------------------------------===//
// 64-bit Loads and Stores.
//===----------------------------------------------------------------------===//
//
// All the 32-bit loads and stores are available. The extending loads are sign
// or zero-extending to 64 bits. The LDrr and LDri instructions load 32 bits
// zero-extended to i64. Their mnemonic is lduw in MOS6502 v9 (Load Unsigned
// Word).
//
// MOS6502 v9 adds 64-bit loads as well as a sign-extending ldsw i32 loads.
let Predicates = [Is64Bit] in {
// 64-bit loads.
let DecoderMethod = "DecodeLoadInt" in
defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in
def TLS_LDXrr : F3_1<3, 0b001011,
(outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
"ldx [$addr], $dst, $sym",
[(set i64:$dst,
(tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>;
// Extending loads to i64.
def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
def : Pat<(i64 (zextloadi1 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
def : Pat<(i64 (extloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi1 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
def : Pat<(i64 (zextloadi8 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
def : Pat<(i64 (zextloadi8 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
def : Pat<(i64 (extloadi8 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi8 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
def : Pat<(i64 (sextloadi8 ADDRrr:$addr)), (LDSBrr ADDRrr:$addr)>;
def : Pat<(i64 (sextloadi8 ADDRri:$addr)), (LDSBri ADDRri:$addr)>;
def : Pat<(i64 (zextloadi16 ADDRrr:$addr)), (LDUHrr ADDRrr:$addr)>;
def : Pat<(i64 (zextloadi16 ADDRri:$addr)), (LDUHri ADDRri:$addr)>;
def : Pat<(i64 (extloadi16 ADDRrr:$addr)), (LDUHrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi16 ADDRri:$addr)), (LDUHri ADDRri:$addr)>;
def : Pat<(i64 (sextloadi16 ADDRrr:$addr)), (LDSHrr ADDRrr:$addr)>;
def : Pat<(i64 (sextloadi16 ADDRri:$addr)), (LDSHri ADDRri:$addr)>;
def : Pat<(i64 (zextloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
def : Pat<(i64 (zextloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
// Sign-extending load of i32 into i64 is a new MOS6502 v9 instruction.
let DecoderMethod = "DecodeLoadInt" in
defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
// 64-bit stores.
let DecoderMethod = "DecodeStoreInt" in
defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
// Truncating stores from i64 are identical to the i32 stores.
def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
def : Pat<(truncstorei8 i64:$src, ADDRri:$addr), (STBri ADDRri:$addr, $src)>;
def : Pat<(truncstorei16 i64:$src, ADDRrr:$addr), (STHrr ADDRrr:$addr, $src)>;
def : Pat<(truncstorei16 i64:$src, ADDRri:$addr), (STHri ADDRri:$addr, $src)>;
def : Pat<(truncstorei32 i64:$src, ADDRrr:$addr), (STrr ADDRrr:$addr, $src)>;
def : Pat<(truncstorei32 i64:$src, ADDRri:$addr), (STri ADDRri:$addr, $src)>;
// store 0, addr -> store %g0, addr
def : Pat<(store (i64 0), ADDRrr:$dst), (STXrr ADDRrr:$dst, (i64 G0))>;
def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>;
} // Predicates = [Is64Bit]
//===----------------------------------------------------------------------===//
// 64-bit Conditionals.
//===----------------------------------------------------------------------===//
//
// Flag-setting instructions like subcc and addcc set both icc and xcc flags.
// The icc flags correspond to the 32-bit result, and the xcc are for the
// full 64-bit result.
//
// We reuse CMPICC SDNodes for compares, but use new BRXCC branch nodes for
// 64-bit compares. See LowerBR_CC.
let Predicates = [Is64Bit] in {
let Uses = [ICC], cc = 0b10 in
defm BPX : IPredBranch<"%xcc", [(SPbrxcc bb:$imm19, imm:$cond)]>;
// Conditional moves on %xcc.
let Uses = [ICC], Constraints = "$f = $rd" in {
let intcc = 1, cc = 0b10 in {
def MOVXCCrr : F4_1<0b101100, (outs IntRegs:$rd),
(ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
"mov$cond %xcc, $rs2, $rd",
[(set i32:$rd,
(SPselectxcc i32:$rs2, i32:$f, imm:$cond))]>;
def MOVXCCri : F4_2<0b101100, (outs IntRegs:$rd),
(ins i32imm:$simm11, IntRegs:$f, CCOp:$cond),
"mov$cond %xcc, $simm11, $rd",
[(set i32:$rd,
(SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>;
} // cc
let intcc = 1, opf_cc = 0b10 in {
def FMOVS_XCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
(ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
"fmovs$cond %xcc, $rs2, $rd",
[(set f32:$rd,
(SPselectxcc f32:$rs2, f32:$f, imm:$cond))]>;
def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
(ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
"fmovd$cond %xcc, $rs2, $rd",
[(set f64:$rd,
(SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>;
def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
"fmovq$cond %xcc, $rs2, $rd",
[(set f128:$rd,
(SPselectxcc f128:$rs2, f128:$f, imm:$cond))]>;
} // opf_cc
} // Uses, Constraints
// Branch On integer register with Prediction (BPr).
let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in
multiclass BranchOnReg<bits<3> cond, string OpcStr> {
def napt : F2_4<cond, 0, 1, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
!strconcat(OpcStr, " $rs1, $imm16"), []>;
def apt : F2_4<cond, 1, 1, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
!strconcat(OpcStr, ",a $rs1, $imm16"), []>;
def napn : F2_4<cond, 0, 0, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
!strconcat(OpcStr, ",pn $rs1, $imm16"), []>;
def apn : F2_4<cond, 1, 0, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
!strconcat(OpcStr, ",a,pn $rs1, $imm16"), []>;
}
multiclass bpr_alias<string OpcStr, Instruction NAPT, Instruction APT> {
def : InstAlias<!strconcat(OpcStr, ",pt $rs1, $imm16"),
(NAPT I64Regs:$rs1, bprtarget16:$imm16), 0>;
def : InstAlias<!strconcat(OpcStr, ",a,pt $rs1, $imm16"),
(APT I64Regs:$rs1, bprtarget16:$imm16), 0>;
}
defm BPZ : BranchOnReg<0b001, "brz">;
defm BPLEZ : BranchOnReg<0b010, "brlez">;
defm BPLZ : BranchOnReg<0b011, "brlz">;
defm BPNZ : BranchOnReg<0b101, "brnz">;
defm BPGZ : BranchOnReg<0b110, "brgz">;
defm BPGEZ : BranchOnReg<0b111, "brgez">;
defm : bpr_alias<"brz", BPZnapt, BPZapt >;
defm : bpr_alias<"brlez", BPLEZnapt, BPLEZapt>;
defm : bpr_alias<"brlz", BPLZnapt, BPLZapt >;
defm : bpr_alias<"brnz", BPNZnapt, BPNZapt >;
defm : bpr_alias<"brgz", BPGZnapt, BPGZapt >;
defm : bpr_alias<"brgez", BPGEZnapt, BPGEZapt>;
// Move integer register on register condition (MOVr).
multiclass MOVR< bits<3> rcond, string OpcStr> {
def rr : F4_4r<0b101111, 0b00000, rcond, (outs I64Regs:$rd),
(ins I64Regs:$rs1, IntRegs:$rs2),
!strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
def ri : F4_4i<0b101111, rcond, (outs I64Regs:$rd),
(ins I64Regs:$rs1, i64imm:$simm10),
!strconcat(OpcStr, " $rs1, $simm10, $rd"), []>;
}
defm MOVRRZ : MOVR<0b001, "movrz">;
defm MOVRLEZ : MOVR<0b010, "movrlez">;
defm MOVRLZ : MOVR<0b011, "movrlz">;
defm MOVRNZ : MOVR<0b101, "movrnz">;
defm MOVRGZ : MOVR<0b110, "movrgz">;
defm MOVRGEZ : MOVR<0b111, "movrgez">;
// Move FP register on integer register condition (FMOVr).
multiclass FMOVR<bits<3> rcond, string OpcStr> {
def S : F4_4r<0b110101, 0b00101, rcond,
(outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
!strconcat(!strconcat("fmovrs", OpcStr)," $rs1, $rs2, $rd"),
[]>;
def D : F4_4r<0b110101, 0b00110, rcond,
(outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
!strconcat(!strconcat("fmovrd", OpcStr)," $rs1, $rs2, $rd"),
[]>;
def Q : F4_4r<0b110101, 0b00111, rcond,
(outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
!strconcat(!strconcat("fmovrq", OpcStr)," $rs1, $rs2, $rd"),
[]>, Requires<[HasHardQuad]>;
}
let Predicates = [HasV9] in {
defm FMOVRZ : FMOVR<0b001, "z">;
defm FMOVRLEZ : FMOVR<0b010, "lez">;
defm FMOVRLZ : FMOVR<0b011, "lz">;
defm FMOVRNZ : FMOVR<0b101, "nz">;
defm FMOVRGZ : FMOVR<0b110, "gz">;
defm FMOVRGEZ : FMOVR<0b111, "gez">;
}
//===----------------------------------------------------------------------===//
// 64-bit Floating Point Conversions.
//===----------------------------------------------------------------------===//
let Predicates = [Is64Bit] in {
def FXTOS : F3_3u<2, 0b110100, 0b010000100,
(outs FPRegs:$rd), (ins DFPRegs:$rs2),
"fxtos $rs2, $rd",
[(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
def FXTOD : F3_3u<2, 0b110100, 0b010001000,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fxtod $rs2, $rd",
[(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
def FXTOQ : F3_3u<2, 0b110100, 0b010001100,
(outs QFPRegs:$rd), (ins DFPRegs:$rs2),
"fxtoq $rs2, $rd",
[(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
def FSTOX : F3_3u<2, 0b110100, 0b010000001,
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
"fstox $rs2, $rd",
[(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>;
def FDTOX : F3_3u<2, 0b110100, 0b010000010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fdtox $rs2, $rd",
[(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>;
def FQTOX : F3_3u<2, 0b110100, 0b010000011,
(outs DFPRegs:$rd), (ins QFPRegs:$rs2),
"fqtox $rs2, $rd",
[(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>,
Requires<[HasHardQuad]>;
} // Predicates = [Is64Bit]
def : Pat<(SPselectxcc i64:$t, i64:$f, imm:$cond),
(MOVXCCrr $t, $f, imm:$cond)>;
def : Pat<(SPselectxcc (i64 simm11:$t), i64:$f, imm:$cond),
(MOVXCCri (as_i32imm $t), $f, imm:$cond)>;
def : Pat<(SPselecticc i64:$t, i64:$f, imm:$cond),
(MOVICCrr $t, $f, imm:$cond)>;
def : Pat<(SPselecticc (i64 simm11:$t), i64:$f, imm:$cond),
(MOVICCri (as_i32imm $t), $f, imm:$cond)>;
def : Pat<(SPselectfcc i64:$t, i64:$f, imm:$cond),
(MOVFCCrr $t, $f, imm:$cond)>;
def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, imm:$cond),
(MOVFCCri (as_i32imm $t), $f, imm:$cond)>;
} // Predicates = [Is64Bit]
// 64 bit SETHI
let Predicates = [Is64Bit], isCodeGenOnly = 1 in {
def SETHIXi : F2_1<0b100,
(outs IntRegs:$rd), (ins i64imm:$imm22),
"sethi $imm22, $rd",
[(set i64:$rd, SETHIimm:$imm22)]>;
}
// ATOMICS.
let Predicates = [Is64Bit], Constraints = "$swap = $rd", asi = 0b10000000 in {
def CASXrr: F3_1_asi<3, 0b111110,
(outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2,
I64Regs:$swap),
"casx [$rs1], $rs2, $rd",
[(set i64:$rd,
(atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>;
} // Predicates = [Is64Bit], Constraints = ...
let Predicates = [Is64Bit] in {
def : Pat<(atomic_fence imm, imm), (MEMBARi 0xf)>;
// atomic_load_64 addr -> load addr
def : Pat<(i64 (atomic_load ADDRrr:$src)), (LDXrr ADDRrr:$src)>;
def : Pat<(i64 (atomic_load ADDRri:$src)), (LDXri ADDRri:$src)>;
// atomic_store_64 val, addr -> store val, addr
def : Pat<(atomic_store ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>;
def : Pat<(atomic_store ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>;
} // Predicates = [Is64Bit]
let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1,
Defs = [ICC] in
multiclass AtomicRMW<SDPatternOperator op32, SDPatternOperator op64> {
def _32 : Pseudo<(outs IntRegs:$rd),
(ins ptr_rc:$addr, IntRegs:$rs2), "",
[(set i32:$rd, (op32 iPTR:$addr, i32:$rs2))]>;
let Predicates = [Is64Bit] in
def _64 : Pseudo<(outs I64Regs:$rd),
(ins ptr_rc:$addr, I64Regs:$rs2), "",
[(set i64:$rd, (op64 iPTR:$addr, i64:$rs2))]>;
}
defm ATOMIC_LOAD_ADD : AtomicRMW<atomic_load_add_32, atomic_load_add_64>;
defm ATOMIC_LOAD_SUB : AtomicRMW<atomic_load_sub_32, atomic_load_sub_64>;
defm ATOMIC_LOAD_AND : AtomicRMW<atomic_load_and_32, atomic_load_and_64>;
defm ATOMIC_LOAD_OR : AtomicRMW<atomic_load_or_32, atomic_load_or_64>;
defm ATOMIC_LOAD_XOR : AtomicRMW<atomic_load_xor_32, atomic_load_xor_64>;
defm ATOMIC_LOAD_NAND : AtomicRMW<atomic_load_nand_32, atomic_load_nand_64>;
defm ATOMIC_LOAD_MIN : AtomicRMW<atomic_load_min_32, atomic_load_min_64>;
defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_32, atomic_load_max_64>;
defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>;
defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>;
// There is no 64-bit variant of SWAP, so use a pseudo.
let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1,
Defs = [ICC], Predicates = [Is64Bit] in
def ATOMIC_SWAP_64 : Pseudo<(outs I64Regs:$rd),
(ins ptr_rc:$addr, I64Regs:$rs2), "",
[(set i64:$rd,
(atomic_swap_64 iPTR:$addr, i64:$rs2))]>;
let Predicates = [Is64Bit], hasSideEffects = 1, Uses = [ICC], cc = 0b10 in
defm TXCC : TRAP<"%xcc">;
// Global addresses, constant pool entries
let Predicates = [Is64Bit] in {
def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
def : Pat<(SPlo tglobaladdr:$in), (ORXri (i64 G0), tglobaladdr:$in)>;
def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
def : Pat<(SPlo tconstpool:$in), (ORXri (i64 G0), tconstpool:$in)>;
// GlobalTLS addresses
def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>;
def : Pat<(SPlo tglobaltlsaddr:$in), (ORXri (i64 G0), tglobaltlsaddr:$in)>;
def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
(ADDXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
(XORXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
// Blockaddress
def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>;
def : Pat<(SPlo tblockaddress:$in), (ORXri (i64 G0), tblockaddress:$in)>;
// Add reg, lo. This is used when taking the addr of a global/constpool entry.
def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDXri $r, tglobaladdr:$in)>;
def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDXri $r, tconstpool:$in)>;
def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
(ADDXri $r, tblockaddress:$in)>;
}

View File

@ -0,0 +1,452 @@
//===-- Mos6502InstrAliases.td - Instruction Aliases for Mos6502 Target -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains instruction aliases for Mos6502.
//===----------------------------------------------------------------------===//
// Instruction aliases for conditional moves.
// mov<cond> <ccreg> rs2, rd
multiclass intcond_mov_alias<string cond, int condVal, string ccreg,
Instruction movrr, Instruction movri,
Instruction fmovs, Instruction fmovd> {
// mov<cond> (%icc|%xcc), rs2, rd
def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
", $rs2, $rd"),
(movrr IntRegs:$rd, IntRegs:$rs2, condVal)>;
// mov<cond> (%icc|%xcc), simm11, rd
def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
", $simm11, $rd"),
(movri IntRegs:$rd, i32imm:$simm11, condVal)>;
// fmovs<cond> (%icc|%xcc), $rs2, $rd
def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg),
", $rs2, $rd"),
(fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>;
// fmovd<cond> (%icc|%xcc), $rs2, $rd
def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg),
", $rs2, $rd"),
(fmovd DFPRegs:$rd, DFPRegs:$rs2, condVal)>;
}
// mov<cond> <ccreg> rs2, rd
multiclass fpcond_mov_alias<string cond, int condVal,
Instruction movrr, Instruction movri,
Instruction fmovs, Instruction fmovd> {
// mov<cond> %fcc[0-3], rs2, rd
def : InstAlias<!strconcat(!strconcat("mov", cond), " $cc, $rs2, $rd"),
(movrr IntRegs:$rd, FCCRegs:$cc, IntRegs:$rs2, condVal)>;
// mov<cond> %fcc[0-3], simm11, rd
def : InstAlias<!strconcat(!strconcat("mov", cond), " $cc, $simm11, $rd"),
(movri IntRegs:$rd, FCCRegs:$cc, i32imm:$simm11, condVal)>;
// fmovs<cond> %fcc[0-3], $rs2, $rd
def : InstAlias<!strconcat(!strconcat("fmovs", cond), " $cc, $rs2, $rd"),
(fmovs FPRegs:$rd, FCCRegs:$cc, FPRegs:$rs2, condVal)>;
// fmovd<cond> %fcc[0-3], $rs2, $rd
def : InstAlias<!strconcat(!strconcat("fmovd", cond), " $cc, $rs2, $rd"),
(fmovd DFPRegs:$rd, FCCRegs:$cc, DFPRegs:$rs2, condVal)>;
}
// Instruction aliases for integer conditional branches and moves.
multiclass int_cond_alias<string cond, int condVal> {
// b<cond> $imm
def : InstAlias<!strconcat(!strconcat("b", cond), " $imm"),
(BCOND brtarget:$imm, condVal)>;
// b<cond>,a $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a $imm"),
(BCONDA brtarget:$imm, condVal)>;
// b<cond> %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), " %icc, $imm"),
(BPICC brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond>,pt %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",pt %icc, $imm"),
(BPICC brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond>,a %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a %icc, $imm"),
(BPICCA brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond>,a,pt %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pt %icc, $imm"),
(BPICCA brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond>,pn %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",pn %icc, $imm"),
(BPICCNT brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond>,a,pn %icc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pn %icc, $imm"),
(BPICCANT brtarget:$imm, condVal)>, Requires<[HasV9]>;
// b<cond> %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"),
(BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
// b<cond>,pt %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",pt %xcc, $imm"),
(BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
// b<cond>,a %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a %xcc, $imm"),
(BPXCCA brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
// b<cond>,a,pt %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pt %xcc, $imm"),
(BPXCCA brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
// b<cond>,pn %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",pn %xcc, $imm"),
(BPXCCNT brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
// b<cond>,a,pn %xcc, $imm
def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pn %xcc, $imm"),
(BPXCCANT brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
defm : intcond_mov_alias<cond, condVal, " %icc",
MOVICCrr, MOVICCri,
FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>;
defm : intcond_mov_alias<cond, condVal, " %xcc",
MOVXCCrr, MOVXCCri,
FMOVS_XCC, FMOVD_XCC>, Requires<[Is64Bit]>;
// fmovq<cond> (%icc|%xcc), $rs2, $rd
def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %icc, $rs2, $rd"),
(FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
Requires<[HasV9, HasHardQuad]>;
def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %xcc, $rs2, $rd"),
(FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
Requires<[Is64Bit, HasHardQuad]>;
// t<cond> %icc, rs1 + rs2
def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $rs2"),
(TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>,
Requires<[HasV9]>;
// t<cond> %icc, rs => t<cond> %icc, G0 + rs
def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs2"),
(TICCrr G0, IntRegs:$rs2, condVal)>,
Requires<[HasV9]>;
// t<cond> %xcc, rs1 + rs2
def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $rs2"),
(TXCCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>,
Requires<[HasV9]>;
// t<cond> %xcc, rs => t<cond> %xcc, G0 + rs
def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs2"),
(TXCCrr G0, IntRegs:$rs2, condVal)>,
Requires<[HasV9]>;
// t<cond> rs1 + rs2 => t<cond> %icc, rs1 + rs2
def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"),
(TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>;
// t<cond> rs=> t<cond> %icc, G0 + rs2
def : InstAlias<!strconcat(!strconcat("t", cond), " $rs2"),
(TICCrr G0, IntRegs:$rs2, condVal)>;
// t<cond> %icc, rs1 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $imm"),
(TICCri IntRegs:$rs1, i32imm:$imm, condVal)>,
Requires<[HasV9]>;
// t<cond> %icc, imm => t<cond> %icc, G0 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $imm"),
(TICCri G0, i32imm:$imm, condVal)>,
Requires<[HasV9]>;
// t<cond> %xcc, rs1 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $imm"),
(TXCCri IntRegs:$rs1, i32imm:$imm, condVal)>,
Requires<[HasV9]>;
// t<cond> %xcc, imm => t<cond> %xcc, G0 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $imm"),
(TXCCri G0, i32imm:$imm, condVal)>,
Requires<[HasV9]>;
// t<cond> rs1 + imm => t<cond> %icc, rs1 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $imm"),
(TICCri IntRegs:$rs1, i32imm:$imm, condVal)>;
// t<cond> imm => t<cond> %icc, G0 + imm
def : InstAlias<!strconcat(!strconcat("t", cond), " $imm"),
(TICCri G0, i32imm:$imm, condVal)>;
}
// Instruction aliases for floating point conditional branches and moves.
multiclass fp_cond_alias<string cond, int condVal> {
// fb<cond> $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), " $imm"),
(FBCOND brtarget:$imm, condVal), 0>;
// fb<cond>,a $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",a $imm"),
(FBCONDA brtarget:$imm, condVal), 0>;
// fb<cond> %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), " $cc, $imm"),
(BPFCC brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
// fb<cond>,pt %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",pt $cc, $imm"),
(BPFCC brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
// fb<cond>,a %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",a $cc, $imm"),
(BPFCCA brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
// fb<cond>,a,pt %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",a,pt $cc, $imm"),
(BPFCCA brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
// fb<cond>,pn %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",pn $cc, $imm"),
(BPFCCNT brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
// fb<cond>,a,pn %fcc0, $imm
def : InstAlias<!strconcat(!strconcat("fb", cond), ",a,pn $cc, $imm"),
(BPFCCANT brtarget:$imm, condVal, FCCRegs:$cc)>,
Requires<[HasV9]>;
defm : fpcond_mov_alias<cond, condVal,
V9MOVFCCrr, V9MOVFCCri,
V9FMOVS_FCC, V9FMOVD_FCC>, Requires<[HasV9]>;
// fmovq<cond> %fcc0, $rs2, $rd
def : InstAlias<!strconcat(!strconcat("fmovq", cond), " $cc, $rs2, $rd"),
(V9FMOVQ_FCC QFPRegs:$rd, FCCRegs:$cc, QFPRegs:$rs2,
condVal)>,
Requires<[HasV9, HasHardQuad]>;
}
defm : int_cond_alias<"a", 0b1000>;
defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual
defm : int_cond_alias<"n", 0b0000>;
defm : int_cond_alias<"ne", 0b1001>;
defm : int_cond_alias<"nz", 0b1001>; // same as ne
defm : int_cond_alias<"e", 0b0001>;
defm : int_cond_alias<"z", 0b0001>; // same as e
defm : int_cond_alias<"g", 0b1010>;
defm : int_cond_alias<"le", 0b0010>;
defm : int_cond_alias<"ge", 0b1011>;
defm : int_cond_alias<"l", 0b0011>;
defm : int_cond_alias<"gu", 0b1100>;
defm : int_cond_alias<"leu", 0b0100>;
defm : int_cond_alias<"cc", 0b1101>;
defm : int_cond_alias<"geu", 0b1101>; // same as cc
defm : int_cond_alias<"cs", 0b0101>;
defm : int_cond_alias<"lu", 0b0101>; // same as cs
defm : int_cond_alias<"pos", 0b1110>;
defm : int_cond_alias<"neg", 0b0110>;
defm : int_cond_alias<"vc", 0b1111>;
defm : int_cond_alias<"vs", 0b0111>;
defm : fp_cond_alias<"a", 0b0000>;
defm : fp_cond_alias<"", 0b0000>; // same as a; gnu asm, not in manual
defm : fp_cond_alias<"n", 0b1000>;
defm : fp_cond_alias<"u", 0b0111>;
defm : fp_cond_alias<"g", 0b0110>;
defm : fp_cond_alias<"ug", 0b0101>;
defm : fp_cond_alias<"l", 0b0100>;
defm : fp_cond_alias<"ul", 0b0011>;
defm : fp_cond_alias<"lg", 0b0010>;
defm : fp_cond_alias<"ne", 0b0001>;
defm : fp_cond_alias<"nz", 0b0001>; // same as ne
defm : fp_cond_alias<"e", 0b1001>;
defm : fp_cond_alias<"z", 0b1001>; // same as e
defm : fp_cond_alias<"ue", 0b1010>;
defm : fp_cond_alias<"ge", 0b1011>;
defm : fp_cond_alias<"uge", 0b1100>;
defm : fp_cond_alias<"le", 0b1101>;
defm : fp_cond_alias<"ule", 0b1110>;
defm : fp_cond_alias<"o", 0b1111>;
// Section A.3 Synthetic Instructions
// Most are marked as Emit=0, so that they are not used for disassembly. This is
// an aesthetic issue, but the chosen policy is to typically prefer using the
// non-alias form, except for the most obvious and clarifying aliases: cmp, jmp,
// call, tst, ret, retl.
// Note: cmp is handled in Mos6502InstrInfo.
// jmp/call/ret/retl have special case handling for output in
// Mos6502InstPrinter.cpp
// jmp addr -> jmpl addr, %g0
def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr), 0>;
def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr), 0>;
// call addr -> jmpl addr, %o7
def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr), 0>;
def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr), 0>;
// tst reg -> orcc %g0, reg, %g0
def : InstAlias<"tst $rs2", (ORCCrr G0, IntRegs:$rs2, G0)>;
// ret -> jmpl %i7+8, %g0 (aka RET 8)
def : InstAlias<"ret", (RET 8)>;
// retl -> jmpl %o7+8, %g0 (aka RETL 8)
def : InstAlias<"retl", (RETL 8)>;
// restore -> restore %g0, %g0, %g0
def : InstAlias<"restore", (RESTORErr G0, G0, G0)>;
// save -> restore %g0, %g0, %g0
def : InstAlias<"save", (SAVErr G0, G0, G0)>;
// set value, rd
// (turns into a sequence of sethi+or, depending on the value)
// def : InstAlias<"set $val, $rd", (ORri IntRegs:$rd, (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>;
def SET : AsmPseudoInst<(outs IntRegs:$rd), (ins i32imm:$val), "set $val, $rd">;
// not rd -> xnor rd, %g0, rd
def : InstAlias<"not $rd", (XNORrr IntRegs:$rd, IntRegs:$rd, G0), 0>;
// not reg, rd -> xnor reg, %g0, rd
def : InstAlias<"not $rs1, $rd", (XNORrr IntRegs:$rd, IntRegs:$rs1, G0), 0>;
// neg rd -> sub %g0, rd, rd
def : InstAlias<"neg $rd", (SUBrr IntRegs:$rd, G0, IntRegs:$rd), 0>;
// neg reg, rd -> sub %g0, reg, rd
def : InstAlias<"neg $rs2, $rd", (SUBrr IntRegs:$rd, G0, IntRegs:$rs2), 0>;
// inc rd -> add rd, 1, rd
def : InstAlias<"inc $rd", (ADDri IntRegs:$rd, IntRegs:$rd, 1), 0>;
// inc simm13, rd -> add rd, simm13, rd
def : InstAlias<"inc $simm13, $rd", (ADDri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// inccc rd -> addcc rd, 1, rd
def : InstAlias<"inccc $rd", (ADDCCri IntRegs:$rd, IntRegs:$rd, 1), 0>;
// inccc simm13, rd -> addcc rd, simm13, rd
def : InstAlias<"inccc $simm13, $rd", (ADDCCri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// dec rd -> sub rd, 1, rd
def : InstAlias<"dec $rd", (SUBri IntRegs:$rd, IntRegs:$rd, 1), 0>;
// dec simm13, rd -> sub rd, simm13, rd
def : InstAlias<"dec $simm13, $rd", (SUBri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// deccc rd -> subcc rd, 1, rd
def : InstAlias<"deccc $rd", (SUBCCri IntRegs:$rd, IntRegs:$rd, 1), 0>;
// deccc simm13, rd -> subcc rd, simm13, rd
def : InstAlias<"deccc $simm13, $rd", (SUBCCri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// btst reg_or_imm, reg -> andcc reg,reg_or_imm,%g0
def : InstAlias<"btst $rs2, $rs1", (ANDCCrr G0, IntRegs:$rs1, IntRegs:$rs2), 0>;
def : InstAlias<"btst $simm13, $rs1", (ANDCCri G0, IntRegs:$rs1, i32imm:$simm13), 0>;
// bset reg_or_imm, rd -> or rd,reg_or_imm,rd
def : InstAlias<"bset $rs2, $rd", (ORrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>;
def : InstAlias<"bset $simm13, $rd", (ORri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// bclr reg_or_imm, rd -> andn rd,reg_or_imm,rd
def : InstAlias<"bclr $rs2, $rd", (ANDNrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>;
def : InstAlias<"bclr $simm13, $rd", (ANDNri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// btog reg_or_imm, rd -> xor rd,reg_or_imm,rd
def : InstAlias<"btog $rs2, $rd", (XORrr IntRegs:$rd, IntRegs:$rd, IntRegs:$rs2), 0>;
def : InstAlias<"btog $simm13, $rd", (XORri IntRegs:$rd, IntRegs:$rd, i32imm:$simm13), 0>;
// clr rd -> or %g0, %g0, rd
def : InstAlias<"clr $rd", (ORrr IntRegs:$rd, G0, G0), 0>;
// clr{b,h,} [addr] -> st{b,h,} %g0, [addr]
def : InstAlias<"clrb [$addr]", (STBrr MEMrr:$addr, G0), 0>;
def : InstAlias<"clrb [$addr]", (STBri MEMri:$addr, G0), 0>;
def : InstAlias<"clrh [$addr]", (STHrr MEMrr:$addr, G0), 0>;
def : InstAlias<"clrh [$addr]", (STHri MEMri:$addr, G0), 0>;
def : InstAlias<"clr [$addr]", (STrr MEMrr:$addr, G0), 0>;
def : InstAlias<"clr [$addr]", (STri MEMri:$addr, G0), 0>;
// mov reg_or_imm, rd -> or %g0, reg_or_imm, rd
def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>;
def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>;
// mov specialreg, rd -> rd specialreg, rd
def : InstAlias<"mov $asr, $rd", (RDASR IntRegs:$rd, ASRRegs:$asr), 0>;
def : InstAlias<"mov %psr, $rd", (RDPSR IntRegs:$rd), 0>;
def : InstAlias<"mov %wim, $rd", (RDWIM IntRegs:$rd), 0>;
def : InstAlias<"mov %tbr, $rd", (RDTBR IntRegs:$rd), 0>;
// mov reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg
def : InstAlias<"mov $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>;
def : InstAlias<"mov $simm13, $asr", (WRASRri ASRRegs:$asr, G0, i32imm:$simm13), 0>;
def : InstAlias<"mov $rs2, %psr", (WRPSRrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"mov $simm13, %psr", (WRPSRri G0, i32imm:$simm13), 0>;
def : InstAlias<"mov $rs2, %wim", (WRWIMrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"mov $simm13, %wim", (WRWIMri G0, i32imm:$simm13), 0>;
def : InstAlias<"mov $rs2, %tbr", (WRTBRrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"mov $simm13, %tbr", (WRTBRri G0, i32imm:$simm13), 0>;
// End of Section A.3
// wr reg_or_imm, specialreg -> wr %g0, reg_or_imm, specialreg
// (aka: omit the first arg when it's g0. This is not in the manual, but is
// supported by gnu and solaris as)
def : InstAlias<"wr $rs2, $asr", (WRASRrr ASRRegs:$asr, G0, IntRegs:$rs2), 0>;
def : InstAlias<"wr $simm13, $asr", (WRASRri ASRRegs:$asr, G0, i32imm:$simm13), 0>;
def : InstAlias<"wr $rs2, %psr", (WRPSRrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"wr $simm13, %psr", (WRPSRri G0, i32imm:$simm13), 0>;
def : InstAlias<"wr $rs2, %wim", (WRWIMrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"wr $simm13, %wim", (WRWIMri G0, i32imm:$simm13), 0>;
def : InstAlias<"wr $rs2, %tbr", (WRTBRrr G0, IntRegs:$rs2), 0>;
def : InstAlias<"wr $simm13, %tbr", (WRTBRri G0, i32imm:$simm13), 0>;
// flush -> flush %g0
def : InstAlias<"flush", (FLUSH), 0>;
def : MnemonicAlias<"return", "rett">, Requires<[HasV9]>;
def : MnemonicAlias<"addc", "addx">, Requires<[HasV9]>;
def : MnemonicAlias<"addccc", "addxcc">, Requires<[HasV9]>;
def : MnemonicAlias<"subc", "subx">, Requires<[HasV9]>;
def : MnemonicAlias<"subccc", "subxcc">, Requires<[HasV9]>;
def : InstAlias<"fcmps $rs1, $rs2", (V9FCMPS FCC0, FPRegs:$rs1, FPRegs:$rs2)>;
def : InstAlias<"fcmpd $rs1, $rs2", (V9FCMPD FCC0, DFPRegs:$rs1, DFPRegs:$rs2)>;
def : InstAlias<"fcmpq $rs1, $rs2", (V9FCMPQ FCC0, QFPRegs:$rs1, QFPRegs:$rs2)>,
Requires<[HasHardQuad]>;
def : InstAlias<"fcmpes $rs1, $rs2", (V9FCMPES FCC0, FPRegs:$rs1, FPRegs:$rs2)>;
def : InstAlias<"fcmped $rs1, $rs2", (V9FCMPED FCC0, DFPRegs:$rs1,
DFPRegs:$rs2)>;
def : InstAlias<"fcmpeq $rs1, $rs2", (V9FCMPEQ FCC0, QFPRegs:$rs1,
QFPRegs:$rs2)>,
Requires<[HasHardQuad]>;

View File

@ -0,0 +1,341 @@
//===-- Mos6502InstrFormats.td - Mos6502 Instruction Formats ---*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern>
: Instruction {
field bits<32> Inst;
let Namespace = "SP";
let Size = 4;
bits<2> op;
let Inst{31-30} = op; // Top two bits are the 'op' field
dag OutOperandList = outs;
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
let DecoderNamespace = "Mos6502";
field bits<32> SoftFail = 0;
}
//===----------------------------------------------------------------------===//
// Format #2 instruction classes in the Mos6502
//===----------------------------------------------------------------------===//
// Format 2 instructions
class F2<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern> {
bits<3> op2;
bits<22> imm22;
let op = 0; // op = 0
let Inst{24-22} = op2;
let Inst{21-0} = imm22;
}
// Specific F2 classes: Mos6502V8 manual, page 44
//
class F2_1<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern>
: F2<outs, ins, asmstr, pattern> {
bits<5> rd;
let op2 = op2Val;
let Inst{29-25} = rd;
}
class F2_2<bits<3> op2Val, bit annul, dag outs, dag ins, string asmstr,
list<dag> pattern> : F2<outs, ins, asmstr, pattern> {
bits<4> cond;
let op2 = op2Val;
let Inst{29} = annul;
let Inst{28-25} = cond;
}
class F2_3<bits<3> op2Val, bit annul, bit pred,
dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern> {
bits<2> cc;
bits<4> cond;
bits<19> imm19;
let op = 0; // op = 0
let Inst{29} = annul;
let Inst{28-25} = cond;
let Inst{24-22} = op2Val;
let Inst{21-20} = cc;
let Inst{19} = pred;
let Inst{18-0} = imm19;
}
class F2_4<bits<3> cond, bit annul, bit pred,
dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern> {
bits<16> imm16;
bits<5> rs1;
let op = 0; // op = 0
let Inst{29} = annul;
let Inst{28} = 0;
let Inst{27-25} = cond;
let Inst{24-22} = 0b011;
let Inst{21-20} = imm16{15-14};
let Inst{19} = pred;
let Inst{18-14} = rs1;
let Inst{13-0} = imm16{13-0};
}
//===----------------------------------------------------------------------===//
// Format #3 instruction classes in the Mos6502
//===----------------------------------------------------------------------===//
class F3<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern> {
bits<5> rd;
bits<6> op3;
bits<5> rs1;
let op{1} = 1; // Op = 2 or 3
let Inst{29-25} = rd;
let Inst{24-19} = op3;
let Inst{18-14} = rs1;
}
// Specific F3 classes: Mos6502V8 manual, page 44
//
class F3_1_asi<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<8> asi;
bits<5> rs2;
let op = opVal;
let op3 = op3val;
let Inst{13} = 0; // i field = 0
let Inst{12-5} = asi; // address space identifier
let Inst{4-0} = rs2;
}
class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr,
list<dag> pattern> : F3_1_asi<opVal, op3val, outs, ins,
asmstr, pattern> {
let asi = 0;
}
class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<13> simm13;
let op = opVal;
let op3 = op3val;
let Inst{13} = 1; // i field = 1
let Inst{12-0} = simm13;
}
// floating-point
class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<5> rs2;
let op = opVal;
let op3 = op3val;
let Inst{13-5} = opfval; // fp opcode
let Inst{4-0} = rs2;
}
// floating-point unary operations.
class F3_3u<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<5> rs2;
let op = opVal;
let op3 = op3val;
let rs1 = 0;
let Inst{13-5} = opfval; // fp opcode
let Inst{4-0} = rs2;
}
// floating-point compares.
class F3_3c<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bits<5> rs2;
let op = opVal;
let op3 = op3val;
let Inst{13-5} = opfval; // fp opcode
let Inst{4-0} = rs2;
}
// Shift by register rs2.
class F3_Sr<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bit x = xVal; // 1 for 64-bit shifts.
bits<5> rs2;
let op = opVal;
let op3 = op3val;
let Inst{13} = 0; // i field = 0
let Inst{12} = x; // extended registers.
let Inst{4-0} = rs2;
}
// Shift by immediate.
class F3_Si<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins,
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
bit x = xVal; // 1 for 64-bit shifts.
bits<6> shcnt; // shcnt32 / shcnt64.
let op = opVal;
let op3 = op3val;
let Inst{13} = 1; // i field = 1
let Inst{12} = x; // extended registers.
let Inst{5-0} = shcnt;
}
// Define rr and ri shift instructions with patterns.
multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode,
ValueType VT, RegisterClass RC> {
def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2),
!strconcat(OpcStr, " $rs1, $rs2, $rd"),
[(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))]>;
def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt),
!strconcat(OpcStr, " $rs1, $shcnt, $rd"),
[(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))]>;
}
class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern>
: InstSP<outs, ins, asmstr, pattern> {
bits<5> rd;
let op = 2;
let Inst{29-25} = rd;
let Inst{24-19} = op3;
}
class F4_1<bits<6> op3, dag outs, dag ins,
string asmstr, list<dag> pattern>
: F4<op3, outs, ins, asmstr, pattern> {
bit intcc;
bits<2> cc;
bits<4> cond;
bits<5> rs2;
let Inst{4-0} = rs2;
let Inst{12-11} = cc;
let Inst{13} = 0;
let Inst{17-14} = cond;
let Inst{18} = intcc;
}
class F4_2<bits<6> op3, dag outs, dag ins,
string asmstr, list<dag> pattern>
: F4<op3, outs, ins, asmstr, pattern> {
bit intcc;
bits<2> cc;
bits<4> cond;
bits<11> simm11;
let Inst{10-0} = simm11;
let Inst{12-11} = cc;
let Inst{13} = 1;
let Inst{17-14} = cond;
let Inst{18} = intcc;
}
class F4_3<bits<6> op3, bits<6> opf_low, dag outs, dag ins,
string asmstr, list<dag> pattern>
: F4<op3, outs, ins, asmstr, pattern> {
bits<4> cond;
bit intcc;
bits<2> opf_cc;
bits<5> rs2;
let Inst{18} = 0;
let Inst{17-14} = cond;
let Inst{13} = intcc;
let Inst{12-11} = opf_cc;
let Inst{10-5} = opf_low;
let Inst{4-0} = rs2;
}
class F4_4r<bits<6> op3, bits<5> opf_low, bits<3> rcond, dag outs, dag ins,
string asmstr, list<dag> pattern>
: F4<op3, outs, ins, asmstr, pattern> {
bits <5> rs1;
bits <5> rs2;
let Inst{18-14} = rs1;
let Inst{13} = 0; // IsImm
let Inst{12-10} = rcond;
let Inst{9-5} = opf_low;
let Inst{4-0} = rs2;
}
class F4_4i<bits<6> op3, bits<3> rcond, dag outs, dag ins,
string asmstr, list<dag> pattern>
: F4<op3, outs, ins, asmstr, pattern> {
bits<5> rs1;
bits<10> simm10;
let Inst{18-14} = rs1;
let Inst{13} = 1; // IsImm
let Inst{12-10} = rcond;
let Inst{9-0} = simm10;
}
class TRAPSP<bits<6> op3Val, bit isimm, dag outs, dag ins, string asmstr,
list<dag> pattern>: F3<outs, ins, asmstr, pattern> {
bits<4> cond;
bits<2> cc;
let op = 0b10;
let rd{4} = 0;
let rd{3-0} = cond;
let op3 = op3Val;
let Inst{13} = isimm;
let Inst{12-11} = cc;
}
class TRAPSPrr<bits<6> op3Val, dag outs, dag ins, string asmstr,
list<dag> pattern>: TRAPSP<op3Val, 0, outs, ins, asmstr, pattern> {
bits<5> rs2;
let Inst{10-5} = 0;
let Inst{4-0} = rs2;
}
class TRAPSPri<bits<6> op3Val, dag outs, dag ins, string asmstr,
list<dag> pattern>: TRAPSP<op3Val, 1, outs, ins, asmstr, pattern> {
bits<8> imm;
let Inst{10-8} = 0;
let Inst{7-0} = imm;
}
// Pseudo-instructions for alternate assembly syntax (never used by codegen).
// These are aliases that require C++ handling to convert to the target
// instruction, while InstAliases can be handled directly by tblgen.
class AsmPseudoInst<dag outs, dag ins, string asm>
: InstSP<outs, ins, asm, []> {
let isPseudo = 1;
}

View File

@ -0,0 +1,454 @@
//===-- Mos6502InstrInfo.cpp - Mos6502 Instruction Information ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mos6502 implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#include "Mos6502InstrInfo.h"
#include "Mos6502.h"
#include "Mos6502MachineFunctionInfo.h"
#include "Mos6502Subtarget.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
#define GET_INSTRINFO_CTOR_DTOR
#include "Mos6502GenInstrInfo.inc"
// Pin the vtable to this file.
void Mos6502InstrInfo::anchor() {}
Mos6502InstrInfo::Mos6502InstrInfo(Mos6502Subtarget &ST)
: Mos6502GenInstrInfo(SP::ADJCALLSTACKDOWN, SP::ADJCALLSTACKUP), RI(),
Subtarget(ST) {}
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned Mos6502InstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
if (MI->getOpcode() == SP::LDri ||
MI->getOpcode() == SP::LDXri ||
MI->getOpcode() == SP::LDFri ||
MI->getOpcode() == SP::LDDFri ||
MI->getOpcode() == SP::LDQFri) {
if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() &&
MI->getOperand(2).getImm() == 0) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
}
return 0;
}
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned Mos6502InstrInfo::isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
if (MI->getOpcode() == SP::STri ||
MI->getOpcode() == SP::STXri ||
MI->getOpcode() == SP::STFri ||
MI->getOpcode() == SP::STDFri ||
MI->getOpcode() == SP::STQFri) {
if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() &&
MI->getOperand(1).getImm() == 0) {
FrameIndex = MI->getOperand(0).getIndex();
return MI->getOperand(2).getReg();
}
}
return 0;
}
static bool IsIntegerCC(unsigned CC)
{
return (CC <= SPCC::ICC_VC);
}
static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC)
{
switch(CC) {
case SPCC::ICC_A: return SPCC::ICC_N;
case SPCC::ICC_N: return SPCC::ICC_A;
case SPCC::ICC_NE: return SPCC::ICC_E;
case SPCC::ICC_E: return SPCC::ICC_NE;
case SPCC::ICC_G: return SPCC::ICC_LE;
case SPCC::ICC_LE: return SPCC::ICC_G;
case SPCC::ICC_GE: return SPCC::ICC_L;
case SPCC::ICC_L: return SPCC::ICC_GE;
case SPCC::ICC_GU: return SPCC::ICC_LEU;
case SPCC::ICC_LEU: return SPCC::ICC_GU;
case SPCC::ICC_CC: return SPCC::ICC_CS;
case SPCC::ICC_CS: return SPCC::ICC_CC;
case SPCC::ICC_POS: return SPCC::ICC_NEG;
case SPCC::ICC_NEG: return SPCC::ICC_POS;
case SPCC::ICC_VC: return SPCC::ICC_VS;
case SPCC::ICC_VS: return SPCC::ICC_VC;
case SPCC::FCC_A: return SPCC::FCC_N;
case SPCC::FCC_N: return SPCC::FCC_A;
case SPCC::FCC_U: return SPCC::FCC_O;
case SPCC::FCC_O: return SPCC::FCC_U;
case SPCC::FCC_G: return SPCC::FCC_ULE;
case SPCC::FCC_LE: return SPCC::FCC_UG;
case SPCC::FCC_UG: return SPCC::FCC_LE;
case SPCC::FCC_ULE: return SPCC::FCC_G;
case SPCC::FCC_L: return SPCC::FCC_UGE;
case SPCC::FCC_GE: return SPCC::FCC_UL;
case SPCC::FCC_UL: return SPCC::FCC_GE;
case SPCC::FCC_UGE: return SPCC::FCC_L;
case SPCC::FCC_LG: return SPCC::FCC_UE;
case SPCC::FCC_UE: return SPCC::FCC_LG;
case SPCC::FCC_NE: return SPCC::FCC_E;
case SPCC::FCC_E: return SPCC::FCC_NE;
}
llvm_unreachable("Invalid cond code");
}
bool Mos6502InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const
{
MachineBasicBlock::iterator I = MBB.end();
MachineBasicBlock::iterator UnCondBrIter = MBB.end();
while (I != MBB.begin()) {
--I;
if (I->isDebugValue())
continue;
// When we see a non-terminator, we are done.
if (!isUnpredicatedTerminator(I))
break;
// Terminator is not a branch.
if (!I->isBranch())
return true;
// Handle Unconditional branches.
if (I->getOpcode() == SP::BA) {
UnCondBrIter = I;
if (!AllowModify) {
TBB = I->getOperand(0).getMBB();
continue;
}
while (std::next(I) != MBB.end())
std::next(I)->eraseFromParent();
Cond.clear();
FBB = nullptr;
if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
TBB = nullptr;
I->eraseFromParent();
I = MBB.end();
UnCondBrIter = MBB.end();
continue;
}
TBB = I->getOperand(0).getMBB();
continue;
}
unsigned Opcode = I->getOpcode();
if (Opcode != SP::BCOND && Opcode != SP::FBCOND)
return true; // Unknown Opcode.
SPCC::CondCodes BranchCode = (SPCC::CondCodes)I->getOperand(1).getImm();
if (Cond.empty()) {
MachineBasicBlock *TargetBB = I->getOperand(0).getMBB();
if (AllowModify && UnCondBrIter != MBB.end() &&
MBB.isLayoutSuccessor(TargetBB)) {
// Transform the code
//
// brCC L1
// ba L2
// L1:
// ..
// L2:
//
// into
//
// brnCC L2
// L1:
// ...
// L2:
//
BranchCode = GetOppositeBranchCondition(BranchCode);
MachineBasicBlock::iterator OldInst = I;
BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(Opcode))
.addMBB(UnCondBrIter->getOperand(0).getMBB()).addImm(BranchCode);
BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(SP::BA))
.addMBB(TargetBB);
OldInst->eraseFromParent();
UnCondBrIter->eraseFromParent();
UnCondBrIter = MBB.end();
I = MBB.end();
continue;
}
FBB = TBB;
TBB = I->getOperand(0).getMBB();
Cond.push_back(MachineOperand::CreateImm(BranchCode));
continue;
}
// FIXME: Handle subsequent conditional branches.
// For now, we can't handle multiple conditional branches.
return true;
}
return false;
}
unsigned
Mos6502InstrInfo::InsertBranch(MachineBasicBlock &MBB,MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
ArrayRef<MachineOperand> Cond,
DebugLoc DL) const {
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
assert((Cond.size() == 1 || Cond.size() == 0) &&
"Mos6502 branch conditions should have one component!");
if (Cond.empty()) {
assert(!FBB && "Unconditional branch with multiple successors!");
BuildMI(&MBB, DL, get(SP::BA)).addMBB(TBB);
return 1;
}
// Conditional branch
unsigned CC = Cond[0].getImm();
if (IsIntegerCC(CC))
BuildMI(&MBB, DL, get(SP::BCOND)).addMBB(TBB).addImm(CC);
else
BuildMI(&MBB, DL, get(SP::FBCOND)).addMBB(TBB).addImm(CC);
if (!FBB)
return 1;
BuildMI(&MBB, DL, get(SP::BA)).addMBB(FBB);
return 2;
}
unsigned Mos6502InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const
{
MachineBasicBlock::iterator I = MBB.end();
unsigned Count = 0;
while (I != MBB.begin()) {
--I;
if (I->isDebugValue())
continue;
if (I->getOpcode() != SP::BA
&& I->getOpcode() != SP::BCOND
&& I->getOpcode() != SP::FBCOND)
break; // Not a branch
I->eraseFromParent();
I = MBB.end();
++Count;
}
return Count;
}
void Mos6502InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, DebugLoc DL,
unsigned DestReg, unsigned SrcReg,
bool KillSrc) const {
unsigned numSubRegs = 0;
unsigned movOpc = 0;
const unsigned *subRegIdx = nullptr;
const unsigned DFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd };
const unsigned QFP_DFP_SubRegsIdx[] = { SP::sub_even64, SP::sub_odd64 };
const unsigned QFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd,
SP::sub_odd64_then_sub_even,
SP::sub_odd64_then_sub_odd };
if (SP::IntRegsRegClass.contains(DestReg, SrcReg))
BuildMI(MBB, I, DL, get(SP::ORrr), DestReg).addReg(SP::G0)
.addReg(SrcReg, getKillRegState(KillSrc));
else if (SP::FPRegsRegClass.contains(DestReg, SrcReg))
BuildMI(MBB, I, DL, get(SP::FMOVS), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
else if (SP::DFPRegsRegClass.contains(DestReg, SrcReg)) {
if (Subtarget.isV9()) {
BuildMI(MBB, I, DL, get(SP::FMOVD), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
} else {
// Use two FMOVS instructions.
subRegIdx = DFP_FP_SubRegsIdx;
numSubRegs = 2;
movOpc = SP::FMOVS;
}
} else if (SP::QFPRegsRegClass.contains(DestReg, SrcReg)) {
if (Subtarget.isV9()) {
if (Subtarget.hasHardQuad()) {
BuildMI(MBB, I, DL, get(SP::FMOVQ), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
} else {
// Use two FMOVD instructions.
subRegIdx = QFP_DFP_SubRegsIdx;
numSubRegs = 2;
movOpc = SP::FMOVD;
}
} else {
// Use four FMOVS instructions.
subRegIdx = QFP_FP_SubRegsIdx;
numSubRegs = 4;
movOpc = SP::FMOVS;
}
} else if (SP::ASRRegsRegClass.contains(DestReg) &&
SP::IntRegsRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(SP::WRASRrr), DestReg)
.addReg(SP::G0)
.addReg(SrcReg, getKillRegState(KillSrc));
} else if (SP::IntRegsRegClass.contains(DestReg) &&
SP::ASRRegsRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(SP::RDASR), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
} else
llvm_unreachable("Impossible reg-to-reg copy");
if (numSubRegs == 0 || subRegIdx == nullptr || movOpc == 0)
return;
const TargetRegisterInfo *TRI = &getRegisterInfo();
MachineInstr *MovMI = nullptr;
for (unsigned i = 0; i != numSubRegs; ++i) {
unsigned Dst = TRI->getSubReg(DestReg, subRegIdx[i]);
unsigned Src = TRI->getSubReg(SrcReg, subRegIdx[i]);
assert(Dst && Src && "Bad sub-register");
MovMI = BuildMI(MBB, I, DL, get(movOpc), Dst).addReg(Src);
}
// Add implicit super-register defs and kills to the last MovMI.
MovMI->addRegisterDefined(DestReg, TRI);
if (KillSrc)
MovMI->addRegisterKilled(SrcReg, TRI);
}
void Mos6502InstrInfo::
storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, bool isKill, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
const MachineFrameInfo &MFI = *MF->getFrameInfo();
MachineMemOperand *MMO =
MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI),
MachineMemOperand::MOStore,
MFI.getObjectSize(FI),
MFI.getObjectAlignment(FI));
// On the order of operands here: think "[FrameIdx + 0] = SrcReg".
if (RC == &SP::I64RegsRegClass)
BuildMI(MBB, I, DL, get(SP::STXri)).addFrameIndex(FI).addImm(0)
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
else if (RC == &SP::IntRegsRegClass)
BuildMI(MBB, I, DL, get(SP::STri)).addFrameIndex(FI).addImm(0)
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
else if (RC == &SP::FPRegsRegClass)
BuildMI(MBB, I, DL, get(SP::STFri)).addFrameIndex(FI).addImm(0)
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
else if (SP::DFPRegsRegClass.hasSubClassEq(RC))
BuildMI(MBB, I, DL, get(SP::STDFri)).addFrameIndex(FI).addImm(0)
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
else if (SP::QFPRegsRegClass.hasSubClassEq(RC))
// Use STQFri irrespective of its legality. If STQ is not legal, it will be
// lowered into two STDs in eliminateFrameIndex.
BuildMI(MBB, I, DL, get(SP::STQFri)).addFrameIndex(FI).addImm(0)
.addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
else
llvm_unreachable("Can't store this register to stack slot");
}
void Mos6502InstrInfo::
loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineFunction *MF = MBB.getParent();
const MachineFrameInfo &MFI = *MF->getFrameInfo();
MachineMemOperand *MMO =
MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI),
MachineMemOperand::MOLoad,
MFI.getObjectSize(FI),
MFI.getObjectAlignment(FI));
if (RC == &SP::I64RegsRegClass)
BuildMI(MBB, I, DL, get(SP::LDXri), DestReg).addFrameIndex(FI).addImm(0)
.addMemOperand(MMO);
else if (RC == &SP::IntRegsRegClass)
BuildMI(MBB, I, DL, get(SP::LDri), DestReg).addFrameIndex(FI).addImm(0)
.addMemOperand(MMO);
else if (RC == &SP::FPRegsRegClass)
BuildMI(MBB, I, DL, get(SP::LDFri), DestReg).addFrameIndex(FI).addImm(0)
.addMemOperand(MMO);
else if (SP::DFPRegsRegClass.hasSubClassEq(RC))
BuildMI(MBB, I, DL, get(SP::LDDFri), DestReg).addFrameIndex(FI).addImm(0)
.addMemOperand(MMO);
else if (SP::QFPRegsRegClass.hasSubClassEq(RC))
// Use LDQFri irrespective of its legality. If LDQ is not legal, it will be
// lowered into two LDDs in eliminateFrameIndex.
BuildMI(MBB, I, DL, get(SP::LDQFri), DestReg).addFrameIndex(FI).addImm(0)
.addMemOperand(MMO);
else
llvm_unreachable("Can't load this register from stack slot");
}
unsigned Mos6502InstrInfo::getGlobalBaseReg(MachineFunction *MF) const
{
Mos6502MachineFunctionInfo *Mos6502FI = MF->getInfo<Mos6502MachineFunctionInfo>();
unsigned GlobalBaseReg = Mos6502FI->getGlobalBaseReg();
if (GlobalBaseReg != 0)
return GlobalBaseReg;
// Insert the set of GlobalBaseReg into the first MBB of the function
MachineBasicBlock &FirstMBB = MF->front();
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
MachineRegisterInfo &RegInfo = MF->getRegInfo();
const TargetRegisterClass *PtrRC =
Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC);
DebugLoc dl;
BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg);
Mos6502FI->setGlobalBaseReg(GlobalBaseReg);
return GlobalBaseReg;
}

View File

@ -0,0 +1,101 @@
//===-- Mos6502InstrInfo.h - Mos6502 Instruction Information --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mos6502 implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502INSTRINFO_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502INSTRINFO_H
#include "Mos6502RegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#define GET_INSTRINFO_HEADER
#include "Mos6502GenInstrInfo.inc"
namespace llvm {
class Mos6502Subtarget;
/// SPII - This namespace holds all of the target specific flags that
/// instruction info tracks.
///
namespace SPII {
enum {
Pseudo = (1<<0),
Load = (1<<1),
Store = (1<<2),
DelaySlot = (1<<3)
};
}
class Mos6502InstrInfo : public Mos6502GenInstrInfo {
const Mos6502RegisterInfo RI;
const Mos6502Subtarget& Subtarget;
virtual void anchor();
public:
explicit Mos6502InstrInfo(Mos6502Subtarget &ST);
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
///
const Mos6502RegisterInfo &getRegisterInfo() const { return RI; }
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const override;
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const override;
bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify = false) const override ;
unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
DebugLoc DL) const override;
void copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, DebugLoc DL,
unsigned DestReg, unsigned SrcReg,
bool KillSrc) const override;
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned SrcReg, bool isKill, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
unsigned getGlobalBaseReg(MachineFunction *MF) const;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
//===---- Mos6502InstrVIS.td - Visual Instruction Set extensions (VIS) -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains instruction formats, definitions and patterns needed for
// VIS, VIS II, VIS II instructions on MOS6502.
//===----------------------------------------------------------------------===//
// VIS Instruction Format.
class VISInstFormat<bits<9> opfval, dag outs, dag ins, string asmstr,
list<dag> pattern>
: F3_3<0b10, 0b110110, opfval, outs, ins, asmstr, pattern>;
class VISInst<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
: VISInstFormat<opfval,
(outs RC:$rd), (ins RC:$rs1, RC:$rs2),
!strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
// VIS Instruction with integer destination register.
class VISInstID<bits<9> opfval, string OpcStr>
: VISInstFormat<opfval,
(outs I64Regs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
!strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
// For VIS Instructions with no operand.
let rd = 0, rs1 = 0, rs2 = 0 in
class VISInst0<bits<9> opfval, string asmstr>
: VISInstFormat<opfval, (outs), (ins), asmstr, []>;
// For VIS Instructions with only rs1, rd operands.
let rs2 = 0 in
class VISInst1<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
: VISInstFormat<opfval,
(outs RC:$rd), (ins RC:$rs1),
!strconcat(OpcStr, " $rs1, $rd"), []>;
// For VIS Instructions with only rs2, rd operands.
let rs1 = 0 in
class VISInst2<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
: VISInstFormat<opfval,
(outs RC:$rd), (ins RC:$rs2),
!strconcat(OpcStr, " $rs2, $rd"), []>;
// For VIS Instructions with only rd operand.
let Constraints = "$rd = $f", rs1 = 0, rs2 = 0 in
class VISInstD<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
: VISInstFormat<opfval,
(outs RC:$rd), (ins RC:$f),
!strconcat(OpcStr, " $rd"), []>;
// VIS 1 Instructions
let Predicates = [HasVIS] in {
def FPADD16 : VISInst<0b001010000, "fpadd16">;
def FPADD16S : VISInst<0b001010001, "fpadd16s">;
def FPADD32 : VISInst<0b001010010, "fpadd32">;
def FPADD32S : VISInst<0b001010011, "fpadd32s">;
def FPSUB16 : VISInst<0b001010100, "fpsub16">;
def FPSUB16S : VISInst<0b001010101, "fpsub16S">;
def FPSUB32 : VISInst<0b001010110, "fpsub32">;
def FPSUB32S : VISInst<0b001010111, "fpsub32S">;
def FPACK16 : VISInst2<0b000111011, "fpack16">;
def FPACK32 : VISInst <0b000111010, "fpack32">;
def FPACKFIX : VISInst2<0b000111101, "fpackfix">;
def FEXPAND : VISInst2<0b001001101, "fexpand">;
def FPMERGE : VISInst <0b001001011, "fpmerge">;
def FMUL8X16 : VISInst<0b000110001, "fmul8x16">;
def FMUL8X16AU : VISInst<0b000110011, "fmul8x16au">;
def FMUL8X16AL : VISInst<0b000110101, "fmul8x16al">;
def FMUL8SUX16 : VISInst<0b000110110, "fmul8sux16">;
def FMUL8ULX16 : VISInst<0b000110111, "fmul8ulx16">;
def FMULD8SUX16 : VISInst<0b000111000, "fmuld8sux16">;
def FMULD8ULX16 : VISInst<0b000111001, "fmuld8ulx16">;
def ALIGNADDR : VISInst<0b000011000, "alignaddr", I64Regs>;
def ALIGNADDRL : VISInst<0b000011010, "alignaddrl", I64Regs>;
def FALIGNADATA : VISInst<0b001001000, "faligndata">;
def FZERO : VISInstD<0b001100000, "fzero">;
def FZEROS : VISInstD<0b001100001, "fzeros", FPRegs>;
def FONE : VISInstD<0b001111110, "fone">;
def FONES : VISInstD<0b001111111, "fones", FPRegs>;
def FSRC1 : VISInst1<0b001110100, "fsrc1">;
def FSRC1S : VISInst1<0b001110101, "fsrc1s", FPRegs>;
def FSRC2 : VISInst2<0b001111000, "fsrc2">;
def FSRC2S : VISInst2<0b001111001, "fsrc2s", FPRegs>;
def FNOT1 : VISInst1<0b001101010, "fnot1">;
def FNOT1S : VISInst1<0b001101011, "fnot1s", FPRegs>;
def FNOT2 : VISInst2<0b001100110, "fnot2">;
def FNOT2S : VISInst2<0b001100111, "fnot2s", FPRegs>;
def FOR : VISInst<0b001111100, "for">;
def FORS : VISInst<0b001111101, "fors", FPRegs>;
def FNOR : VISInst<0b001100010, "fnor">;
def FNORS : VISInst<0b001100011, "fnors", FPRegs>;
def FAND : VISInst<0b001110000, "fand">;
def FANDS : VISInst<0b001110001, "fands", FPRegs>;
def FNAND : VISInst<0b001101110, "fnand">;
def FNANDS : VISInst<0b001101111, "fnands", FPRegs>;
def FXOR : VISInst<0b001101100, "fxor">;
def FXORS : VISInst<0b001101101, "fxors", FPRegs>;
def FXNOR : VISInst<0b001110010, "fxnor">;
def FXNORS : VISInst<0b001110011, "fxnors", FPRegs>;
def FORNOT1 : VISInst<0b001111010, "fornot1">;
def FORNOT1S : VISInst<0b001111011, "fornot1s", FPRegs>;
def FORNOT2 : VISInst<0b001110110, "fornot2">;
def FORNOT2S : VISInst<0b001110111, "fornot2s", FPRegs>;
def FANDNOT1 : VISInst<0b001101000, "fandnot1">;
def FANDNOT1S : VISInst<0b001101001, "fandnot1s", FPRegs>;
def FANDNOT2 : VISInst<0b001100100, "fandnot2">;
def FANDNOT2S : VISInst<0b001100101, "fandnot2s", FPRegs>;
def FCMPGT16 : VISInstID<0b000101000, "fcmpgt16">;
def FCMPGT32 : VISInstID<0b000101100, "fcmpgt32">;
def FCMPLE16 : VISInstID<0b000100000, "fcmple16">;
def FCMPLE32 : VISInstID<0b000100100, "fcmple32">;
def FCMPNE16 : VISInstID<0b000100010, "fcmpne16">;
def FCMPNE32 : VISInstID<0b000100110, "fcmpne32">;
def FCMPEQ16 : VISInstID<0b000101010, "fcmpeq16">;
def FCMPEQ32 : VISInstID<0b000101110, "fcmpeq32">;
def EDGE8 : VISInst<0b000000000, "edge8", I64Regs>;
def EDGE8L : VISInst<0b000000010, "edge8l", I64Regs>;
def EDGE16 : VISInst<0b000000100, "edge16", I64Regs>;
def EDGE16L : VISInst<0b000000110, "edge16l", I64Regs>;
def EDGE32 : VISInst<0b000001000, "edge32", I64Regs>;
def EDGE32L : VISInst<0b000001010, "edge32l", I64Regs>;
def PDIST : VISInst<0b000111110, "pdist">;
def ARRAY8 : VISInst<0b000010000, "array8", I64Regs>;
def ARRAY16 : VISInst<0b000010010, "array16", I64Regs>;
def ARRAY32 : VISInst<0b000010100, "array32", I64Regs>;
def SHUTDOWN : VISInst0<0b010000000, "shutdown">;
} // Predicates = [HasVIS]
// VIS 2 Instructions.
let Predicates = [HasVIS2] in {
def BMASK : VISInst<0b000011001, "bmask", I64Regs>;
def BSHUFFLE : VISInst<0b000011100, "bshuffle">;
def SIAM : VISInst0<0b010000001, "siam">;
def EDGE8N : VISInst<0b000000001, "edge8n", I64Regs>;
def EDGE8LN : VISInst<0b000000011, "edge8ln", I64Regs>;
def EDGE16N : VISInst<0b000000101, "edge16n", I64Regs>;
def EDGE16LN : VISInst<0b000000111, "edge16ln", I64Regs>;
def EDGE32N : VISInst<0b000001001, "edge32n", I64Regs>;
def EDGE32LN : VISInst<0b000001011, "edge32ln", I64Regs>;
} // Predicates = [HasVIS2]
// VIS 3 Instructions.
let Predicates = [HasVIS3] in {
let Uses = [ICC] in
def ADDXC : VISInst<0b000010001, "addxc", I64Regs>;
let Defs = [ICC], Uses = [ICC] in
def ADDXCCC : VISInst<0b000010011, "addxccc", I64Regs>;
let rd = 0, rs1 = 0 in {
def CMASK8 : VISInstFormat<0b000011011, (outs), (ins I64Regs:$rs2),
"cmask8 $rs2", []>;
def CMASK16 : VISInstFormat<0b000011101, (outs), (ins I64Regs:$rs2),
"cmask16 $rs2", []>;
def CMASK32 : VISInstFormat<0b000011111, (outs), (ins I64Regs:$rs2),
"cmask32 $rs2", []>;
}
def FCHKSM16 : VISInst<0b001000100, "fchksm16">;
def FHADDS : F3_3<0b10, 0b110100, 0b001100001,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fhadds $rs1, $rs2, $rd", []>;
def FHADDD : F3_3<0b10, 0b110100, 0b001100010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fhaddd $rs1, $rs2, $rd", []>;
def FHSUBS : F3_3<0b10, 0b110100, 0b001100101,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fhsubs $rs1, $rs2, $rd", []>;
def FHSUBD : F3_3<0b10, 0b110100, 0b001100110,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fhsubd $rs1, $rs2, $rd", []>;
def FLCMPS : VISInstFormat<0b101010001, (outs FCCRegs:$rd),
(ins DFPRegs:$rs1, DFPRegs:$rs2),
"flcmps $rd, $rs1, $rs2", []>;
def FLCMPD : VISInstFormat<0b101010010, (outs FCCRegs:$rd),
(ins DFPRegs:$rs1, DFPRegs:$rs2),
"flcmpd $rd, $rs1, $rs2", []>;
def FMEAN16 : VISInst<0b001000000, "fmean16">;
def FNADDS : F3_3<0b10, 0b110100, 0b001010001,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnadds $rs1, $rs2, $rd", []>;
def FNADDD : F3_3<0b10, 0b110100, 0b001010010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnaddd $rs1, $rs2, $rd", []>;
def FNHADDS : F3_3<0b10, 0b110100, 0b001110001,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnhadds $rs1, $rs2, $rd", []>;
def FNHADDD : F3_3<0b10, 0b110100, 0b001110010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnhaddd $rs1, $rs2, $rd", []>;
def FNMULS : F3_3<0b10, 0b110100, 0b001011001,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnhadds $rs1, $rs2, $rd", []>;
def FNMULD : F3_3<0b10, 0b110100, 0b001011010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnhaddd $rs1, $rs2, $rd", []>;
def FNSMULD : F3_3<0b10, 0b110100, 0b001111001,
(outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
"fnhadds $rs1, $rs2, $rd", []>;
def FPADD64 : VISInst<0b001000010, "fpadd64">;
def FSLL16 : VISInst<0b000100001, "fsll16">;
def FSRL16 : VISInst<0b000100011, "fsrl16">;
def FSLL32 : VISInst<0b000100101, "fsll32">;
def FSRL32 : VISInst<0b000100111, "fsrl32">;
def FSLAS16 : VISInst<0b000101001, "fslas16">;
def FSRA16 : VISInst<0b000101011, "fsra16">;
def FSLAS32 : VISInst<0b000101101, "fslas32">;
def FSRA32 : VISInst<0b000101111, "fsra32">;
let rs1 = 0 in
def LZCNT : VISInstFormat<0b000010111, (outs I64Regs:$rd),
(ins I64Regs:$rs2), "lzcnt $rs2, $rd", []>;
let rs1 = 0 in {
def MOVSTOSW : VISInstFormat<0b100010011, (outs I64Regs:$rd),
(ins DFPRegs:$rs2), "movstosw $rs2, $rd", []>;
def MOVSTOUW : VISInstFormat<0b100010001, (outs I64Regs:$rd),
(ins DFPRegs:$rs2), "movstouw $rs2, $rd", []>;
def MOVDTOX : VISInstFormat<0b100010000, (outs I64Regs:$rd),
(ins DFPRegs:$rs2), "movdtox $rs2, $rd", []>;
def MOVWTOS : VISInstFormat<0b100011001, (outs DFPRegs:$rd),
(ins I64Regs:$rs2), "movdtox $rs2, $rd", []>;
def MOVXTOD : VISInstFormat<0b100011000, (outs DFPRegs:$rd),
(ins I64Regs:$rs2), "movdtox $rs2, $rd", []>;
}
def PDISTN : VISInst<0b000111111, "pdistn">;
def UMULXHI : VISInst<0b000010110, "umulxhi", I64Regs>;
def XMULX : VISInst<0b100010101, "xmulx", I64Regs>;
def XMULXHI : VISInst<0b100010111, "xmulxhi", I64Regs>;
} // Predicates = [IsVIS3]

View File

@ -0,0 +1,109 @@
//===-- Mos6502MCInstLower.cpp - Convert Mos6502 MachineInstr to MCInst -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains code to lower Mos6502 MachineInstrs to their corresponding
// MCInst records.
//
//===----------------------------------------------------------------------===//
#include "Mos6502.h"
#include "MCTargetDesc/Mos6502MCExpr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/IR/Mangler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
using namespace llvm;
static MCOperand LowerSymbolOperand(const MachineInstr *MI,
const MachineOperand &MO,
AsmPrinter &AP) {
Mos6502MCExpr::VariantKind Kind =
(Mos6502MCExpr::VariantKind)MO.getTargetFlags();
const MCSymbol *Symbol = nullptr;
switch(MO.getType()) {
default: llvm_unreachable("Unknown type in LowerSymbolOperand");
case MachineOperand::MO_MachineBasicBlock:
Symbol = MO.getMBB()->getSymbol();
break;
case MachineOperand::MO_GlobalAddress:
Symbol = AP.getSymbol(MO.getGlobal());
break;
case MachineOperand::MO_BlockAddress:
Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress());
break;
case MachineOperand::MO_ExternalSymbol:
Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName());
break;
case MachineOperand::MO_ConstantPoolIndex:
Symbol = AP.GetCPISymbol(MO.getIndex());
break;
}
const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol,
AP.OutContext);
const Mos6502MCExpr *expr = Mos6502MCExpr::create(Kind, MCSym,
AP.OutContext);
return MCOperand::createExpr(expr);
}
static MCOperand LowerOperand(const MachineInstr *MI,
const MachineOperand &MO,
AsmPrinter &AP) {
switch(MO.getType()) {
default: llvm_unreachable("unknown operand type"); break;
case MachineOperand::MO_Register:
if (MO.isImplicit())
break;
return MCOperand::createReg(MO.getReg());
case MachineOperand::MO_Immediate:
return MCOperand::createImm(MO.getImm());
case MachineOperand::MO_MachineBasicBlock:
case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_BlockAddress:
case MachineOperand::MO_ExternalSymbol:
case MachineOperand::MO_ConstantPoolIndex:
return LowerSymbolOperand(MI, MO, AP);
case MachineOperand::MO_RegisterMask: break;
}
return MCOperand();
}
void llvm::LowerMos6502MachineInstrToMCInst(const MachineInstr *MI,
MCInst &OutMI,
AsmPrinter &AP)
{
OutMI.setOpcode(MI->getOpcode());
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
MCOperand MCOp = LowerOperand(MI, MO, AP);
if (MCOp.isValid())
OutMI.addOperand(MCOp);
}
}

View File

@ -0,0 +1,14 @@
//===-- Mos6502MachineFunctionInfo.cpp - Mos6502 Machine Function Info --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Mos6502MachineFunctionInfo.h"
using namespace llvm;
void Mos6502MachineFunctionInfo::anchor() { }

View File

@ -0,0 +1,56 @@
//===- Mos6502MachineFunctionInfo.h - Mos6502 Machine Function Info -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares Mos6502 specific per-machine-function information.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502MACHINEFUNCTIONINFO_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502MACHINEFUNCTIONINFO_H
#include "llvm/CodeGen/MachineFunction.h"
namespace llvm {
class Mos6502MachineFunctionInfo : public MachineFunctionInfo {
virtual void anchor();
private:
unsigned GlobalBaseReg;
/// VarArgsFrameOffset - Frame offset to start of varargs area.
int VarArgsFrameOffset;
/// SRetReturnReg - Holds the virtual register into which the sret
/// argument is passed.
unsigned SRetReturnReg;
/// IsLeafProc - True if the function is a leaf procedure.
bool IsLeafProc;
public:
Mos6502MachineFunctionInfo()
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
IsLeafProc(false) {}
explicit Mos6502MachineFunctionInfo(MachineFunction &MF)
: GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
IsLeafProc(false) {}
unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
unsigned getSRetReturnReg() const { return SRetReturnReg; }
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
void setLeafProc(bool rhs) { IsLeafProc = rhs; }
bool isLeafProc() const { return IsLeafProc; }
};
}
#endif

View File

@ -0,0 +1,213 @@
//===-- Mos6502RegisterInfo.cpp - MOS6502 Register Information ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the MOS6502 implementation of the TargetRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#include "Mos6502RegisterInfo.h"
#include "Mos6502.h"
#include "Mos6502MachineFunctionInfo.h"
#include "Mos6502Subtarget.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetInstrInfo.h"
using namespace llvm;
#define GET_REGINFO_TARGET_DESC
#include "Mos6502GenRegisterInfo.inc"
static cl::opt<bool>
ReserveAppRegisters("mos6502-reserve-app-registers", cl::Hidden, cl::init(false),
cl::desc("Reserve application registers (%g2-%g4)"));
Mos6502RegisterInfo::Mos6502RegisterInfo() : Mos6502GenRegisterInfo(SP::O7) {}
const MCPhysReg*
Mos6502RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
return CSR_SaveList;
}
const uint32_t *
Mos6502RegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
return CSR_RegMask;
}
const uint32_t*
Mos6502RegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const {
return RTCSR_RegMask;
}
BitVector Mos6502RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
BitVector Reserved(getNumRegs());
const Mos6502Subtarget &Subtarget = MF.getSubtarget<Mos6502Subtarget>();
// FIXME: G1 reserved for now for large imm generation by frame code.
Reserved.set(SP::G1);
// G1-G4 can be used in applications.
if (ReserveAppRegisters) {
Reserved.set(SP::G2);
Reserved.set(SP::G3);
Reserved.set(SP::G4);
}
// G5 is not reserved in 64 bit mode.
if (!Subtarget.is64Bit())
Reserved.set(SP::G5);
Reserved.set(SP::O6);
Reserved.set(SP::I6);
Reserved.set(SP::I7);
Reserved.set(SP::G0);
Reserved.set(SP::G6);
Reserved.set(SP::G7);
// Unaliased double registers are not available in non-V9 targets.
if (!Subtarget.isV9()) {
for (unsigned n = 0; n != 16; ++n) {
for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI)
Reserved.set(*AI);
}
}
return Reserved;
}
const TargetRegisterClass*
Mos6502RegisterInfo::getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const {
const Mos6502Subtarget &Subtarget = MF.getSubtarget<Mos6502Subtarget>();
return Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
}
static void replaceFI(MachineFunction &MF,
MachineBasicBlock::iterator II,
MachineInstr &MI,
DebugLoc dl,
unsigned FIOperandNum, int Offset,
unsigned FramePtr)
{
// Replace frame index with a frame pointer reference.
if (Offset >= -4096 && Offset <= 4095) {
// If the offset is small enough to fit in the immediate field, directly
// encode it.
MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
return;
}
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
// FIXME: it would be better to scavenge a register here instead of
// reserving G1 all of the time.
if (Offset >= 0) {
// Emit nonnegaive immediates with sethi + or.
// sethi %hi(Offset), %g1
// add %g1, %fp, %g1
// Insert G1+%lo(offset) into the user.
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HI22(Offset));
// Emit G1 = G1 + I6
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
.addReg(FramePtr);
// Insert: G1+%lo(offset) into the user.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset));
return;
}
// Emit Negative numbers with sethi + xor
// sethi %hix(Offset), %g1
// xor %g1, %lox(offset), %g1
// add %g1, %fp, %g1
// Insert: G1 + 0 into the user.
BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
.addImm(HIX22(Offset));
BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1)
.addReg(SP::G1).addImm(LOX10(Offset));
BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
.addReg(FramePtr);
// Insert: G1+%lo(offset) into the user.
MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
}
void
Mos6502RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS) const {
assert(SPAdj == 0 && "Unexpected");
MachineInstr &MI = *II;
DebugLoc dl = MI.getDebugLoc();
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
// Addressable stack objects are accessed using neg. offsets from %fp
MachineFunction &MF = *MI.getParent()->getParent();
const Mos6502Subtarget &Subtarget = MF.getSubtarget<Mos6502Subtarget>();
int64_t Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
MI.getOperand(FIOperandNum + 1).getImm() +
Subtarget.getStackPointerBias();
Mos6502MachineFunctionInfo *FuncInfo = MF.getInfo<Mos6502MachineFunctionInfo>();
unsigned FramePtr = SP::I6;
if (FuncInfo->isLeafProc()) {
// Use %sp and adjust offset if needed.
FramePtr = SP::O6;
int stackSize = MF.getFrameInfo()->getStackSize();
Offset += (stackSize) ? Subtarget.getAdjustedFrameSize(stackSize) : 0 ;
}
if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) {
if (MI.getOpcode() == SP::STQFri) {
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
unsigned SrcReg = MI.getOperand(2).getReg();
unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64);
unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64);
MachineInstr *StMI =
BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri))
.addReg(FramePtr).addImm(0).addReg(SrcEvenReg);
replaceFI(MF, II, *StMI, dl, 0, Offset, FramePtr);
MI.setDesc(TII.get(SP::STDFri));
MI.getOperand(2).setReg(SrcOddReg);
Offset += 8;
} else if (MI.getOpcode() == SP::LDQFri) {
const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
unsigned DestReg = MI.getOperand(0).getReg();
unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64);
unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64);
MachineInstr *StMI =
BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg)
.addReg(FramePtr).addImm(0);
replaceFI(MF, II, *StMI, dl, 1, Offset, FramePtr);
MI.setDesc(TII.get(SP::LDDFri));
MI.getOperand(0).setReg(DestOddReg);
Offset += 8;
}
}
replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FramePtr);
}
unsigned Mos6502RegisterInfo::getFrameRegister(const MachineFunction &MF) const {
return SP::I6;
}

View File

@ -0,0 +1,51 @@
//===-- Mos6502RegisterInfo.h - Mos6502 Register Information Impl ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mos6502 implementation of the TargetRegisterInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502REGISTERINFO_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502REGISTERINFO_H
#include "llvm/Target/TargetRegisterInfo.h"
#define GET_REGINFO_HEADER
#include "Mos6502GenRegisterInfo.inc"
namespace llvm {
struct Mos6502RegisterInfo : public Mos6502GenRegisterInfo {
Mos6502RegisterInfo();
/// Code Generation virtual methods...
const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const override;
const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const;
BitVector getReservedRegs(const MachineFunction &MF) const override;
const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF,
unsigned Kind) const override;
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS = nullptr) const override;
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
RegScavenger *RS = nullptr) const;
// Debug information queries.
unsigned getFrameRegister(const MachineFunction &MF) const override;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,254 @@
//===-- Mos6502RegisterInfo.td - Mos6502 Register defs ---------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Declarations that describe the Mos6502 register file
//===----------------------------------------------------------------------===//
class Mos6502Reg<bits<16> Enc, string n> : Register<n> {
let HWEncoding = Enc;
let Namespace = "SP";
}
class Mos6502CtrlReg<bits<16> Enc, string n>: Register<n> {
let HWEncoding = Enc;
let Namespace = "SP";
}
let Namespace = "SP" in {
def sub_even : SubRegIndex<32>;
def sub_odd : SubRegIndex<32, 32>;
def sub_even64 : SubRegIndex<64>;
def sub_odd64 : SubRegIndex<64, 64>;
}
// Registers are identified with 5-bit ID numbers.
// Ri - 32-bit integer registers
class Ri<bits<16> Enc, string n> : Mos6502Reg<Enc, n>;
// Rf - 32-bit floating-point registers
class Rf<bits<16> Enc, string n> : Mos6502Reg<Enc, n>;
// Rd - Slots in the FP register file for 64-bit floating-point values.
class Rd<bits<16> Enc, string n, list<Register> subregs> : Mos6502Reg<Enc, n> {
let SubRegs = subregs;
let SubRegIndices = [sub_even, sub_odd];
let CoveredBySubRegs = 1;
}
// Rq - Slots in the FP register file for 128-bit floating-point values.
class Rq<bits<16> Enc, string n, list<Register> subregs> : Mos6502Reg<Enc, n> {
let SubRegs = subregs;
let SubRegIndices = [sub_even64, sub_odd64];
let CoveredBySubRegs = 1;
}
// Control Registers
def ICC : Mos6502CtrlReg<0, "ICC">; // This represents icc and xcc in 64-bit code.
foreach I = 0-3 in
def FCC#I : Mos6502CtrlReg<I, "FCC"#I>;
// Y register
def Y : Mos6502CtrlReg<0, "Y">, DwarfRegNum<[64]>;
// Ancillary state registers (implementation defined)
def ASR1 : Mos6502CtrlReg<1, "ASR1">;
def ASR2 : Mos6502CtrlReg<2, "ASR2">;
def ASR3 : Mos6502CtrlReg<3, "ASR3">;
def ASR4 : Mos6502CtrlReg<4, "ASR4">;
def ASR5 : Mos6502CtrlReg<5, "ASR5">;
def ASR6 : Mos6502CtrlReg<6, "ASR6">;
def ASR7 : Mos6502CtrlReg<7, "ASR7">;
def ASR8 : Mos6502CtrlReg<8, "ASR8">;
def ASR9 : Mos6502CtrlReg<9, "ASR9">;
def ASR10 : Mos6502CtrlReg<10, "ASR10">;
def ASR11 : Mos6502CtrlReg<11, "ASR11">;
def ASR12 : Mos6502CtrlReg<12, "ASR12">;
def ASR13 : Mos6502CtrlReg<13, "ASR13">;
def ASR14 : Mos6502CtrlReg<14, "ASR14">;
def ASR15 : Mos6502CtrlReg<15, "ASR15">;
def ASR16 : Mos6502CtrlReg<16, "ASR16">;
def ASR17 : Mos6502CtrlReg<17, "ASR17">;
def ASR18 : Mos6502CtrlReg<18, "ASR18">;
def ASR19 : Mos6502CtrlReg<19, "ASR19">;
def ASR20 : Mos6502CtrlReg<20, "ASR20">;
def ASR21 : Mos6502CtrlReg<21, "ASR21">;
def ASR22 : Mos6502CtrlReg<22, "ASR22">;
def ASR23 : Mos6502CtrlReg<23, "ASR23">;
def ASR24 : Mos6502CtrlReg<24, "ASR24">;
def ASR25 : Mos6502CtrlReg<25, "ASR25">;
def ASR26 : Mos6502CtrlReg<26, "ASR26">;
def ASR27 : Mos6502CtrlReg<27, "ASR27">;
def ASR28 : Mos6502CtrlReg<28, "ASR28">;
def ASR29 : Mos6502CtrlReg<29, "ASR29">;
def ASR30 : Mos6502CtrlReg<30, "ASR30">;
def ASR31 : Mos6502CtrlReg<31, "ASR31">;
// Note that PSR, WIM, and TBR don't exist on the Mos6502V9, only the V8.
def PSR : Mos6502CtrlReg<0, "PSR">;
def WIM : Mos6502CtrlReg<0, "WIM">;
def TBR : Mos6502CtrlReg<0, "TBR">;
// Integer registers
def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>;
def G1 : Ri< 1, "G1">, DwarfRegNum<[1]>;
def G2 : Ri< 2, "G2">, DwarfRegNum<[2]>;
def G3 : Ri< 3, "G3">, DwarfRegNum<[3]>;
def G4 : Ri< 4, "G4">, DwarfRegNum<[4]>;
def G5 : Ri< 5, "G5">, DwarfRegNum<[5]>;
def G6 : Ri< 6, "G6">, DwarfRegNum<[6]>;
def G7 : Ri< 7, "G7">, DwarfRegNum<[7]>;
def O0 : Ri< 8, "O0">, DwarfRegNum<[8]>;
def O1 : Ri< 9, "O1">, DwarfRegNum<[9]>;
def O2 : Ri<10, "O2">, DwarfRegNum<[10]>;
def O3 : Ri<11, "O3">, DwarfRegNum<[11]>;
def O4 : Ri<12, "O4">, DwarfRegNum<[12]>;
def O5 : Ri<13, "O5">, DwarfRegNum<[13]>;
def O6 : Ri<14, "SP">, DwarfRegNum<[14]>;
def O7 : Ri<15, "O7">, DwarfRegNum<[15]>;
def L0 : Ri<16, "L0">, DwarfRegNum<[16]>;
def L1 : Ri<17, "L1">, DwarfRegNum<[17]>;
def L2 : Ri<18, "L2">, DwarfRegNum<[18]>;
def L3 : Ri<19, "L3">, DwarfRegNum<[19]>;
def L4 : Ri<20, "L4">, DwarfRegNum<[20]>;
def L5 : Ri<21, "L5">, DwarfRegNum<[21]>;
def L6 : Ri<22, "L6">, DwarfRegNum<[22]>;
def L7 : Ri<23, "L7">, DwarfRegNum<[23]>;
def I0 : Ri<24, "I0">, DwarfRegNum<[24]>;
def I1 : Ri<25, "I1">, DwarfRegNum<[25]>;
def I2 : Ri<26, "I2">, DwarfRegNum<[26]>;
def I3 : Ri<27, "I3">, DwarfRegNum<[27]>;
def I4 : Ri<28, "I4">, DwarfRegNum<[28]>;
def I5 : Ri<29, "I5">, DwarfRegNum<[29]>;
def I6 : Ri<30, "FP">, DwarfRegNum<[30]>;
def I7 : Ri<31, "I7">, DwarfRegNum<[31]>;
// Floating-point registers
def F0 : Rf< 0, "F0">, DwarfRegNum<[32]>;
def F1 : Rf< 1, "F1">, DwarfRegNum<[33]>;
def F2 : Rf< 2, "F2">, DwarfRegNum<[34]>;
def F3 : Rf< 3, "F3">, DwarfRegNum<[35]>;
def F4 : Rf< 4, "F4">, DwarfRegNum<[36]>;
def F5 : Rf< 5, "F5">, DwarfRegNum<[37]>;
def F6 : Rf< 6, "F6">, DwarfRegNum<[38]>;
def F7 : Rf< 7, "F7">, DwarfRegNum<[39]>;
def F8 : Rf< 8, "F8">, DwarfRegNum<[40]>;
def F9 : Rf< 9, "F9">, DwarfRegNum<[41]>;
def F10 : Rf<10, "F10">, DwarfRegNum<[42]>;
def F11 : Rf<11, "F11">, DwarfRegNum<[43]>;
def F12 : Rf<12, "F12">, DwarfRegNum<[44]>;
def F13 : Rf<13, "F13">, DwarfRegNum<[45]>;
def F14 : Rf<14, "F14">, DwarfRegNum<[46]>;
def F15 : Rf<15, "F15">, DwarfRegNum<[47]>;
def F16 : Rf<16, "F16">, DwarfRegNum<[48]>;
def F17 : Rf<17, "F17">, DwarfRegNum<[49]>;
def F18 : Rf<18, "F18">, DwarfRegNum<[50]>;
def F19 : Rf<19, "F19">, DwarfRegNum<[51]>;
def F20 : Rf<20, "F20">, DwarfRegNum<[52]>;
def F21 : Rf<21, "F21">, DwarfRegNum<[53]>;
def F22 : Rf<22, "F22">, DwarfRegNum<[54]>;
def F23 : Rf<23, "F23">, DwarfRegNum<[55]>;
def F24 : Rf<24, "F24">, DwarfRegNum<[56]>;
def F25 : Rf<25, "F25">, DwarfRegNum<[57]>;
def F26 : Rf<26, "F26">, DwarfRegNum<[58]>;
def F27 : Rf<27, "F27">, DwarfRegNum<[59]>;
def F28 : Rf<28, "F28">, DwarfRegNum<[60]>;
def F29 : Rf<29, "F29">, DwarfRegNum<[61]>;
def F30 : Rf<30, "F30">, DwarfRegNum<[62]>;
def F31 : Rf<31, "F31">, DwarfRegNum<[63]>;
// Aliases of the F* registers used to hold 64-bit fp values (doubles)
def D0 : Rd< 0, "F0", [F0, F1]>, DwarfRegNum<[72]>;
def D1 : Rd< 2, "F2", [F2, F3]>, DwarfRegNum<[73]>;
def D2 : Rd< 4, "F4", [F4, F5]>, DwarfRegNum<[74]>;
def D3 : Rd< 6, "F6", [F6, F7]>, DwarfRegNum<[75]>;
def D4 : Rd< 8, "F8", [F8, F9]>, DwarfRegNum<[76]>;
def D5 : Rd<10, "F10", [F10, F11]>, DwarfRegNum<[77]>;
def D6 : Rd<12, "F12", [F12, F13]>, DwarfRegNum<[78]>;
def D7 : Rd<14, "F14", [F14, F15]>, DwarfRegNum<[79]>;
def D8 : Rd<16, "F16", [F16, F17]>, DwarfRegNum<[80]>;
def D9 : Rd<18, "F18", [F18, F19]>, DwarfRegNum<[81]>;
def D10 : Rd<20, "F20", [F20, F21]>, DwarfRegNum<[82]>;
def D11 : Rd<22, "F22", [F22, F23]>, DwarfRegNum<[83]>;
def D12 : Rd<24, "F24", [F24, F25]>, DwarfRegNum<[84]>;
def D13 : Rd<26, "F26", [F26, F27]>, DwarfRegNum<[85]>;
def D14 : Rd<28, "F28", [F28, F29]>, DwarfRegNum<[86]>;
def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>;
// Unaliased double precision floating point registers.
// FIXME: Define DwarfRegNum for these registers.
def D16 : Mos6502Reg< 1, "F32">;
def D17 : Mos6502Reg< 3, "F34">;
def D18 : Mos6502Reg< 5, "F36">;
def D19 : Mos6502Reg< 7, "F38">;
def D20 : Mos6502Reg< 9, "F40">;
def D21 : Mos6502Reg<11, "F42">;
def D22 : Mos6502Reg<13, "F44">;
def D23 : Mos6502Reg<15, "F46">;
def D24 : Mos6502Reg<17, "F48">;
def D25 : Mos6502Reg<19, "F50">;
def D26 : Mos6502Reg<21, "F52">;
def D27 : Mos6502Reg<23, "F54">;
def D28 : Mos6502Reg<25, "F56">;
def D29 : Mos6502Reg<27, "F58">;
def D30 : Mos6502Reg<29, "F60">;
def D31 : Mos6502Reg<31, "F62">;
// Aliases of the F* registers used to hold 128-bit for values (long doubles).
def Q0 : Rq< 0, "F0", [D0, D1]>;
def Q1 : Rq< 4, "F4", [D2, D3]>;
def Q2 : Rq< 8, "F8", [D4, D5]>;
def Q3 : Rq<12, "F12", [D6, D7]>;
def Q4 : Rq<16, "F16", [D8, D9]>;
def Q5 : Rq<20, "F20", [D10, D11]>;
def Q6 : Rq<24, "F24", [D12, D13]>;
def Q7 : Rq<28, "F28", [D14, D15]>;
def Q8 : Rq< 1, "F32", [D16, D17]>;
def Q9 : Rq< 5, "F36", [D18, D19]>;
def Q10 : Rq< 9, "F40", [D20, D21]>;
def Q11 : Rq<13, "F44", [D22, D23]>;
def Q12 : Rq<17, "F48", [D24, D25]>;
def Q13 : Rq<21, "F52", [D26, D27]>;
def Q14 : Rq<25, "F56", [D28, D29]>;
def Q15 : Rq<29, "F60", [D30, D31]>;
// Register classes.
//
// FIXME: the register order should be defined in terms of the preferred
// allocation order...
//
// This register class should not be used to hold i64 values, use the I64Regs
// register class for that. The i64 type is included here to allow i64 patterns
// using the integer instructions.
def IntRegs : RegisterClass<"SP", [i32, i64], 32,
(add (sequence "I%u", 0, 7),
(sequence "G%u", 0, 7),
(sequence "L%u", 0, 7),
(sequence "O%u", 0, 7))>;
// Register class for 64-bit mode, with a 64-bit spill slot size.
// These are the same as the 32-bit registers, so TableGen will consider this
// to be a sub-class of IntRegs. That works out because requiring a 64-bit
// spill slot is a stricter constraint than only requiring a 32-bit spill slot.
def I64Regs : RegisterClass<"SP", [i64], 64, (add IntRegs)>;
// Floating point register classes.
def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>;
def DFPRegs : RegisterClass<"SP", [f64], 64, (sequence "D%u", 0, 31)>;
def QFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 15)>;
// Floating point control register classes.
def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>;
// Ancillary state registers
def ASRRegs : RegisterClass<"SP", [i32], 32,
(add Y, (sequence "ASR%u", 1, 31))> {
let isAllocatable = 0;
}

View File

@ -0,0 +1,83 @@
//===-- Mos6502Subtarget.cpp - MOS6502 Subtarget Information ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MOS6502 specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//
#include "Mos6502Subtarget.h"
#include "Mos6502.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
#define DEBUG_TYPE "mos6502-subtarget"
#define GET_SUBTARGETINFO_TARGET_DESC
#define GET_SUBTARGETINFO_CTOR
#include "Mos6502GenSubtargetInfo.inc"
void Mos6502Subtarget::anchor() { }
Mos6502Subtarget &Mos6502Subtarget::initializeSubtargetDependencies(StringRef CPU,
StringRef FS) {
IsV9 = false;
V8DeprecatedInsts = false;
IsVIS = false;
HasHardQuad = false;
UsePopc = false;
// Determine default and user specified characteristics
std::string CPUName = CPU;
if (CPUName.empty())
CPUName = (Is64Bit) ? "v9" : "v8";
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
// Popc is a v9-only instruction.
if (!IsV9)
UsePopc = false;
return *this;
}
Mos6502Subtarget::Mos6502Subtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, TargetMachine &TM,
bool is64Bit)
: Mos6502GenSubtargetInfo(TT, CPU, FS), Is64Bit(is64Bit),
InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
FrameLowering(*this) {}
int Mos6502Subtarget::getAdjustedFrameSize(int frameSize) const {
if (is64Bit()) {
// All 64-bit stack frames must be 16-byte aligned, and must reserve space
// for spilling the 16 window registers at %sp+BIAS..%sp+BIAS+128.
frameSize += 128;
// Frames with calls must also reserve space for 6 outgoing arguments
// whether they are used or not. LowerCall_64 takes care of that.
assert(frameSize % 16 == 0 && "Stack size not 16-byte aligned");
} else {
// Emit the correct save instruction based on the number of bytes in
// the frame. Minimum stack frame size according to V8 ABI is:
// 16 words for register window spill
// 1 word for address of returned aggregate-value
// + 6 words for passing parameters on the stack
// ----------
// 23 words * 4 bytes per word = 92 bytes
frameSize += 92;
// Round up to next doubleword boundary -- a double-word boundary
// is required by the ABI.
frameSize = RoundUpToAlignment(frameSize, 8);
}
return frameSize;
}

View File

@ -0,0 +1,93 @@
//===-- Mos6502Subtarget.h - Define Subtarget for the MOS6502 -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the MOS6502 specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502SUBTARGET_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502SUBTARGET_H
#include "Mos6502FrameLowering.h"
#include "Mos6502InstrInfo.h"
#include "Mos6502ISelLowering.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetSelectionDAGInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <string>
#define GET_SUBTARGETINFO_HEADER
#include "Mos6502GenSubtargetInfo.inc"
namespace llvm {
class StringRef;
class Mos6502Subtarget : public Mos6502GenSubtargetInfo {
virtual void anchor();
bool IsV9;
bool V8DeprecatedInsts;
bool IsVIS, IsVIS2, IsVIS3;
bool Is64Bit;
bool HasHardQuad;
bool UsePopc;
Mos6502InstrInfo InstrInfo;
Mos6502TargetLowering TLInfo;
TargetSelectionDAGInfo TSInfo;
Mos6502FrameLowering FrameLowering;
public:
Mos6502Subtarget(const Triple &TT, const std::string &CPU,
const std::string &FS, TargetMachine &TM, bool is64bit);
const Mos6502InstrInfo *getInstrInfo() const override { return &InstrInfo; }
const TargetFrameLowering *getFrameLowering() const override {
return &FrameLowering;
}
const Mos6502RegisterInfo *getRegisterInfo() const override {
return &InstrInfo.getRegisterInfo();
}
const Mos6502TargetLowering *getTargetLowering() const override {
return &TLInfo;
}
const TargetSelectionDAGInfo *getSelectionDAGInfo() const override {
return &TSInfo;
}
bool isV9() const { return IsV9; }
bool isVIS() const { return IsVIS; }
bool isVIS2() const { return IsVIS2; }
bool isVIS3() const { return IsVIS3; }
bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; }
bool hasHardQuad() const { return HasHardQuad; }
bool usePopc() const { return UsePopc; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
Mos6502Subtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS);
bool is64Bit() const { return Is64Bit; }
/// The 64-bit ABI uses biased stack and frame pointers, so the stack frame
/// of the current function is the area from [%sp+BIAS] to [%fp+BIAS].
int64_t getStackPointerBias() const {
return is64Bit() ? 2047 : 0;
}
/// Given a actual stack size as determined by FrameInfo, this function
/// returns adjusted framesize which includes space for register window
/// spills and arguments.
int getAdjustedFrameSize(int stackSize) const;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,132 @@
//===-- Mos6502TargetMachine.cpp - Define TargetMachine for Mos6502 -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "Mos6502TargetMachine.h"
#include "Mos6502TargetObjectFile.h"
#include "Mos6502.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
extern "C" void LLVMInitializeMos6502Target() {
// Register the target.
RegisterTargetMachine<Mos6502V8TargetMachine> X(TheMos6502Target);
RegisterTargetMachine<Mos6502V9TargetMachine> Y(TheMos6502V9Target);
RegisterTargetMachine<Mos6502elTargetMachine> Z(TheMos6502elTarget);
}
static std::string computeDataLayout(const Triple &T, bool is64Bit) {
// Mos6502 is typically big endian, but some are little.
std::string Ret = T.getArch() == Triple::mos6502el ? "e" : "E";
Ret += "-m:e";
// Some ABIs have 32bit pointers.
if (!is64Bit)
Ret += "-p:32:32";
// Alignments for 64 bit integers.
Ret += "-i64:64";
// On Mos6502V9 128 floats are aligned to 128 bits, on others only to 64.
// On Mos6502V9 registers can hold 64 or 32 bits, on others only 32.
if (is64Bit)
Ret += "-n32:64";
else
Ret += "-f128:64-n32";
if (is64Bit)
Ret += "-S128";
else
Ret += "-S64";
return Ret;
}
/// Mos6502TargetMachine ctor - Create an ILP32 architecture model
///
Mos6502TargetMachine::Mos6502TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL, bool is64bit)
: LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
RM, CM, OL),
TLOF(make_unique<Mos6502ELFTargetObjectFile>()),
Subtarget(TT, CPU, FS, *this, is64bit) {
initAsmInfo();
}
Mos6502TargetMachine::~Mos6502TargetMachine() {}
namespace {
/// Mos6502 Code Generator Pass Configuration Options.
class Mos6502PassConfig : public TargetPassConfig {
public:
Mos6502PassConfig(Mos6502TargetMachine *TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {}
Mos6502TargetMachine &getMos6502TargetMachine() const {
return getTM<Mos6502TargetMachine>();
}
void addIRPasses() override;
bool addInstSelector() override;
void addPreEmitPass() override;
};
} // namespace
TargetPassConfig *Mos6502TargetMachine::createPassConfig(PassManagerBase &PM) {
return new Mos6502PassConfig(this, PM);
}
void Mos6502PassConfig::addIRPasses() {
addPass(createAtomicExpandPass(&getMos6502TargetMachine()));
TargetPassConfig::addIRPasses();
}
bool Mos6502PassConfig::addInstSelector() {
addPass(createMos6502ISelDag(getMos6502TargetMachine()));
return false;
}
void Mos6502PassConfig::addPreEmitPass(){
addPass(createMos6502DelaySlotFillerPass(getMos6502TargetMachine()));
}
void Mos6502V8TargetMachine::anchor() { }
Mos6502V8TargetMachine::Mos6502V8TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL)
: Mos6502TargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
void Mos6502V9TargetMachine::anchor() { }
Mos6502V9TargetMachine::Mos6502V9TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL)
: Mos6502TargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
void Mos6502elTargetMachine::anchor() {}
Mos6502elTargetMachine::Mos6502elTargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS,
const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL)
: Mos6502TargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}

View File

@ -0,0 +1,78 @@
//===-- Mos6502TargetMachine.h - Define TargetMachine for Mos6502 ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Mos6502 specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502TARGETMACHINE_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502TARGETMACHINE_H
#include "Mos6502InstrInfo.h"
#include "Mos6502Subtarget.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class Mos6502TargetMachine : public LLVMTargetMachine {
std::unique_ptr<TargetLoweringObjectFile> TLOF;
Mos6502Subtarget Subtarget;
public:
Mos6502TargetMachine(const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL,
bool is64bit);
~Mos6502TargetMachine() override;
const Mos6502Subtarget *getSubtargetImpl(const Function &) const override {
return &Subtarget;
}
// Pass Pipeline Configuration
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
TargetLoweringObjectFile *getObjFileLowering() const override {
return TLOF.get();
}
};
/// Mos6502V8TargetMachine - Mos6502 32-bit target machine
///
class Mos6502V8TargetMachine : public Mos6502TargetMachine {
virtual void anchor();
public:
Mos6502V8TargetMachine(const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL);
};
/// Mos6502V9TargetMachine - Mos6502 64-bit target machine
///
class Mos6502V9TargetMachine : public Mos6502TargetMachine {
virtual void anchor();
public:
Mos6502V9TargetMachine(const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL);
};
class Mos6502elTargetMachine : public Mos6502TargetMachine {
virtual void anchor();
public:
Mos6502elTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
StringRef FS, const TargetOptions &Options,
Reloc::Model RM, CodeModel::Model CM,
CodeGenOpt::Level OL);
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,43 @@
//===------- Mos6502TargetObjectFile.cpp - Mos6502 Object Info Impl -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Mos6502TargetObjectFile.h"
#include "MCTargetDesc/Mos6502MCExpr.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;
const MCExpr *Mos6502ELFTargetObjectFile::getTTypeGlobalReference(
const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
const TargetMachine &TM, MachineModuleInfo *MMI,
MCStreamer &Streamer) const {
if (Encoding & dwarf::DW_EH_PE_pcrel) {
MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, ".DW.stub", Mang, TM);
// Add information about the stub reference to ELFMMI so that the stub
// gets emitted by the asmprinter.
MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym);
if (!StubSym.getPointer()) {
MCSymbol *Sym = TM.getSymbol(GV, Mang);
StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage());
}
MCContext &Ctx = getContext();
return Mos6502MCExpr::create(Mos6502MCExpr::VK_Mos6502_R_DISP32,
MCSymbolRefExpr::create(SSym, Ctx), Ctx);
}
return TargetLoweringObjectFileELF::getTTypeGlobalReference(
GV, Encoding, Mang, TM, MMI, Streamer);
}

View File

@ -0,0 +1,35 @@
//===-- Mos6502TargetObjectFile.h - Mos6502 Object Info -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502TARGETOBJECTFILE_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502TARGETOBJECTFILE_H
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
namespace llvm {
class MCContext;
class TargetMachine;
class Mos6502ELFTargetObjectFile : public TargetLoweringObjectFileELF {
public:
Mos6502ELFTargetObjectFile() :
TargetLoweringObjectFileELF()
{}
const MCExpr *
getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
Mangler &Mang, const TargetMachine &TM,
MachineModuleInfo *MMI,
MCStreamer &Streamer) const override;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,49 @@
//===-- Mos6502TargetStreamer.h - Mos6502 Target Streamer ----------*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_MOS6502_MOS6502TARGETSTREAMER_H
#define LLVM_LIB_TARGET_MOS6502_MOS6502TARGETSTREAMER_H
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCStreamer.h"
namespace llvm {
class Mos6502TargetStreamer : public MCTargetStreamer {
virtual void anchor();
public:
Mos6502TargetStreamer(MCStreamer &S);
/// Emit ".register <reg>, #ignore".
virtual void emitMos6502RegisterIgnore(unsigned reg) = 0;
/// Emit ".register <reg>, #scratch".
virtual void emitMos6502RegisterScratch(unsigned reg) = 0;
};
// This part is for ascii assembly output
class Mos6502TargetAsmStreamer : public Mos6502TargetStreamer {
formatted_raw_ostream &OS;
public:
Mos6502TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
void emitMos6502RegisterIgnore(unsigned reg) override;
void emitMos6502RegisterScratch(unsigned reg) override;
};
// This part is for ELF object output
class Mos6502TargetELFStreamer : public Mos6502TargetStreamer {
public:
Mos6502TargetELFStreamer(MCStreamer &S);
MCELFStreamer &getStreamer();
void emitMos6502RegisterIgnore(unsigned reg) override {}
void emitMos6502RegisterScratch(unsigned reg) override {}
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,3 @@
add_llvm_library(LLVMMos6502Info
Mos6502TargetInfo.cpp
)

View File

@ -0,0 +1,23 @@
;===- ./lib/Target/Mos6502/TargetInfo/LLVMBuild.txt --------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Mos6502Info
parent = Mos6502
required_libraries = Support
add_to_library_groups = Mos6502

View File

@ -0,0 +1,15 @@
##===- lib/Target/Mos6502/TargetInfo/Makefile ----------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMMos6502Info
# Hack: we need to include 'main' target directory to grab private headers
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,26 @@
//===-- Mos6502TargetInfo.cpp - Mos6502 Target Implementation -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Mos6502.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
Target llvm::TheMos6502Target;
Target llvm::TheMos6502V9Target;
Target llvm::TheMos6502elTarget;
extern "C" void LLVMInitializeMos6502TargetInfo() {
RegisterTarget<Triple::mos6502, /*HasJIT=*/true> X(TheMos6502Target, "mos6502",
"Mos6502");
RegisterTarget<Triple::mos6502v9, /*HasJIT=*/true> Y(TheMos6502V9Target,
"mos6502v9", "Mos6502 V9");
RegisterTarget<Triple::mos6502el, /*HasJIT=*/true> Z(TheMos6502elTarget,
"mos6502el", "Mos6502 LE");
}