diff options
Diffstat (limited to 'contrib/llvm/lib/Target/MSP430')
36 files changed, 5715 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/CMakeLists.txt b/contrib/llvm/lib/Target/MSP430/AsmPrinter/CMakeLists.txt new file mode 100644 index 0000000..4b1f4e6 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMSP430AsmPrinter + MSP430AsmPrinter.cpp + MSP430InstPrinter.cpp + MSP430MCInstLower.cpp + ) +add_dependencies(LLVMMSP430AsmPrinter MSP430CodeGenTable_gen) diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp new file mode 100644 index 0000000..56f72bb --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -0,0 +1,179 @@ +//===-- MSP430AsmPrinter.cpp - MSP430 LLVM assembly writer ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to the MSP430 assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" +#include "MSP430MCAsmInfo.h" +#include "MSP430MCInstLower.h" +#include "MSP430TargetMachine.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + class MSP430AsmPrinter : public AsmPrinter { + public: + MSP430AsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) {} + + virtual const char *getPassName() const { + return "MSP430 Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char* Modifier = 0); + void printSrcMemOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + bool PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O); + void EmitInstruction(const MachineInstr *MI); + }; +} // end of anonymous namespace + + +void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + default: assert(0 && "Not implemented yet!"); + case MachineOperand::MO_Register: + O << MSP430InstPrinter::getRegisterName(MO.getReg()); + return; + case MachineOperand::MO_Immediate: + if (!Modifier || strcmp(Modifier, "nohash")) + O << '#'; + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: { + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + uint64_t Offset = MO.getOffset(); + + // If the global address expression is a part of displacement field with a + // register base, we should not emit any prefix symbol here, e.g. + // mov.w &foo, r1 + // vs + // mov.w glb(r1), r2 + // Otherwise (!) msp430-as will silently miscompile the output :( + if (!Modifier || strcmp(Modifier, "nohash")) + O << (isMemOp ? '&' : '#'); + if (Offset) + O << '(' << Offset << '+'; + + O << *Mang->getSymbol(MO.getGlobal()); + + if (Offset) + O << ')'; + + return; + } + case MachineOperand::MO_ExternalSymbol: { + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + O << (isMemOp ? '&' : '#'); + O << MAI->getGlobalPrefix() << MO.getSymbolName(); + return; + } + } +} + +void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &Base = MI->getOperand(OpNum); + const MachineOperand &Disp = MI->getOperand(OpNum+1); + + // Print displacement first + + // Imm here is in fact global address - print extra modifier. + if (Disp.isImm() && !Base.getReg()) + O << '&'; + printOperand(MI, OpNum+1, O, "nohash"); + + // Print register base field + if (Base.getReg()) { + O << '('; + printOperand(MI, OpNum, O); + O << ')'; + } +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool MSP430AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + printOperand(MI, OpNo, O); + return false; +} + +bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) { + return true; // Unknown modifier. + } + printSrcMemOperand(MI, OpNo, O); + return false; +} + +//===----------------------------------------------------------------------===// +void MSP430AsmPrinter::EmitInstruction(const MachineInstr *MI) { + MSP430MCInstLower MCInstLowering(OutContext, *Mang, *this); + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); +} + +static MCInstPrinter *createMSP430MCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI) { + if (SyntaxVariant == 0) + return new MSP430InstPrinter(MAI); + return 0; +} + +// Force static initialization. +extern "C" void LLVMInitializeMSP430AsmPrinter() { + RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target); + TargetRegistry::RegisterMCInstPrinter(TheMSP430Target, + createMSP430MCInstPrinter); +} diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp new file mode 100644 index 0000000..c15d408 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp @@ -0,0 +1,116 @@ +//===-- MSP430InstPrinter.cpp - Convert MSP430 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 MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#include "MSP430GenAsmWriter.inc" +#undef MachineInstr + +void MSP430InstPrinter::printInst(const MCInst *MI, raw_ostream &O) { + printInstruction(MI, O); +} + +void MSP430InstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) + O << Op.getImm(); + else { + assert(Op.isExpr() && "unknown pcrel immediate operand"); + O << *Op.getExpr(); + } +} + +void MSP430InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << '#' << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << '#' << *Op.getExpr(); + } +} + +void MSP430InstPrinter::printSrcMemOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, + const char *Modifier) { + const MCOperand &Base = MI->getOperand(OpNo); + const MCOperand &Disp = MI->getOperand(OpNo+1); + + // Print displacement first + + // If the global address expression is a part of displacement field with a + // register base, we should not emit any prefix symbol here, e.g. + // mov.w &foo, r1 + // vs + // mov.w glb(r1), r2 + // Otherwise (!) msp430-as will silently miscompile the output :( + if (!Base.getReg()) + O << '&'; + + if (Disp.isExpr()) + O << *Disp.getExpr(); + else { + assert(Disp.isImm() && "Expected immediate in displacement field"); + O << Disp.getImm(); + } + + // Print register base field + if (Base.getReg()) + O << '(' << getRegisterName(Base.getReg()) << ')'; +} + +void MSP430InstPrinter::printCCOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + unsigned CC = MI->getOperand(OpNo).getImm(); + + switch (CC) { + default: + llvm_unreachable("Unsupported CC code"); + break; + case MSP430CC::COND_E: + O << "eq"; + break; + case MSP430CC::COND_NE: + O << "ne"; + break; + case MSP430CC::COND_HS: + O << "hs"; + break; + case MSP430CC::COND_LO: + O << "lo"; + break; + case MSP430CC::COND_GE: + O << "ge"; + break; + case MSP430CC::COND_L: + O << 'l'; + break; + } +} diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h new file mode 100644 index 0000000..f0e1ce2 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h @@ -0,0 +1,43 @@ +//===-- MSP430InstPrinter.h - Convert MSP430 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 a MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430INSTPRINTER_H +#define MSP430INSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + class MCOperand; + + class MSP430InstPrinter : public MCInstPrinter { + public: + MSP430InstPrinter(const MCAsmInfo &MAI) : MCInstPrinter(MAI) { + } + + virtual void printInst(const MCInst *MI, raw_ostream &O); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = 0); + void printPCRelImmOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printSrcMemOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = 0); + void printCCOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + }; +} + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp new file mode 100644 index 0000000..d1d9a11 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp @@ -0,0 +1,150 @@ +//===-- MSP430MCInstLower.cpp - Convert MSP430 MachineInstr to an 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 MSP430 MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "MSP430MCInstLower.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +MCSymbol *MSP430MCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.Mang->getSymbol(MO.getGlobal()); +} + +MCSymbol *MSP430MCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCSymbol *MSP430MCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetBlockAddressSymbol(const MachineOperand &MO) const { + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.GetBlockAddressSymbol(MO.getBlockAddress()); +} + +MCOperand MSP430MCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + +void MSP430MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, GetBlockAddressSymbol(MO)); + } + + OutMI.addOperand(MCOp); + } +} diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h new file mode 100644 index 0000000..e937696 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h @@ -0,0 +1,50 @@ +//===-- MSP430MCInstLower.h - Lower MachineInstr to MCInst ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430_MCINSTLOWER_H +#define MSP430_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + + /// MSP430MCInstLower - This class is used to lower an MachineInstr + /// into an MCInst. +class LLVM_LIBRARY_VISIBILITY MSP430MCInstLower { + MCContext &Ctx; + Mangler &Mang; + + AsmPrinter &Printer; +public: + MSP430MCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCSymbol *GetBlockAddressSymbol(const MachineOperand &MO) const; +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/AsmPrinter/Makefile b/contrib/llvm/lib/Target/MSP430/AsmPrinter/Makefile new file mode 100644 index 0000000..a5293ab --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/AsmPrinter/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/MSP430/AsmPrinter/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 = LLVMMSP430AsmPrinter + +# Hack: we need to include 'main' MSP430 target directory to grab private headers +CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/Target/MSP430/CMakeLists.txt b/contrib/llvm/lib/Target/MSP430/CMakeLists.txt new file mode 100644 index 0000000..a3f60d2 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_TARGET_DEFINITIONS MSP430.td) + +tablegen(MSP430GenRegisterInfo.h.inc -gen-register-desc-header) +tablegen(MSP430GenRegisterNames.inc -gen-register-enums) +tablegen(MSP430GenRegisterInfo.inc -gen-register-desc) +tablegen(MSP430GenInstrNames.inc -gen-instr-enums) +tablegen(MSP430GenInstrInfo.inc -gen-instr-desc) +tablegen(MSP430GenAsmWriter.inc -gen-asm-writer) +tablegen(MSP430GenDAGISel.inc -gen-dag-isel) +tablegen(MSP430GenCallingConv.inc -gen-callingconv) +tablegen(MSP430GenSubtarget.inc -gen-subtarget) + +add_llvm_target(MSP430CodeGen + MSP430BranchSelector.cpp + MSP430ISelDAGToDAG.cpp + MSP430ISelLowering.cpp + MSP430InstrInfo.cpp + MSP430MCAsmInfo.cpp + MSP430RegisterInfo.cpp + MSP430Subtarget.cpp + MSP430TargetMachine.cpp + MSP430SelectionDAGInfo.cpp + ) + +target_link_libraries (LLVMMSP430CodeGen LLVMSelectionDAG) diff --git a/contrib/llvm/lib/Target/MSP430/MSP430.h b/contrib/llvm/lib/Target/MSP430/MSP430.h new file mode 100644 index 0000000..e742118 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430.h @@ -0,0 +1,55 @@ +//==-- MSP430.h - Top-level interface for MSP430 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 MSP430 backend. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MSP430_H +#define LLVM_TARGET_MSP430_H + +#include "llvm/Target/TargetMachine.h" + +namespace MSP430CC { + // MSP430 specific condition code. + enum CondCodes { + COND_E = 0, // aka COND_Z + COND_NE = 1, // aka COND_NZ + COND_HS = 2, // aka COND_C + COND_LO = 3, // aka COND_NC + COND_GE = 4, + COND_L = 5, + + COND_INVALID = -1 + }; +} + +namespace llvm { + class MSP430TargetMachine; + class FunctionPass; + class formatted_raw_ostream; + + FunctionPass *createMSP430ISelDag(MSP430TargetMachine &TM, + CodeGenOpt::Level OptLevel); + + FunctionPass *createMSP430BranchSelectionPass(); + + extern Target TheMSP430Target; + +} // end namespace llvm; + +// Defines symbolic names for MSP430 registers. +// This defines a mapping from register name to register number. +#include "MSP430GenRegisterNames.inc" + +// Defines symbolic names for the MSP430 instructions. +#include "MSP430GenInstrNames.inc" + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/MSP430.td b/contrib/llvm/lib/Target/MSP430/MSP430.td new file mode 100644 index 0000000..0f08e3d --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430.td @@ -0,0 +1,65 @@ +//===- MSP430.td - Describe the MSP430 Target Machine ---------*- tblgen -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This is the top level entry point for the MSP430 target. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Target-independent interfaces +//===----------------------------------------------------------------------===// + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Subtarget Features. +//===----------------------------------------------------------------------===// +def FeatureX + : SubtargetFeature<"ext", "ExtendedInsts", "true", + "Enable MSP430-X extensions">; + +//===----------------------------------------------------------------------===// +// MSP430 supported processors. +//===----------------------------------------------------------------------===// +class Proc<string Name, list<SubtargetFeature> Features> + : Processor<Name, NoItineraries, Features>; + +def : Proc<"generic", []>; + +//===----------------------------------------------------------------------===// +// Register File Description +//===----------------------------------------------------------------------===// + +include "MSP430RegisterInfo.td" + +//===----------------------------------------------------------------------===// +// Calling Convention Description +//===----------------------------------------------------------------------===// + +include "MSP430CallingConv.td" + +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// + +include "MSP430InstrInfo.td" + +def MSP430InstrInfo : InstrInfo; + +def MSP430InstPrinter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; +} + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def MSP430 : Target { + let InstructionSet = MSP430InstrInfo; + let AssemblyWriters = [MSP430InstPrinter]; +} + diff --git a/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp b/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp new file mode 100644 index 0000000..bd64443 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp @@ -0,0 +1,180 @@ +//===-- MSP430BranchSelector.cpp - Emit long conditional branches--*- 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 a pass that scans a machine function to determine which +// conditional branches need more than 10 bits of displacement to reach their +// target basic block. It does this in two passes; a calculation of basic block +// positions pass, and a branch pseudo op to machine branch opcode pass. This +// pass should be run last, just before the assembly printer. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "msp430-branch-select" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/MathExtras.h" +using namespace llvm; + +STATISTIC(NumExpanded, "Number of branches expanded to long format"); + +namespace { + struct MSP430BSel : public MachineFunctionPass { + static char ID; + MSP430BSel() : MachineFunctionPass(ID) {} + + /// BlockSizes - The sizes of the basic blocks in the function. + std::vector<unsigned> BlockSizes; + + virtual bool runOnMachineFunction(MachineFunction &Fn); + + virtual const char *getPassName() const { + return "MSP430 Branch Selector"; + } + }; + char MSP430BSel::ID = 0; +} + +/// createMSP430BranchSelectionPass - returns an instance of the Branch +/// Selection Pass +/// +FunctionPass *llvm::createMSP430BranchSelectionPass() { + return new MSP430BSel(); +} + +bool MSP430BSel::runOnMachineFunction(MachineFunction &Fn) { + const MSP430InstrInfo *TII = + static_cast<const MSP430InstrInfo*>(Fn.getTarget().getInstrInfo()); + // Give the blocks of the function a dense, in-order, numbering. + Fn.RenumberBlocks(); + BlockSizes.resize(Fn.getNumBlockIDs()); + + // Measure each MBB and compute a size for the entire function. + unsigned FuncSize = 0; + for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; + ++MFI) { + MachineBasicBlock *MBB = MFI; + + unsigned BlockSize = 0; + for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end(); + MBBI != EE; ++MBBI) + BlockSize += TII->GetInstSizeInBytes(MBBI); + + BlockSizes[MBB->getNumber()] = BlockSize; + FuncSize += BlockSize; + } + + // If the entire function is smaller than the displacement of a branch field, + // we know we don't need to shrink any branches in this function. This is a + // common case. + if (FuncSize < (1 << 9)) { + BlockSizes.clear(); + return false; + } + + // For each conditional branch, if the offset to its destination is larger + // than the offset field allows, transform it into a long branch sequence + // like this: + // short branch: + // bCC MBB + // long branch: + // b!CC $PC+6 + // b MBB + // + bool MadeChange = true; + bool EverMadeChange = false; + while (MadeChange) { + // Iteratively expand branches until we reach a fixed point. + MadeChange = false; + + for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; + ++MFI) { + MachineBasicBlock &MBB = *MFI; + unsigned MBBStartOffset = 0; + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E; ++I) { + if ((I->getOpcode() != MSP430::JCC || I->getOperand(0).isImm()) && + I->getOpcode() != MSP430::JMP) { + MBBStartOffset += TII->GetInstSizeInBytes(I); + continue; + } + + // Determine the offset from the current branch to the destination + // block. + MachineBasicBlock *Dest = I->getOperand(0).getMBB(); + + int BranchSize; + if (Dest->getNumber() <= MBB.getNumber()) { + // If this is a backwards branch, the delta is the offset from the + // start of this block to this branch, plus the sizes of all blocks + // from this block to the dest. + BranchSize = MBBStartOffset; + + for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i) + BranchSize += BlockSizes[i]; + } else { + // Otherwise, add the size of the blocks between this block and the + // dest to the number of bytes left in this block. + BranchSize = -MBBStartOffset; + + for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i) + BranchSize += BlockSizes[i]; + } + + // If this branch is in range, ignore it. + if (isInt<10>(BranchSize)) { + MBBStartOffset += 2; + continue; + } + + // Otherwise, we have to expand it to a long branch. + unsigned NewSize; + MachineInstr *OldBranch = I; + DebugLoc dl = OldBranch->getDebugLoc(); + + if (I->getOpcode() == MSP430::JMP) { + NewSize = 4; + } else { + // The BCC operands are: + // 0. MSP430 branch predicate + // 1. Target MBB + SmallVector<MachineOperand, 1> Cond; + Cond.push_back(I->getOperand(1)); + + // Jump over the uncond branch inst (i.e. $+6) on opposite condition. + TII->ReverseBranchCondition(Cond); + BuildMI(MBB, I, dl, TII->get(MSP430::JCC)) + .addImm(4).addOperand(Cond[0]); + + NewSize = 6; + } + // Uncond branch to the real destination. + I = BuildMI(MBB, I, dl, TII->get(MSP430::Bi)).addMBB(Dest); + + // Remove the old branch from the function. + OldBranch->eraseFromParent(); + + // Remember that this instruction is NewSize bytes, increase the size of the + // block by NewSize-2, remember to iterate. + BlockSizes[MBB.getNumber()] += NewSize-2; + MBBStartOffset += NewSize; + + ++NumExpanded; + MadeChange = true; + } + } + EverMadeChange |= MadeChange; + } + + BlockSizes.clear(); + return true; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430CallingConv.td b/contrib/llvm/lib/Target/MSP430/MSP430CallingConv.td new file mode 100644 index 0000000..ad27cc9 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430CallingConv.td @@ -0,0 +1,37 @@ +//==- MSP430CallingConv.td - Calling Conventions for MSP430 -*- 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 MSP430 architecture. +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// MSP430 Return Value Calling Convention +//===----------------------------------------------------------------------===// +def RetCC_MSP430 : CallingConv<[ + // i8 are returned in registers R15B, R14B, R13B, R12B + CCIfType<[i8], CCAssignToReg<[R15B, R14B, R13B, R12B]>>, + + // i16 are returned in registers R15, R14, R13, R12 + CCIfType<[i16], CCAssignToReg<[R15W, R14W, R13W, R12W]>> +]>; + +//===----------------------------------------------------------------------===// +// MSP430 Argument Calling Conventions +//===----------------------------------------------------------------------===// +def CC_MSP430 : CallingConv<[ + // Promote i8 arguments to i16. + CCIfType<[i8], CCPromoteToType<i16>>, + + // The first 4 integer arguments of non-varargs functions are passed in + // integer registers. + CCIfNotVarArg<CCIfType<[i16], CCAssignToReg<[R15W, R14W, R13W, R12W]>>>, + + // Integer values get stored in stack slots that are 2 bytes in + // size and 2-byte aligned. + CCIfType<[i16], CCAssignToStack<2, 2>> +]>; diff --git a/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp new file mode 100644 index 0000000..3395e9f --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -0,0 +1,501 @@ +//===-- MSP430ISelDAGToDAG.cpp - A dag to dag inst selector for MSP430 ----===// +// +// 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 MSP430 target. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "MSP430TargetMachine.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/Constants.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Target/TargetLowering.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; + +namespace { + struct MSP430ISelAddressMode { + enum { + RegBase, + FrameIndexBase + } BaseType; + + struct { // This is really a union, discriminated by BaseType! + SDValue Reg; + int FrameIndex; + } Base; + + int16_t Disp; + const GlobalValue *GV; + const Constant *CP; + const BlockAddress *BlockAddr; + const char *ES; + int JT; + unsigned Align; // CP alignment. + + MSP430ISelAddressMode() + : BaseType(RegBase), Disp(0), GV(0), CP(0), BlockAddr(0), + ES(0), JT(-1), Align(0) { + } + + bool hasSymbolicDisplacement() const { + return GV != 0 || CP != 0 || ES != 0 || JT != -1; + } + + bool hasBaseReg() const { + return Base.Reg.getNode() != 0; + } + + void setBaseReg(SDValue Reg) { + BaseType = RegBase; + Base.Reg = Reg; + } + + void dump() { + errs() << "MSP430ISelAddressMode " << this << '\n'; + if (BaseType == RegBase && Base.Reg.getNode() != 0) { + errs() << "Base.Reg "; + Base.Reg.getNode()->dump(); + } else if (BaseType == FrameIndexBase) { + errs() << " Base.FrameIndex " << Base.FrameIndex << '\n'; + } + errs() << " Disp " << Disp << '\n'; + if (GV) { + errs() << "GV "; + GV->dump(); + } else if (CP) { + errs() << " CP "; + CP->dump(); + errs() << " Align" << Align << '\n'; + } else if (ES) { + errs() << "ES "; + errs() << ES << '\n'; + } else if (JT != -1) + errs() << " JT" << JT << " Align" << Align << '\n'; + } + }; +} + +/// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine +/// instructions for SelectionDAG operations. +/// +namespace { + class MSP430DAGToDAGISel : public SelectionDAGISel { + const MSP430TargetLowering &Lowering; + const MSP430Subtarget &Subtarget; + + public: + MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel), + Lowering(*TM.getTargetLowering()), + Subtarget(*TM.getSubtargetImpl()) { } + + virtual const char *getPassName() const { + return "MSP430 DAG->DAG Pattern Instruction Selection"; + } + + bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM); + bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM); + bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM); + + virtual bool + SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps); + + // Include the pieces autogenerated from the target description. + #include "MSP430GenDAGISel.inc" + + private: + SDNode *Select(SDNode *N); + SDNode *SelectIndexedLoad(SDNode *Op); + SDNode *SelectIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2, + unsigned Opc8, unsigned Opc16); + + bool SelectAddr(SDNode *Op, SDValue Addr, SDValue &Base, SDValue &Disp); + }; +} // end anonymous namespace + +/// createMSP430ISelDag - This pass converts a legalized DAG into a +/// MSP430-specific DAG, ready for instruction scheduling. +/// +FunctionPass *llvm::createMSP430ISelDag(MSP430TargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new MSP430DAGToDAGISel(TM, OptLevel); +} + + +/// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode. +/// These wrap things that will resolve down into a symbol reference. If no +/// match is possible, this returns true, otherwise it returns false. +bool MSP430DAGToDAGISel::MatchWrapper(SDValue N, MSP430ISelAddressMode &AM) { + // If the addressing mode already has a symbol as the displacement, we can + // never match another symbol. + if (AM.hasSymbolicDisplacement()) + return true; + + SDValue N0 = N.getOperand(0); + + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) { + AM.GV = G->getGlobal(); + AM.Disp += G->getOffset(); + //AM.SymbolFlags = G->getTargetFlags(); + } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) { + AM.CP = CP->getConstVal(); + AM.Align = CP->getAlignment(); + AM.Disp += CP->getOffset(); + //AM.SymbolFlags = CP->getTargetFlags(); + } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(N0)) { + AM.ES = S->getSymbol(); + //AM.SymbolFlags = S->getTargetFlags(); + } else if (JumpTableSDNode *J = dyn_cast<JumpTableSDNode>(N0)) { + AM.JT = J->getIndex(); + //AM.SymbolFlags = J->getTargetFlags(); + } else { + AM.BlockAddr = cast<BlockAddressSDNode>(N0)->getBlockAddress(); + //AM.SymbolFlags = cast<BlockAddressSDNode>(N0)->getTargetFlags(); + } + return false; +} + +/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the +/// specified addressing mode without any further recursion. +bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM) { + // Is the base register already occupied? + if (AM.BaseType != MSP430ISelAddressMode::RegBase || AM.Base.Reg.getNode()) { + // If so, we cannot select it. + return true; + } + + // Default, generate it as a register. + AM.BaseType = MSP430ISelAddressMode::RegBase; + AM.Base.Reg = N; + return false; +} + +bool MSP430DAGToDAGISel::MatchAddress(SDValue N, MSP430ISelAddressMode &AM) { + DEBUG(errs() << "MatchAddress: "; AM.dump()); + + switch (N.getOpcode()) { + default: break; + case ISD::Constant: { + uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); + AM.Disp += Val; + return false; + } + + case MSP430ISD::Wrapper: + if (!MatchWrapper(N, AM)) + return false; + break; + + case ISD::FrameIndex: + if (AM.BaseType == MSP430ISelAddressMode::RegBase + && AM.Base.Reg.getNode() == 0) { + AM.BaseType = MSP430ISelAddressMode::FrameIndexBase; + AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex(); + return false; + } + break; + + case ISD::ADD: { + MSP430ISelAddressMode Backup = AM; + if (!MatchAddress(N.getNode()->getOperand(0), AM) && + !MatchAddress(N.getNode()->getOperand(1), AM)) + return false; + AM = Backup; + if (!MatchAddress(N.getNode()->getOperand(1), AM) && + !MatchAddress(N.getNode()->getOperand(0), AM)) + return false; + AM = Backup; + + break; + } + + case ISD::OR: + // Handle "X | C" as "X + C" iff X is known to have C bits clear. + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) { + MSP430ISelAddressMode Backup = AM; + uint64_t Offset = CN->getSExtValue(); + // Start with the LHS as an addr mode. + if (!MatchAddress(N.getOperand(0), AM) && + // Address could not have picked a GV address for the displacement. + AM.GV == NULL && + // Check to see if the LHS & C is zero. + CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { + AM.Disp += Offset; + return false; + } + AM = Backup; + } + break; + } + + return MatchAddressBase(N, AM); +} + +/// SelectAddr - returns true if it is able pattern match an addressing mode. +/// It returns the operands which make up the maximal addressing mode it can +/// match by reference. +bool MSP430DAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, + SDValue &Base, SDValue &Disp) { + MSP430ISelAddressMode AM; + + if (MatchAddress(N, AM)) + return false; + + EVT VT = N.getValueType(); + if (AM.BaseType == MSP430ISelAddressMode::RegBase) { + if (!AM.Base.Reg.getNode()) + AM.Base.Reg = CurDAG->getRegister(0, VT); + } + + Base = (AM.BaseType == MSP430ISelAddressMode::FrameIndexBase) ? + CurDAG->getTargetFrameIndex(AM.Base.FrameIndex, TLI.getPointerTy()) : + AM.Base.Reg; + + if (AM.GV) + Disp = CurDAG->getTargetGlobalAddress(AM.GV, Op->getDebugLoc(), + MVT::i16, AM.Disp, + 0/*AM.SymbolFlags*/); + else if (AM.CP) + Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i16, + AM.Align, AM.Disp, 0/*AM.SymbolFlags*/); + else if (AM.ES) + Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i16, 0/*AM.SymbolFlags*/); + else if (AM.JT != -1) + Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i16, 0/*AM.SymbolFlags*/); + else if (AM.BlockAddr) + Disp = CurDAG->getBlockAddress(AM.BlockAddr, MVT::i32, + true, 0/*AM.SymbolFlags*/); + else + Disp = CurDAG->getTargetConstant(AM.Disp, MVT::i16); + + return true; +} + +bool MSP430DAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps) { + SDValue Op0, Op1; + switch (ConstraintCode) { + default: return true; + case 'm': // memory + if (!SelectAddr(Op.getNode(), Op, Op0, Op1)) + return true; + break; + } + + OutOps.push_back(Op0); + OutOps.push_back(Op1); + return false; +} + +static bool isValidIndexedLoad(const LoadSDNode *LD) { + ISD::MemIndexedMode AM = LD->getAddressingMode(); + if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD) + return false; + + EVT VT = LD->getMemoryVT(); + + switch (VT.getSimpleVT().SimpleTy) { + case MVT::i8: + // Sanity check + if (cast<ConstantSDNode>(LD->getOffset())->getZExtValue() != 1) + return false; + + break; + case MVT::i16: + // Sanity check + if (cast<ConstantSDNode>(LD->getOffset())->getZExtValue() != 2) + return false; + + break; + default: + return false; + } + + return true; +} + +SDNode *MSP430DAGToDAGISel::SelectIndexedLoad(SDNode *N) { + LoadSDNode *LD = cast<LoadSDNode>(N); + if (!isValidIndexedLoad(LD)) + return NULL; + + MVT VT = LD->getMemoryVT().getSimpleVT(); + + unsigned Opcode = 0; + switch (VT.SimpleTy) { + case MVT::i8: + Opcode = MSP430::MOV8rm_POST; + break; + case MVT::i16: + Opcode = MSP430::MOV16rm_POST; + break; + default: + return NULL; + } + + return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), + VT, MVT::i16, MVT::Other, + LD->getBasePtr(), LD->getChain()); +} + +SDNode *MSP430DAGToDAGISel::SelectIndexedBinOp(SDNode *Op, + SDValue N1, SDValue N2, + unsigned Opc8, unsigned Opc16) { + if (N1.getOpcode() == ISD::LOAD && + N1.hasOneUse() && + IsLegalToFold(N1, Op, Op, OptLevel)) { + LoadSDNode *LD = cast<LoadSDNode>(N1); + if (!isValidIndexedLoad(LD)) + return NULL; + + MVT VT = LD->getMemoryVT().getSimpleVT(); + unsigned Opc = (VT == MVT::i16 ? Opc16 : Opc8); + MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1); + MemRefs0[0] = cast<MemSDNode>(N1)->getMemOperand(); + SDValue Ops0[] = { N2, LD->getBasePtr(), LD->getChain() }; + SDNode *ResNode = + CurDAG->SelectNodeTo(Op, Opc, + VT, MVT::i16, MVT::Other, + Ops0, 3); + cast<MachineSDNode>(ResNode)->setMemRefs(MemRefs0, MemRefs0 + 1); + // Transfer chain. + ReplaceUses(SDValue(N1.getNode(), 2), SDValue(ResNode, 2)); + // Transfer writeback. + ReplaceUses(SDValue(N1.getNode(), 1), SDValue(ResNode, 1)); + return ResNode; + } + + return NULL; +} + + +SDNode *MSP430DAGToDAGISel::Select(SDNode *Node) { + DebugLoc dl = Node->getDebugLoc(); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "); + DEBUG(Node->dump(CurDAG)); + DEBUG(errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; + Node->dump(CurDAG); + errs() << "\n"); + return NULL; + } + + // Few custom selection stuff. + switch (Node->getOpcode()) { + default: break; + case ISD::FrameIndex: { + assert(Node->getValueType(0) == MVT::i16); + int FI = cast<FrameIndexSDNode>(Node)->getIndex(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i16); + if (Node->hasOneUse()) + return CurDAG->SelectNodeTo(Node, MSP430::ADD16ri, MVT::i16, + TFI, CurDAG->getTargetConstant(0, MVT::i16)); + return CurDAG->getMachineNode(MSP430::ADD16ri, dl, MVT::i16, + TFI, CurDAG->getTargetConstant(0, MVT::i16)); + } + case ISD::LOAD: + if (SDNode *ResNode = SelectIndexedLoad(Node)) + return ResNode; + // Other cases are autogenerated. + break; + case ISD::ADD: + if (SDNode *ResNode = + SelectIndexedBinOp(Node, + Node->getOperand(0), Node->getOperand(1), + MSP430::ADD8rm_POST, MSP430::ADD16rm_POST)) + return ResNode; + else if (SDNode *ResNode = + SelectIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), + MSP430::ADD8rm_POST, MSP430::ADD16rm_POST)) + return ResNode; + + // Other cases are autogenerated. + break; + case ISD::SUB: + if (SDNode *ResNode = + SelectIndexedBinOp(Node, + Node->getOperand(0), Node->getOperand(1), + MSP430::SUB8rm_POST, MSP430::SUB16rm_POST)) + return ResNode; + + // Other cases are autogenerated. + break; + case ISD::AND: + if (SDNode *ResNode = + SelectIndexedBinOp(Node, + Node->getOperand(0), Node->getOperand(1), + MSP430::AND8rm_POST, MSP430::AND16rm_POST)) + return ResNode; + else if (SDNode *ResNode = + SelectIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), + MSP430::AND8rm_POST, MSP430::AND16rm_POST)) + return ResNode; + + // Other cases are autogenerated. + break; + case ISD::OR: + if (SDNode *ResNode = + SelectIndexedBinOp(Node, + Node->getOperand(0), Node->getOperand(1), + MSP430::OR8rm_POST, MSP430::OR16rm_POST)) + return ResNode; + else if (SDNode *ResNode = + SelectIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), + MSP430::OR8rm_POST, MSP430::OR16rm_POST)) + return ResNode; + + // Other cases are autogenerated. + break; + case ISD::XOR: + if (SDNode *ResNode = + SelectIndexedBinOp(Node, + Node->getOperand(0), Node->getOperand(1), + MSP430::XOR8rm_POST, MSP430::XOR16rm_POST)) + return ResNode; + else if (SDNode *ResNode = + SelectIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), + MSP430::XOR8rm_POST, MSP430::XOR16rm_POST)) + return ResNode; + + // Other cases are autogenerated. + break; + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Node); + + DEBUG(errs() << "=> "); + if (ResNode == NULL || ResNode == Node) + DEBUG(Node->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DEBUG(errs() << "\n"); + + return ResNode; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp new file mode 100644 index 0000000..a1703a3 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -0,0 +1,1203 @@ +//===-- MSP430ISelLowering.cpp - MSP430 DAG Lowering Implementation ------===// +// +// 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 MSP430TargetLowering class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "msp430-lower" + +#include "MSP430ISelLowering.h" +#include "MSP430.h" +#include "MSP430MachineFunctionInfo.h" +#include "MSP430TargetMachine.h" +#include "MSP430Subtarget.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/Intrinsics.h" +#include "llvm/CallingConv.h" +#include "llvm/GlobalVariable.h" +#include "llvm/GlobalAlias.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/VectorExtras.h" +using namespace llvm; + +typedef enum { + NoHWMult, + HWMultIntr, + HWMultNoIntr +} HWMultUseMode; + +static cl::opt<HWMultUseMode> +HWMultMode("msp430-hwmult-mode", + cl::desc("Hardware multiplier use mode"), + cl::init(HWMultNoIntr), + cl::values( + clEnumValN(NoHWMult, "no", + "Do not use hardware multiplier"), + clEnumValN(HWMultIntr, "interrupts", + "Assume hardware multiplier can be used inside interrupts"), + clEnumValN(HWMultNoIntr, "use", + "Assume hardware multiplier cannot be used inside interrupts"), + clEnumValEnd)); + +MSP430TargetLowering::MSP430TargetLowering(MSP430TargetMachine &tm) : + TargetLowering(tm, new TargetLoweringObjectFileELF()), + Subtarget(*tm.getSubtargetImpl()), TM(tm) { + + TD = getTargetData(); + + // Set up the register classes. + addRegisterClass(MVT::i8, MSP430::GR8RegisterClass); + addRegisterClass(MVT::i16, MSP430::GR16RegisterClass); + + // Compute derived properties from the register classes + computeRegisterProperties(); + + // Provide all sorts of operation actions + + // Division is expensive + setIntDivIsCheap(false); + + // Even if we have only 1 bit shift here, we can perform + // shifts of the whole bitwidth 1 bit per step. + setShiftAmountType(MVT::i8); + + setStackPointerRegisterToSaveRestore(MSP430::SPW); + setBooleanContents(ZeroOrOneBooleanContent); + setSchedulingPreference(Sched::Latency); + + // We have post-incremented loads / stores. + setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal); + setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal); + + setLoadExtAction(ISD::EXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, MVT::i16, Expand); + + // We don't have any truncstores + setTruncStoreAction(MVT::i16, MVT::i8, Expand); + + setOperationAction(ISD::SRA, MVT::i8, Custom); + setOperationAction(ISD::SHL, MVT::i8, Custom); + setOperationAction(ISD::SRL, MVT::i8, Custom); + setOperationAction(ISD::SRA, MVT::i16, Custom); + setOperationAction(ISD::SHL, MVT::i16, Custom); + setOperationAction(ISD::SRL, MVT::i16, Custom); + setOperationAction(ISD::ROTL, MVT::i8, Expand); + setOperationAction(ISD::ROTR, MVT::i8, Expand); + setOperationAction(ISD::ROTL, MVT::i16, Expand); + setOperationAction(ISD::ROTR, MVT::i16, Expand); + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom); + setOperationAction(ISD::BlockAddress, MVT::i16, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::i8, Custom); + setOperationAction(ISD::BR_CC, MVT::i16, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::SETCC, MVT::i8, Custom); + setOperationAction(ISD::SETCC, MVT::i16, Custom); + setOperationAction(ISD::SELECT, MVT::i8, Expand); + setOperationAction(ISD::SELECT, MVT::i16, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i8, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i16, Custom); + setOperationAction(ISD::SIGN_EXTEND, MVT::i16, Custom); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand); + + setOperationAction(ISD::CTTZ, MVT::i8, Expand); + setOperationAction(ISD::CTTZ, MVT::i16, Expand); + setOperationAction(ISD::CTLZ, MVT::i8, Expand); + setOperationAction(ISD::CTLZ, MVT::i16, Expand); + setOperationAction(ISD::CTPOP, MVT::i8, Expand); + setOperationAction(ISD::CTPOP, MVT::i16, Expand); + + setOperationAction(ISD::SHL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i8, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + // FIXME: Implement efficiently multiplication by a constant + setOperationAction(ISD::MUL, MVT::i8, Expand); + setOperationAction(ISD::MULHS, MVT::i8, Expand); + setOperationAction(ISD::MULHU, MVT::i8, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand); + setOperationAction(ISD::MUL, MVT::i16, Expand); + setOperationAction(ISD::MULHS, MVT::i16, Expand); + setOperationAction(ISD::MULHU, MVT::i16, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); + + setOperationAction(ISD::UDIV, MVT::i8, Expand); + setOperationAction(ISD::UDIVREM, MVT::i8, Expand); + setOperationAction(ISD::UREM, MVT::i8, Expand); + setOperationAction(ISD::SDIV, MVT::i8, Expand); + setOperationAction(ISD::SDIVREM, MVT::i8, Expand); + setOperationAction(ISD::SREM, MVT::i8, Expand); + setOperationAction(ISD::UDIV, MVT::i16, Expand); + setOperationAction(ISD::UDIVREM, MVT::i16, Expand); + setOperationAction(ISD::UREM, MVT::i16, Expand); + setOperationAction(ISD::SDIV, MVT::i16, Expand); + setOperationAction(ISD::SDIVREM, MVT::i16, Expand); + setOperationAction(ISD::SREM, MVT::i16, Expand); + + // Libcalls names. + if (HWMultMode == HWMultIntr) { + setLibcallName(RTLIB::MUL_I8, "__mulqi3hw"); + setLibcallName(RTLIB::MUL_I16, "__mulhi3hw"); + } else if (HWMultMode == HWMultNoIntr) { + setLibcallName(RTLIB::MUL_I8, "__mulqi3hw_noint"); + setLibcallName(RTLIB::MUL_I16, "__mulhi3hw_noint"); + } +} + +SDValue MSP430TargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::SHL: // FALLTHROUGH + case ISD::SRL: + case ISD::SRA: return LowerShifts(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); + case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); + case ISD::BR_CC: return LowerBR_CC(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::SIGN_EXTEND: return LowerSIGN_EXTEND(Op, DAG); + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); + case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + default: + llvm_unreachable("unimplemented operand"); + return SDValue(); + } +} + +/// getFunctionAlignment - Return the Log2 alignment of this function. +unsigned MSP430TargetLowering::getFunctionAlignment(const Function *F) const { + return F->hasFnAttr(Attribute::OptimizeForSize) ? 1 : 2; +} + +//===----------------------------------------------------------------------===// +// MSP430 Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +TargetLowering::ConstraintType +MSP430TargetLowering::getConstraintType(const std::string &Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return C_RegisterClass; + default: + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +std::pair<unsigned, const TargetRegisterClass*> +MSP430TargetLowering:: +getRegForInlineAsmConstraint(const std::string &Constraint, + EVT VT) const { + if (Constraint.size() == 1) { + // GCC Constraint Letters + switch (Constraint[0]) { + default: break; + case 'r': // GENERAL_REGS + if (VT == MVT::i8) + return std::make_pair(0U, MSP430::GR8RegisterClass); + + return std::make_pair(0U, MSP430::GR16RegisterClass); + } + } + + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "MSP430GenCallingConv.inc" + +SDValue +MSP430TargetLowering::LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Chain, CallConv, isVarArg, Ins, dl, DAG, InVals); + case CallingConv::MSP430_INTR: + if (Ins.empty()) + return Chain; + else { + report_fatal_error("ISRs cannot have arguments"); + return SDValue(); + } + } +} + +SDValue +MSP430TargetLowering::LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // MSP430 target does not yet support tail call optimization. + isTailCall = false; + + switch (CallConv) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Chain, Callee, CallConv, isVarArg, isTailCall, + Outs, OutVals, Ins, dl, DAG, InVals); + case CallingConv::MSP430_INTR: + report_fatal_error("ISRs cannot be called directly"); + return SDValue(); + } +} + +/// LowerCCCArguments - transform physical registers into virtual registers and +/// generate load operations for arguments places on the stack. +// FIXME: struct return stuff +// FIXME: varargs +SDValue +MSP430TargetLowering::LowerCCCArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> + &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_MSP430); + + assert(!isVarArg && "Varargs not supported yet"); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // Arguments passed in registers + EVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT().SimpleTy) { + default: + { +#ifndef NDEBUG + errs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getSimpleVT().SimpleTy << "\n"; +#endif + llvm_unreachable(0); + } + case MVT::i16: + unsigned VReg = + RegInfo.createVirtualRegister(MSP430::GR16RegisterClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, VReg, RegVT); + + // If this is an 8-bit value, it is really passed promoted to 16 + // bits. Insert an assert[sz]ext to capture this, then truncate to the + // right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + + InVals.push_back(ArgValue); + } + } else { + // Sanity check + assert(VA.isMemLoc()); + // Load the argument to a virtual register + unsigned ObjSize = VA.getLocVT().getSizeInBits()/8; + if (ObjSize > 2) { + errs() << "LowerFormalArguments Unhandled argument type: " + << VA.getLocVT().getSimpleVT().SimpleTy + << "\n"; + } + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load + //from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i16); + InVals.push_back(DAG.getLoad(VA.getLocVT(), dl, Chain, FIN, + PseudoSourceValue::getFixedStack(FI), 0, + false, false, 0)); + } + } + + return Chain; +} + +SDValue +MSP430TargetLowering::LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const { + + // CCValAssign - represent the assignment of the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + + // ISRs cannot return any value. + if (CallConv == CallingConv::MSP430_INTR && !Outs.empty()) { + report_fatal_error("ISRs cannot return any value"); + return SDValue(); + } + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, RetCC_MSP430); + + // If this is the first return lowered for this function, add the regs to the + // liveout set for the function. + if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { + for (unsigned i = 0; i != RVLocs.size(); ++i) + if (RVLocs[i].isRegLoc()) + DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); + } + + SDValue Flag; + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + } + + unsigned Opc = (CallConv == CallingConv::MSP430_INTR ? + MSP430ISD::RETI_FLAG : MSP430ISD::RET_FLAG); + + if (Flag.getNode()) + return DAG.getNode(Opc, dl, MVT::Other, Chain, Flag); + + // Return Void + return DAG.getNode(Opc, dl, MVT::Other, Chain); +} + +/// LowerCCCCallTo - functions arguments are copied from virtual regs to +/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. +/// TODO: sret. +SDValue +MSP430TargetLowering::LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, + const SmallVectorImpl<ISD::OutputArg> + &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + ArgLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallOperands(Outs, CC_MSP430); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = CCInfo.getNextStackOffset(); + + Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes, + getPointerTy(), true)); + + SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; + SmallVector<SDValue, 12> MemOpChains; + SDValue StackPtr; + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); + break; + } + + // Arguments that can be passed on register must be kept at RegsToPass + // vector + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + + if (StackPtr.getNode() == 0) + StackPtr = DAG.getCopyFromReg(Chain, dl, MSP430::SPW, getPointerTy()); + + SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), + StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset())); + + + MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, + PseudoSourceValue::getStack(), + VA.getLocMemOffset(), false, false, 0)); + } + } + + // Transform all store nodes into one single node because all store nodes are + // independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, + &MemOpChains[0], MemOpChains.size()); + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InFlag in + // necessary since all emited instructions must be stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i16); + else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i16); + + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + SmallVector<SDValue, 8> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + Chain = DAG.getNode(MSP430ISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, + DAG.getConstant(NumBytes, getPointerTy(), true), + DAG.getConstant(0, getPointerTy(), true), + InFlag); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, + DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +/// +SDValue +MSP430TargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const { + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_MSP430); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +SDValue MSP430TargetLowering::LowerShifts(SDValue Op, + SelectionDAG &DAG) const { + unsigned Opc = Op.getOpcode(); + SDNode* N = Op.getNode(); + EVT VT = Op.getValueType(); + DebugLoc dl = N->getDebugLoc(); + + // Expand non-constant shifts to loops: + if (!isa<ConstantSDNode>(N->getOperand(1))) + switch (Opc) { + default: + assert(0 && "Invalid shift opcode!"); + case ISD::SHL: + return DAG.getNode(MSP430ISD::SHL, dl, + VT, N->getOperand(0), N->getOperand(1)); + case ISD::SRA: + return DAG.getNode(MSP430ISD::SRA, dl, + VT, N->getOperand(0), N->getOperand(1)); + case ISD::SRL: + return DAG.getNode(MSP430ISD::SRL, dl, + VT, N->getOperand(0), N->getOperand(1)); + } + + uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); + + // Expand the stuff into sequence of shifts. + // FIXME: for some shift amounts this might be done better! + // E.g.: foo >> (8 + N) => sxt(swpb(foo)) >> N + SDValue Victim = N->getOperand(0); + + if (Opc == ISD::SRL && ShiftAmount) { + // Emit a special goodness here: + // srl A, 1 => clrc; rrc A + Victim = DAG.getNode(MSP430ISD::RRC, dl, VT, Victim); + ShiftAmount -= 1; + } + + while (ShiftAmount--) + Victim = DAG.getNode((Opc == ISD::SHL ? MSP430ISD::RLA : MSP430ISD::RRA), + dl, VT, Victim); + + return Victim; +} + +SDValue MSP430TargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); + int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset(); + + // Create the TargetGlobalAddress node, folding in the constant offset. + SDValue Result = DAG.getTargetGlobalAddress(GV, Op.getDebugLoc(), + getPointerTy(), Offset); + return DAG.getNode(MSP430ISD::Wrapper, Op.getDebugLoc(), + getPointerTy(), Result); +} + +SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + const char *Sym = cast<ExternalSymbolSDNode>(Op)->getSymbol(); + SDValue Result = DAG.getTargetExternalSymbol(Sym, getPointerTy()); + + return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);; +} + +SDValue MSP430TargetLowering::LowerBlockAddress(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress(); + SDValue Result = DAG.getBlockAddress(BA, getPointerTy(), /*isTarget=*/true); + + return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);; +} + +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC, + ISD::CondCode CC, + DebugLoc dl, SelectionDAG &DAG) { + // FIXME: Handle bittests someday + assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet"); + + // FIXME: Handle jump negative someday + MSP430CC::CondCodes TCC = MSP430CC::COND_INVALID; + switch (CC) { + default: llvm_unreachable("Invalid integer condition!"); + case ISD::SETEQ: + TCC = MSP430CC::COND_E; // aka COND_Z + // Minor optimization: if LHS is a constant, swap operands, then the + // constant can be folded into comparison. + if (LHS.getOpcode() == ISD::Constant) + std::swap(LHS, RHS); + break; + case ISD::SETNE: + TCC = MSP430CC::COND_NE; // aka COND_NZ + // Minor optimization: if LHS is a constant, swap operands, then the + // constant can be folded into comparison. + if (LHS.getOpcode() == ISD::Constant) + std::swap(LHS, RHS); + break; + case ISD::SETULE: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETUGE: + // Turn lhs u>= rhs with lhs constant into rhs u< lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_LO; + break; + } + TCC = MSP430CC::COND_HS; // aka COND_C + break; + case ISD::SETUGT: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETULT: + // Turn lhs u< rhs with lhs constant into rhs u>= lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_HS; + break; + } + TCC = MSP430CC::COND_LO; // aka COND_NC + break; + case ISD::SETLE: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETGE: + // Turn lhs >= rhs with lhs constant into rhs < lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_L; + break; + } + TCC = MSP430CC::COND_GE; + break; + case ISD::SETGT: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETLT: + // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast<ConstantSDNode>(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_GE; + break; + } + TCC = MSP430CC::COND_L; + break; + } + + TargetCC = DAG.getConstant(TCC, MVT::i8); + return DAG.getNode(MSP430ISD::CMP, dl, MVT::Flag, LHS, RHS); +} + + +SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + DebugLoc dl = Op.getDebugLoc(); + + SDValue TargetCC; + SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); + + return DAG.getNode(MSP430ISD::BR_CC, dl, Op.getValueType(), + Chain, Dest, TargetCC, Flag); +} + +SDValue MSP430TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + DebugLoc dl = Op.getDebugLoc(); + + // If we are doing an AND and testing against zero, then the CMP + // will not be generated. The AND (or BIT) will generate the condition codes, + // but they are different from CMP. + // FIXME: since we're doing a post-processing, use a pseudoinstr here, so + // lowering & isel wouldn't diverge. + bool andCC = false; + if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) { + if (RHSC->isNullValue() && LHS.hasOneUse() && + (LHS.getOpcode() == ISD::AND || + (LHS.getOpcode() == ISD::TRUNCATE && + LHS.getOperand(0).getOpcode() == ISD::AND))) { + andCC = true; + } + } + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get(); + SDValue TargetCC; + SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); + + // Get the condition codes directly from the status register, if its easy. + // Otherwise a branch will be generated. Note that the AND and BIT + // instructions generate different flags than CMP, the carry bit can be used + // for NE/EQ. + bool Invert = false; + bool Shift = false; + bool Convert = true; + switch (cast<ConstantSDNode>(TargetCC)->getZExtValue()) { + default: + Convert = false; + break; + case MSP430CC::COND_HS: + // Res = SRW & 1, no processing is required + break; + case MSP430CC::COND_LO: + // Res = ~(SRW & 1) + Invert = true; + break; + case MSP430CC::COND_NE: + if (andCC) { + // C = ~Z, thus Res = SRW & 1, no processing is required + } else { + // Res = ~((SRW >> 1) & 1) + Shift = true; + Invert = true; + } + break; + case MSP430CC::COND_E: + Shift = true; + // C = ~Z for AND instruction, thus we can put Res = ~(SRW & 1), however, + // Res = (SRW >> 1) & 1 is 1 word shorter. + break; + } + EVT VT = Op.getValueType(); + SDValue One = DAG.getConstant(1, VT); + if (Convert) { + SDValue SR = DAG.getCopyFromReg(DAG.getEntryNode(), dl, MSP430::SRW, + MVT::i16, Flag); + if (Shift) + // FIXME: somewhere this is turned into a SRL, lower it MSP specific? + SR = DAG.getNode(ISD::SRA, dl, MVT::i16, SR, One); + SR = DAG.getNode(ISD::AND, dl, MVT::i16, SR, One); + if (Invert) + SR = DAG.getNode(ISD::XOR, dl, MVT::i16, SR, One); + return SR; + } else { + SDValue Zero = DAG.getConstant(0, VT); + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); + SmallVector<SDValue, 4> Ops; + Ops.push_back(One); + Ops.push_back(Zero); + Ops.push_back(TargetCC); + Ops.push_back(Flag); + return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); + } +} + +SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, + SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueV = Op.getOperand(2); + SDValue FalseV = Op.getOperand(3); + ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); + DebugLoc dl = Op.getDebugLoc(); + + SDValue TargetCC; + SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); + SmallVector<SDValue, 4> Ops; + Ops.push_back(TrueV); + Ops.push_back(FalseV); + Ops.push_back(TargetCC); + Ops.push_back(Flag); + + return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); +} + +SDValue MSP430TargetLowering::LowerSIGN_EXTEND(SDValue Op, + SelectionDAG &DAG) const { + SDValue Val = Op.getOperand(0); + EVT VT = Op.getValueType(); + DebugLoc dl = Op.getDebugLoc(); + + assert(VT == MVT::i16 && "Only support i16 for now!"); + + return DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, VT, + DAG.getNode(ISD::ANY_EXTEND, dl, VT, Val), + DAG.getValueType(Val.getValueType())); +} + +SDValue +MSP430TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + MSP430MachineFunctionInfo *FuncInfo = MF.getInfo<MSP430MachineFunctionInfo>(); + int ReturnAddrIndex = FuncInfo->getRAIndex(); + + if (ReturnAddrIndex == 0) { + // Set up a frame object for the return address. + uint64_t SlotSize = TD->getPointerSize(); + ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(SlotSize, -SlotSize, + true); + FuncInfo->setRAIndex(ReturnAddrIndex); + } + + return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy()); +} + +SDValue MSP430TargetLowering::LowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setReturnAddressIsTaken(true); + + unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + DebugLoc dl = Op.getDebugLoc(); + + if (Depth > 0) { + SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); + SDValue Offset = + DAG.getConstant(TD->getPointerSize(), MVT::i16); + return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), + DAG.getNode(ISD::ADD, dl, getPointerTy(), + FrameAddr, Offset), + NULL, 0, false, false, 0); + } + + // Just load the return address. + SDValue RetAddrFI = getReturnAddressFrameIndex(DAG); + return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), + RetAddrFI, NULL, 0, false, false, 0); +} + +SDValue MSP430TargetLowering::LowerFRAMEADDR(SDValue Op, + SelectionDAG &DAG) const { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + + EVT VT = Op.getValueType(); + DebugLoc dl = Op.getDebugLoc(); // FIXME probably not meaningful + unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, + MSP430::FPW, VT); + while (Depth--) + FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, NULL, 0, + false, false, 0); + return FrameAddr; +} + +/// getPostIndexedAddressParts - returns true by value, base pointer and +/// offset pointer and addressing mode by reference if this node can be +/// combined with a load / store to form a post-indexed load / store. +bool MSP430TargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op, + SDValue &Base, + SDValue &Offset, + ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const { + + LoadSDNode *LD = cast<LoadSDNode>(N); + if (LD->getExtensionType() != ISD::NON_EXTLOAD) + return false; + + EVT VT = LD->getMemoryVT(); + if (VT != MVT::i8 && VT != MVT::i16) + return false; + + if (Op->getOpcode() != ISD::ADD) + return false; + + if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) { + uint64_t RHSC = RHS->getZExtValue(); + if ((VT == MVT::i16 && RHSC != 2) || + (VT == MVT::i8 && RHSC != 1)) + return false; + + Base = Op->getOperand(0); + Offset = DAG.getConstant(RHSC, VT); + AM = ISD::POST_INC; + return true; + } + + return false; +} + + +const char *MSP430TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return NULL; + case MSP430ISD::RET_FLAG: return "MSP430ISD::RET_FLAG"; + case MSP430ISD::RETI_FLAG: return "MSP430ISD::RETI_FLAG"; + case MSP430ISD::RRA: return "MSP430ISD::RRA"; + case MSP430ISD::RLA: return "MSP430ISD::RLA"; + case MSP430ISD::RRC: return "MSP430ISD::RRC"; + case MSP430ISD::CALL: return "MSP430ISD::CALL"; + case MSP430ISD::Wrapper: return "MSP430ISD::Wrapper"; + case MSP430ISD::BR_CC: return "MSP430ISD::BR_CC"; + case MSP430ISD::CMP: return "MSP430ISD::CMP"; + case MSP430ISD::SELECT_CC: return "MSP430ISD::SELECT_CC"; + case MSP430ISD::SHL: return "MSP430ISD::SHL"; + case MSP430ISD::SRA: return "MSP430ISD::SRA"; + } +} + +bool MSP430TargetLowering::isTruncateFree(const Type *Ty1, + const Type *Ty2) const { + if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy()) + return false; + + return (Ty1->getPrimitiveSizeInBits() > Ty2->getPrimitiveSizeInBits()); +} + +bool MSP430TargetLowering::isTruncateFree(EVT VT1, EVT VT2) const { + if (!VT1.isInteger() || !VT2.isInteger()) + return false; + + return (VT1.getSizeInBits() > VT2.getSizeInBits()); +} + +bool MSP430TargetLowering::isZExtFree(const Type *Ty1, const Type *Ty2) const { + // MSP430 implicitly zero-extends 8-bit results in 16-bit registers. + return 0 && Ty1->isIntegerTy(8) && Ty2->isIntegerTy(16); +} + +bool MSP430TargetLowering::isZExtFree(EVT VT1, EVT VT2) const { + // MSP430 implicitly zero-extends 8-bit results in 16-bit registers. + return 0 && VT1 == MVT::i8 && VT2 == MVT::i16; +} + +//===----------------------------------------------------------------------===// +// Other Lowering Code +//===----------------------------------------------------------------------===// + +MachineBasicBlock* +MSP430TargetLowering::EmitShiftInstr(MachineInstr *MI, + MachineBasicBlock *BB) const { + MachineFunction *F = BB->getParent(); + MachineRegisterInfo &RI = F->getRegInfo(); + DebugLoc dl = MI->getDebugLoc(); + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + + unsigned Opc; + const TargetRegisterClass * RC; + switch (MI->getOpcode()) { + default: + assert(0 && "Invalid shift opcode!"); + case MSP430::Shl8: + Opc = MSP430::SHL8r1; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Shl16: + Opc = MSP430::SHL16r1; + RC = MSP430::GR16RegisterClass; + break; + case MSP430::Sra8: + Opc = MSP430::SAR8r1; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Sra16: + Opc = MSP430::SAR16r1; + RC = MSP430::GR16RegisterClass; + break; + case MSP430::Srl8: + Opc = MSP430::SAR8r1c; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Srl16: + Opc = MSP430::SAR16r1c; + RC = MSP430::GR16RegisterClass; + break; + } + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = BB; + ++I; + + // Create loop block + MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(I, LoopBB); + F->insert(I, RemBB); + + // Update machine-CFG edges by transferring all successors of the current + // block to the block containing instructions after shift. + RemBB->splice(RemBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + RemBB->transferSuccessorsAndUpdatePHIs(BB); + + // Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB + BB->addSuccessor(LoopBB); + BB->addSuccessor(RemBB); + LoopBB->addSuccessor(RemBB); + LoopBB->addSuccessor(LoopBB); + + unsigned ShiftAmtReg = RI.createVirtualRegister(MSP430::GR8RegisterClass); + unsigned ShiftAmtReg2 = RI.createVirtualRegister(MSP430::GR8RegisterClass); + unsigned ShiftReg = RI.createVirtualRegister(RC); + unsigned ShiftReg2 = RI.createVirtualRegister(RC); + unsigned ShiftAmtSrcReg = MI->getOperand(2).getReg(); + unsigned SrcReg = MI->getOperand(1).getReg(); + unsigned DstReg = MI->getOperand(0).getReg(); + + // BB: + // cmp 0, N + // je RemBB + BuildMI(BB, dl, TII.get(MSP430::CMP8ri)) + .addReg(ShiftAmtSrcReg).addImm(0); + BuildMI(BB, dl, TII.get(MSP430::JCC)) + .addMBB(RemBB) + .addImm(MSP430CC::COND_E); + + // LoopBB: + // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB] + // ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB] + // ShiftReg2 = shift ShiftReg + // ShiftAmt2 = ShiftAmt - 1; + BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftReg) + .addReg(SrcReg).addMBB(BB) + .addReg(ShiftReg2).addMBB(LoopBB); + BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftAmtReg) + .addReg(ShiftAmtSrcReg).addMBB(BB) + .addReg(ShiftAmtReg2).addMBB(LoopBB); + BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2) + .addReg(ShiftReg); + BuildMI(LoopBB, dl, TII.get(MSP430::SUB8ri), ShiftAmtReg2) + .addReg(ShiftAmtReg).addImm(1); + BuildMI(LoopBB, dl, TII.get(MSP430::JCC)) + .addMBB(LoopBB) + .addImm(MSP430CC::COND_NE); + + // RemBB: + // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB] + BuildMI(*RemBB, RemBB->begin(), dl, TII.get(MSP430::PHI), DstReg) + .addReg(SrcReg).addMBB(BB) + .addReg(ShiftReg2).addMBB(LoopBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return RemBB; +} + +MachineBasicBlock* +MSP430TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + unsigned Opc = MI->getOpcode(); + + if (Opc == MSP430::Shl8 || Opc == MSP430::Shl16 || + Opc == MSP430::Sra8 || Opc == MSP430::Sra16 || + Opc == MSP430::Srl8 || Opc == MSP430::Srl16) + return EmitShiftInstr(MI, BB); + + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + + assert((Opc == MSP430::Select16 || Opc == MSP430::Select8) && + "Unexpected instr type to insert"); + + // To "insert" a SELECT instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = BB; + ++I; + + // thisMBB: + // ... + // TrueVal = ... + // cmpTY ccX, r1, r2 + // jCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *copy1MBB = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(I, copy0MBB); + F->insert(I, copy1MBB); + // Update machine-CFG edges by transferring all successors of the current + // block to the new block which will contain the Phi node for the select. + copy1MBB->splice(copy1MBB->begin(), BB, + llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + copy1MBB->transferSuccessorsAndUpdatePHIs(BB); + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(copy1MBB); + + BuildMI(BB, dl, TII.get(MSP430::JCC)) + .addMBB(copy1MBB) + .addImm(MI->getOperand(3).getImm()); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to copy1MBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(copy1MBB); + + // copy1MBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = copy1MBB; + BuildMI(*BB, BB->begin(), dl, TII.get(MSP430::PHI), + MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.h new file mode 100644 index 0000000..673c543 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430ISelLowering.h @@ -0,0 +1,183 @@ +//==-- MSP430ISelLowering.h - MSP430 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 MSP430 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MSP430_ISELLOWERING_H +#define LLVM_TARGET_MSP430_ISELLOWERING_H + +#include "MSP430.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" + +namespace llvm { + namespace MSP430ISD { + enum { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + /// Return with a flag operand. Operand 0 is the chain operand. + RET_FLAG, + + /// Same as RET_FLAG, but used for returning from ISRs. + RETI_FLAG, + + /// Y = R{R,L}A X, rotate right (left) arithmetically + RRA, RLA, + + /// Y = RRC X, rotate right via carry + RRC, + + /// CALL - These operations represent an abstract call + /// instruction, which includes a bunch of information. + CALL, + + /// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, + /// and TargetGlobalAddress. + Wrapper, + + /// CMP - Compare instruction. + CMP, + + /// SetCC - Operand 0 is condition code, and operand 1 is the flag + /// operand produced by a CMP instruction. + SETCC, + + /// MSP430 conditional branches. Operand 0 is the chain operand, operand 1 + /// is the block to branch if condition is true, operand 2 is the + /// condition code, and operand 3 is the flag operand produced by a CMP + /// instruction. + BR_CC, + + /// SELECT_CC - Operand 0 and operand 1 are selection variable, operand 3 + /// is condition code and operand 4 is flag operand. + SELECT_CC, + + /// SHL, SRA, SRL - Non-constant shifts. + SHL, SRA, SRL + }; + } + + class MSP430Subtarget; + class MSP430TargetMachine; + + class MSP430TargetLowering : public TargetLowering { + public: + explicit MSP430TargetLowering(MSP430TargetMachine &TM); + + /// LowerOperation - Provide custom lowering hooks for some operations. + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; + + /// getTargetNodeName - This method returns the name of a target specific + /// DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + /// getFunctionAlignment - Return the Log2 alignment of this function. + virtual unsigned getFunctionAlignment(const Function *F) const; + + SDValue LowerShifts(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSIGN_EXTEND(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue getReturnAddressFrameIndex(SelectionDAG &DAG) const; + + TargetLowering::ConstraintType + getConstraintType(const std::string &Constraint) const; + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const; + + /// isTruncateFree - Return true if it's free to truncate a value of type + /// Ty1 to type Ty2. e.g. On msp430 it's free to truncate a i16 value in + /// register R15W to i8 by referencing its sub-register R15B. + virtual bool isTruncateFree(const Type *Ty1, const Type *Ty2) const; + virtual bool isTruncateFree(EVT VT1, EVT VT2) const; + + /// isZExtFree - Return true if any actual instruction that defines a value + /// of type Ty1 implicit zero-extends the value to Ty2 in the result + /// register. This does not necessarily include registers defined in unknown + /// ways, such as incoming arguments, or copies from unknown virtual + /// registers. Also, if isTruncateFree(Ty2, Ty1) is true, this does not + /// necessarily apply to truncate instructions. e.g. on msp430, all + /// instructions that define 8-bit values implicit zero-extend the result + /// out to 16 bits. + virtual bool isZExtFree(const Type *Ty1, const Type *Ty2) const; + virtual bool isZExtFree(EVT VT1, EVT VT2) const; + + MachineBasicBlock* EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const; + MachineBasicBlock* EmitShiftInstr(MachineInstr *MI, + MachineBasicBlock *BB) const; + + private: + SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, + bool isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + SDValue LowerCCCArguments(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + virtual SDValue + LowerCall(SDValue Chain, SDValue Callee, + CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SmallVectorImpl<ISD::InputArg> &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const; + + virtual SDValue + LowerReturn(SDValue Chain, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + DebugLoc dl, SelectionDAG &DAG) const; + + virtual bool getPostIndexedAddressParts(SDNode *N, SDNode *Op, + SDValue &Base, + SDValue &Offset, + ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const; + + const MSP430Subtarget &Subtarget; + const MSP430TargetMachine &TM; + const TargetData *TD; + }; +} // namespace llvm + +#endif // LLVM_TARGET_MSP430_ISELLOWERING_H diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrFormats.td b/contrib/llvm/lib/Target/MSP430/MSP430InstrFormats.td new file mode 100644 index 0000000..73aef1f --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrFormats.td @@ -0,0 +1,211 @@ +//===- MSP430InstrFormats.td - MSP430 Instruction Formats-----*- tblgen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Describe MSP430 instructions format here +// + +// Format specifies the encoding used by the instruction. This is part of the +// ad-hoc solution used to emit machine instruction encodings by our machine +// code emitter. +class Format<bits<2> val> { + bits<2> Value = val; +} + +def PseudoFrm : Format<0>; +def SingleOpFrm : Format<1>; +def DoubleOpFrm : Format<2>; +def CondJumpFrm : Format<3>; + +class SourceMode<bits<2> val> { + bits<2> Value = val; +} + +def SrcReg : SourceMode<0>; +def SrcMem : SourceMode<1>; +def SrcIndReg : SourceMode<2>; +def SrcPostInc : SourceMode<3>; +def SrcImm : SourceMode<3>; + +class DestMode<bit val> { + bit Value = val; +} + +def DstReg : DestMode<0>; +def DstMem : DestMode<1>; + +class SizeVal<bits<3> val> { + bits<3> Value = val; +} + +def SizeUnknown : SizeVal<0>; // Unknown / unset size +def SizeSpecial : SizeVal<1>; // Special instruction, e.g. pseudo +def Size2Bytes : SizeVal<2>; +def Size4Bytes : SizeVal<3>; +def Size6Bytes : SizeVal<4>; + +// Generic MSP430 Format +class MSP430Inst<dag outs, dag ins, SizeVal sz, Format f, + string asmstr> : Instruction { + field bits<16> Inst; + + let Namespace = "MSP430"; + + dag OutOperandList = outs; + dag InOperandList = ins; + + Format Form = f; + SizeVal Sz = sz; + + // Define how we want to layout our TargetSpecific information field... This + // should be kept up-to-date with the fields in the MSP430InstrInfo.h file. + let TSFlags{1-0} = Form.Value; + let TSFlags{4-2} = Sz.Value; + + let AsmString = asmstr; +} + +// FIXME: Create different classes for different addressing modes. + +// MSP430 Double Operand (Format I) Instructions +class IForm<bits<4> opcode, DestMode dest, bit bw, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, sz, DoubleOpFrm, asmstr> { + let Pattern = pattern; + + DestMode ad = dest; + SourceMode as = src; + + let Inst{12-15} = opcode; + let Inst{7} = ad.Value; + let Inst{6} = bw; + let Inst{4-5} = as.Value; +} + +// 8 bit IForm instructions +class IForm8<bits<4> opcode, DestMode dest, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm<opcode, dest, 1, src, sz, outs, ins, asmstr, pattern>; + +class I8rr<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstReg, SrcReg, Size2Bytes, outs, ins, asmstr, pattern>; + +class I8ri<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstReg, SrcImm, Size4Bytes, outs, ins, asmstr, pattern>; + +class I8rm<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstReg, SrcMem, Size4Bytes, outs, ins, asmstr, pattern>; + +class I8mr<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstMem, SrcReg, Size4Bytes, outs, ins, asmstr, pattern>; + +class I8mi<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstMem, SrcImm, Size6Bytes, outs, ins, asmstr, pattern>; + +class I8mm<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm8<opcode, DstMem, SrcMem, Size6Bytes, outs, ins, asmstr, pattern>; + +// 16 bit IForm instructions +class IForm16<bits<4> opcode, DestMode dest, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm<opcode, dest, 0, src, sz, outs, ins, asmstr, pattern>; + +class I16rr<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstReg, SrcReg, Size2Bytes, outs, ins, asmstr, pattern>; + +class I16ri<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstReg, SrcImm, Size4Bytes, outs, ins, asmstr, pattern>; + +class I16rm<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstReg, SrcMem, Size4Bytes, outs, ins, asmstr, pattern>; + +class I16mr<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstMem, SrcReg, Size4Bytes, outs, ins, asmstr, pattern>; + +class I16mi<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstMem, SrcImm, Size6Bytes, outs, ins, asmstr, pattern>; + +class I16mm<bits<4> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IForm16<opcode, DstMem, SrcMem, Size6Bytes, outs, ins, asmstr, pattern>; + +// MSP430 Single Operand (Format II) Instructions +class IIForm<bits<9> opcode, bit bw, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, sz, SingleOpFrm, asmstr> { + let Pattern = pattern; + + SourceMode as = src; + + let Inst{7-15} = opcode; + let Inst{6} = bw; + let Inst{4-5} = as.Value; +} + +// 8 bit IIForm instructions +class IIForm8<bits<9> opcode, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm<opcode, 1, src, sz, outs, ins, asmstr, pattern>; + +class II8r<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm8<opcode, SrcReg, Size2Bytes, outs, ins, asmstr, pattern>; + +class II8m<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm8<opcode, SrcMem, Size4Bytes, outs, ins, asmstr, pattern>; + +class II8i<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm8<opcode, SrcImm, Size4Bytes, outs, ins, asmstr, pattern>; + +// 16 bit IIForm instructions +class IIForm16<bits<9> opcode, SourceMode src, SizeVal sz, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm<opcode, 0, src, sz, outs, ins, asmstr, pattern>; + +class II16r<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm16<opcode, SrcReg, Size2Bytes, outs, ins, asmstr, pattern>; + +class II16m<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm16<opcode, SrcMem, Size4Bytes, outs, ins, asmstr, pattern>; + +class II16i<bits<9> opcode, + dag outs, dag ins, string asmstr, list<dag> pattern> + : IIForm16<opcode, SrcImm, Size4Bytes, outs, ins, asmstr, pattern>; + +// MSP430 Conditional Jumps Instructions +class CJForm<bits<3> opcode, bits<3> cond, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, Size2Bytes, CondJumpFrm, asmstr> { + let Pattern = pattern; + + let Inst{13-15} = opcode; + let Inst{10-12} = cond; +} + +// Pseudo instructions +class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, SizeSpecial, PseudoFrm, asmstr> { + let Pattern = pattern; + let Inst{15-0} = 0; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp new file mode 100644 index 0000000..bfab844 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -0,0 +1,373 @@ +//===- MSP430InstrInfo.cpp - MSP430 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 MSP430 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430MachineFunctionInfo.h" +#include "MSP430TargetMachine.h" +#include "MSP430GenInstrInfo.inc" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +MSP430InstrInfo::MSP430InstrInfo(MSP430TargetMachine &tm) + : TargetInstrInfoImpl(MSP430Insts, array_lengthof(MSP430Insts)), + RI(tm, *this), TM(tm) {} + +void MSP430InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + + MachineMemOperand *MMO = + MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FrameIdx), + MachineMemOperand::MOStore, 0, + MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + + if (RC == &MSP430::GR16RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV16mr)) + .addFrameIndex(FrameIdx).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); + else if (RC == &MSP430::GR8RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV8mr)) + .addFrameIndex(FrameIdx).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO); + else + llvm_unreachable("Cannot store this register to stack slot!"); +} + +void MSP430InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const{ + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + MachineFunction &MF = *MBB.getParent(); + MachineFrameInfo &MFI = *MF.getFrameInfo(); + + MachineMemOperand *MMO = + MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FrameIdx), + MachineMemOperand::MOLoad, 0, + MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + + if (RC == &MSP430::GR16RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV16rm)) + .addReg(DestReg).addFrameIndex(FrameIdx).addImm(0).addMemOperand(MMO); + else if (RC == &MSP430::GR8RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV8rm)) + .addReg(DestReg).addFrameIndex(FrameIdx).addImm(0).addMemOperand(MMO); + else + llvm_unreachable("Cannot store this register to stack slot!"); +} + +void MSP430InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const { + unsigned Opc; + if (MSP430::GR16RegClass.contains(DestReg, SrcReg)) + Opc = MSP430::MOV16rr; + else if (MSP430::GR8RegClass.contains(DestReg, SrcReg)) + Opc = MSP430::MOV8rr; + else + llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); +} + +bool +MSP430InstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + MachineFunction &MF = *MBB.getParent(); + MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>(); + MFI->setCalleeSavedFrameSize(CSI.size() * 2); + + for (unsigned i = CSI.size(); i != 0; --i) { + unsigned Reg = CSI[i-1].getReg(); + // Add the callee-saved register as live-in. It's killed at the spill. + MBB.addLiveIn(Reg); + BuildMI(MBB, MI, DL, get(MSP430::PUSH16r)) + .addReg(Reg, RegState::Kill); + } + return true; +} + +bool +MSP430InstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + for (unsigned i = 0, e = CSI.size(); i != e; ++i) + BuildMI(MBB, MI, DL, get(MSP430::POP16r), CSI[i].getReg()); + + return true; +} + +unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + if (I->getOpcode() != MSP430::JMP && + I->getOpcode() != MSP430::JCC && + I->getOpcode() != MSP430::Br && + I->getOpcode() != MSP430::Bm) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +bool MSP430InstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid Xbranch condition!"); + + MSP430CC::CondCodes CC = static_cast<MSP430CC::CondCodes>(Cond[0].getImm()); + + switch (CC) { + default: + assert(0 && "Invalid branch condition!"); + break; + case MSP430CC::COND_E: + CC = MSP430CC::COND_NE; + break; + case MSP430CC::COND_NE: + CC = MSP430CC::COND_E; + break; + case MSP430CC::COND_L: + CC = MSP430CC::COND_GE; + break; + case MSP430CC::COND_GE: + CC = MSP430CC::COND_L; + break; + case MSP430CC::COND_HS: + CC = MSP430CC::COND_LO; + break; + case MSP430CC::COND_LO: + CC = MSP430CC::COND_HS; + break; + } + + Cond[0].setImm(CC); + return false; +} + +bool MSP430InstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.isTerminator()) return false; + + // Conditional branch is a special case. + if (TID.isBranch() && !TID.isBarrier()) + return true; + if (!TID.isPredicable()) + return true; + return !isPredicated(MI); +} + +bool MSP430InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) + return true; + + // Cannot handle indirect branches. + if (I->getOpcode() == MSP430::Br || + I->getOpcode() == MSP430::Bm) + return true; + + // Handle unconditional branches. + if (I->getOpcode() == MSP430::JMP) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (llvm::next(I) != MBB.end()) + llvm::next(I)->eraseFromParent(); + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + assert(I->getOpcode() == MSP430::JCC && "Invalid conditional branch"); + MSP430CC::CondCodes BranchCode = + static_cast<MSP430CC::CondCodes>(I->getOperand(1).getImm()); + if (BranchCode == MSP430CC::COND_INVALID) + return true; // Can't handle weird stuff. + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) + return true; + + MSP430CC::CondCodes OldBranchCode = (MSP430CC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) + continue; + + return true; + } + + return false; +} + +unsigned +MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const { + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 1 || Cond.size() == 0) && + "MSP430 branch conditions have one component!"); + + if (Cond.empty()) { + // Unconditional branch? + assert(!FBB && "Unconditional branch with multiple successors!"); + BuildMI(&MBB, DL, get(MSP430::JMP)).addMBB(TBB); + return 1; + } + + // Conditional branch. + unsigned Count = 0; + BuildMI(&MBB, DL, get(MSP430::JCC)).addMBB(TBB).addImm(Cond[0].getImm()); + ++Count; + + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, DL, get(MSP430::JMP)).addMBB(FBB); + ++Count; + } + return Count; +} + +/// GetInstSize - Return the number of bytes of code the specified +/// instruction may be. This returns the maximum number of bytes. +/// +unsigned MSP430InstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { + const TargetInstrDesc &Desc = MI->getDesc(); + + switch (Desc.TSFlags & MSP430II::SizeMask) { + default: + switch (Desc.getOpcode()) { + default: + assert(0 && "Unknown instruction size!"); + case TargetOpcode::PROLOG_LABEL: + case TargetOpcode::EH_LABEL: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + case TargetOpcode::DBG_VALUE: + return 0; + case TargetOpcode::INLINEASM: { + const MachineFunction *MF = MI->getParent()->getParent(); + const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); + return TII.getInlineAsmLength(MI->getOperand(0).getSymbolName(), + *MF->getTarget().getMCAsmInfo()); + } + } + case MSP430II::SizeSpecial: + switch (MI->getOpcode()) { + default: + assert(0 && "Unknown instruction size!"); + case MSP430::SAR8r1c: + case MSP430::SAR16r1c: + return 4; + } + case MSP430II::Size2Bytes: + return 2; + case MSP430II::Size4Bytes: + return 4; + case MSP430II::Size6Bytes: + return 6; + } + + return 6; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h new file mode 100644 index 0000000..49ccc03 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.h @@ -0,0 +1,98 @@ +//===- MSP430InstrInfo.h - MSP430 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 MSP430 implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MSP430INSTRINFO_H +#define LLVM_TARGET_MSP430INSTRINFO_H + +#include "llvm/Target/TargetInstrInfo.h" +#include "MSP430RegisterInfo.h" + +namespace llvm { + +class MSP430TargetMachine; + +/// MSP430II - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace MSP430II { + enum { + SizeShift = 2, + SizeMask = 7 << SizeShift, + + SizeUnknown = 0 << SizeShift, + SizeSpecial = 1 << SizeShift, + Size2Bytes = 2 << SizeShift, + Size4Bytes = 3 << SizeShift, + Size6Bytes = 4 << SizeShift + }; +} + +class MSP430InstrInfo : public TargetInstrInfoImpl { + const MSP430RegisterInfo RI; + MSP430TargetMachine &TM; +public: + explicit MSP430InstrInfo(MSP430TargetMachine &TM); + + /// 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). + /// + virtual const TargetRegisterInfo &getRegisterInfo() const { return RI; } + + void copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, DebugLoc DL, + unsigned DestReg, unsigned SrcReg, + bool KillSrc) const; + + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const; + + virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI, + const TargetRegisterInfo *TRI) const; + + unsigned GetInstSizeInBytes(const MachineInstr *MI) const; + + // Branch folding goodness + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + bool isUnpredicatedTerminator(const MachineInstr *MI) const; + bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond, + DebugLoc DL) const; + +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.td b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.td new file mode 100644 index 0000000..8792b22 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430InstrInfo.td @@ -0,0 +1,1211 @@ +//===- MSP430InstrInfo.td - MSP430 Instruction defs -----------*- tblgen-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the MSP430 instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +include "MSP430InstrFormats.td" + +//===----------------------------------------------------------------------===// +// Type Constraints. +//===----------------------------------------------------------------------===// +class SDTCisI8<int OpNum> : SDTCisVT<OpNum, i8>; +class SDTCisI16<int OpNum> : SDTCisVT<OpNum, i16>; + +//===----------------------------------------------------------------------===// +// Type Profiles. +//===----------------------------------------------------------------------===// +def SDT_MSP430Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; +def SDT_MSP430CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i16>]>; +def SDT_MSP430CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i16>, SDTCisVT<1, i16>]>; +def SDT_MSP430Wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; +def SDT_MSP430Cmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; +def SDT_MSP430BrCC : SDTypeProfile<0, 2, [SDTCisVT<0, OtherVT>, + SDTCisVT<1, i8>]>; +def SDT_MSP430SelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, + SDTCisSameAs<1, 2>, + SDTCisVT<3, i8>]>; +def SDT_MSP430Shift : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, + SDTCisI8<2>]>; + +//===----------------------------------------------------------------------===// +// MSP430 Specific Node Definitions. +//===----------------------------------------------------------------------===// +def MSP430retflag : SDNode<"MSP430ISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag]>; +def MSP430retiflag : SDNode<"MSP430ISD::RETI_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag]>; + +def MSP430rra : SDNode<"MSP430ISD::RRA", SDTIntUnaryOp, []>; +def MSP430rla : SDNode<"MSP430ISD::RLA", SDTIntUnaryOp, []>; +def MSP430rrc : SDNode<"MSP430ISD::RRC", SDTIntUnaryOp, []>; + +def MSP430call : SDNode<"MSP430ISD::CALL", SDT_MSP430Call, + [SDNPHasChain, SDNPOutFlag, SDNPOptInFlag, SDNPVariadic]>; +def MSP430callseq_start : + SDNode<"ISD::CALLSEQ_START", SDT_MSP430CallSeqStart, + [SDNPHasChain, SDNPOutFlag]>; +def MSP430callseq_end : + SDNode<"ISD::CALLSEQ_END", SDT_MSP430CallSeqEnd, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; +def MSP430Wrapper : SDNode<"MSP430ISD::Wrapper", SDT_MSP430Wrapper>; +def MSP430cmp : SDNode<"MSP430ISD::CMP", SDT_MSP430Cmp, [SDNPOutFlag]>; +def MSP430brcc : SDNode<"MSP430ISD::BR_CC", SDT_MSP430BrCC, + [SDNPHasChain, SDNPInFlag]>; +def MSP430selectcc: SDNode<"MSP430ISD::SELECT_CC", SDT_MSP430SelectCC, + [SDNPInFlag]>; +def MSP430shl : SDNode<"MSP430ISD::SHL", SDT_MSP430Shift, []>; +def MSP430sra : SDNode<"MSP430ISD::SRA", SDT_MSP430Shift, []>; +def MSP430srl : SDNode<"MSP430ISD::SRL", SDT_MSP430Shift, []>; + +//===----------------------------------------------------------------------===// +// MSP430 Operand Definitions. +//===----------------------------------------------------------------------===// + +// Address operands +def memsrc : Operand<i16> { + let PrintMethod = "printSrcMemOperand"; + let MIOperandInfo = (ops GR16, i16imm); +} + +def memdst : Operand<i16> { + let PrintMethod = "printSrcMemOperand"; + let MIOperandInfo = (ops GR16, i16imm); +} + +// Short jump targets have OtherVT type and are printed as pcrel imm values. +def jmptarget : Operand<OtherVT> { + let PrintMethod = "printPCRelImmOperand"; +} + +// Operand for printing out a condition code. +def cc : Operand<i8> { + let PrintMethod = "printCCOperand"; +} + +//===----------------------------------------------------------------------===// +// MSP430 Complex Pattern Definitions. +//===----------------------------------------------------------------------===// + +def addr : ComplexPattern<iPTR, 2, "SelectAddr", [], []>; + +//===----------------------------------------------------------------------===// +// Pattern Fragments +def zextloadi16i8 : PatFrag<(ops node:$ptr), (i16 (zextloadi8 node:$ptr))>; +def extloadi16i8 : PatFrag<(ops node:$ptr), (i16 ( extloadi8 node:$ptr))>; +def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{ + return N->hasOneUse(); +}]>; +//===----------------------------------------------------------------------===// +// Instruction list.. + +// ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into +// a stack adjustment and the codegen must know that they may modify the stack +// pointer before prolog-epilog rewriting occurs. +// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become +// sub / add which can clobber SRW. +let Defs = [SPW, SRW], Uses = [SPW] in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i16imm:$amt), + "#ADJCALLSTACKDOWN", + [(MSP430callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i16imm:$amt1, i16imm:$amt2), + "#ADJCALLSTACKUP", + [(MSP430callseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1 in { + def Select8 : Pseudo<(outs GR8:$dst), (ins GR8:$src, GR8:$src2, i8imm:$cc), + "# Select8 PSEUDO", + [(set GR8:$dst, + (MSP430selectcc GR8:$src, GR8:$src2, imm:$cc))]>; + def Select16 : Pseudo<(outs GR16:$dst), (ins GR16:$src, GR16:$src2, i8imm:$cc), + "# Select16 PSEUDO", + [(set GR16:$dst, + (MSP430selectcc GR16:$src, GR16:$src2, imm:$cc))]>; + let Defs = [SRW] in { + def Shl8 : Pseudo<(outs GR8:$dst), (ins GR8:$src, GR8:$cnt), + "# Shl8 PSEUDO", + [(set GR8:$dst, (MSP430shl GR8:$src, GR8:$cnt))]>; + def Shl16 : Pseudo<(outs GR16:$dst), (ins GR16:$src, GR8:$cnt), + "# Shl16 PSEUDO", + [(set GR16:$dst, (MSP430shl GR16:$src, GR8:$cnt))]>; + def Sra8 : Pseudo<(outs GR8:$dst), (ins GR8:$src, GR8:$cnt), + "# Sra8 PSEUDO", + [(set GR8:$dst, (MSP430sra GR8:$src, GR8:$cnt))]>; + def Sra16 : Pseudo<(outs GR16:$dst), (ins GR16:$src, GR8:$cnt), + "# Sra16 PSEUDO", + [(set GR16:$dst, (MSP430sra GR16:$src, GR8:$cnt))]>; + def Srl8 : Pseudo<(outs GR8:$dst), (ins GR8:$src, GR8:$cnt), + "# Srl8 PSEUDO", + [(set GR8:$dst, (MSP430srl GR8:$src, GR8:$cnt))]>; + def Srl16 : Pseudo<(outs GR16:$dst), (ins GR16:$src, GR8:$cnt), + "# Srl16 PSEUDO", + [(set GR16:$dst, (MSP430srl GR16:$src, GR8:$cnt))]>; + + } +} + +let neverHasSideEffects = 1 in +def NOP : Pseudo<(outs), (ins), "nop", []>; + +//===----------------------------------------------------------------------===// +// Control Flow Instructions... +// + +// FIXME: Provide proper encoding! +let isReturn = 1, isTerminator = 1, isBarrier = 1 in { + def RET : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs), (ins), "ret", [(MSP430retflag)]>; + def RETI : II16r<0x0, (outs), (ins), "reti", [(MSP430retiflag)]>; +} + +let isBranch = 1, isTerminator = 1 in { + +// FIXME: expand opcode & cond field for branches! + +// Direct branch +let isBarrier = 1 in { + // Short branch + def JMP : CJForm<0, 0, (outs), (ins jmptarget:$dst), + "jmp\t$dst", + [(br bb:$dst)]>; + let isIndirectBranch = 1 in { + // Long branches + def Bi : I16ri<0, (outs), (ins i16imm:$brdst), + "br\t$brdst", + [(brind tblockaddress:$brdst)]>; + def Br : I16rr<0, (outs), (ins GR16:$brdst), + "mov.w\t{$brdst, pc}", + [(brind GR16:$brdst)]>; + def Bm : I16rm<0, (outs), (ins memsrc:$brdst), + "mov.w\t{$brdst, pc}", + [(brind (load addr:$brdst))]>; + } +} + +// Conditional branches +let Uses = [SRW] in + def JCC : CJForm<0, 0, + (outs), (ins jmptarget:$dst, cc:$cc), + "j$cc\t$dst", + [(MSP430brcc bb:$dst, imm:$cc)]>; +} // isBranch, isTerminator + +//===----------------------------------------------------------------------===// +// Call Instructions... +// +let isCall = 1 in + // All calls clobber the non-callee saved registers. SPW is marked as + // a use to prevent stack-pointer assignments that appear immediately + // before calls from potentially appearing dead. Uses for argument + // registers are added manually. + let Defs = [R12W, R13W, R14W, R15W, SRW], + Uses = [SPW] in { + def CALLi : II16i<0x0, + (outs), (ins i16imm:$dst, variable_ops), + "call\t$dst", [(MSP430call imm:$dst)]>; + def CALLr : II16r<0x0, + (outs), (ins GR16:$dst, variable_ops), + "call\t$dst", [(MSP430call GR16:$dst)]>; + def CALLm : II16m<0x0, + (outs), (ins memsrc:$dst, variable_ops), + "call\t${dst:mem}", [(MSP430call (load addr:$dst))]>; + } + + +//===----------------------------------------------------------------------===// +// Miscellaneous Instructions... +// +let Defs = [SPW], Uses = [SPW], neverHasSideEffects=1 in { +let mayLoad = 1 in +def POP16r : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$reg), (ins), "pop.w\t$reg", []>; + +let mayStore = 1 in +def PUSH16r : II16r<0x0, + (outs), (ins GR16:$reg), "push.w\t$reg",[]>; +} + +//===----------------------------------------------------------------------===// +// Move Instructions + +// FIXME: Provide proper encoding! +let neverHasSideEffects = 1 in { +def MOV8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src), + "mov.b\t{$src, $dst}", + []>; +def MOV16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src), + "mov.w\t{$src, $dst}", + []>; +} + +// FIXME: Provide proper encoding! +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def MOV8ri : I8ri<0x0, + (outs GR8:$dst), (ins i8imm:$src), + "mov.b\t{$src, $dst}", + [(set GR8:$dst, imm:$src)]>; +def MOV16ri : I16ri<0x0, + (outs GR16:$dst), (ins i16imm:$src), + "mov.w\t{$src, $dst}", + [(set GR16:$dst, imm:$src)]>; +} + +let canFoldAsLoad = 1, isReMaterializable = 1 in { +def MOV8rm : I8rm<0x0, + (outs GR8:$dst), (ins memsrc:$src), + "mov.b\t{$src, $dst}", + [(set GR8:$dst, (load addr:$src))]>; +def MOV16rm : I16rm<0x0, + (outs GR16:$dst), (ins memsrc:$src), + "mov.w\t{$src, $dst}", + [(set GR16:$dst, (load addr:$src))]>; +} + +def MOVZX16rr8 : I8rr<0x0, + (outs GR16:$dst), (ins GR8:$src), + "mov.b\t{$src, $dst}", + [(set GR16:$dst, (zext GR8:$src))]>; +def MOVZX16rm8 : I8rm<0x0, + (outs GR16:$dst), (ins memsrc:$src), + "mov.b\t{$src, $dst}", + [(set GR16:$dst, (zextloadi16i8 addr:$src))]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, Constraints = "$base = $base_wb" in { +def MOV8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), (ins GR16:$base), + "mov.b\t{@$base+, $dst}", []>; +def MOV16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), (ins GR16:$base), + "mov.w\t{@$base+, $dst}", []>; +} + +// Any instruction that defines a 8-bit result leaves the high half of the +// register. Truncate can be lowered to EXTRACT_SUBREG, and CopyFromReg may +// be copying from a truncate, but any other 8-bit operation will zero-extend +// up to 16 bits. +def def8 : PatLeaf<(i8 GR8:$src), [{ + return N->getOpcode() != ISD::TRUNCATE && + N->getOpcode() != TargetOpcode::EXTRACT_SUBREG && + N->getOpcode() != ISD::CopyFromReg; +}]>; + +// In the case of a 8-bit def that is known to implicitly zero-extend, +// we can use a SUBREG_TO_REG. +def : Pat<(i16 (zext def8:$src)), + (SUBREG_TO_REG (i16 0), GR8:$src, subreg_8bit)>; + +def MOV8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "mov.b\t{$src, $dst}", + [(store (i8 imm:$src), addr:$dst)]>; +def MOV16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "mov.w\t{$src, $dst}", + [(store (i16 imm:$src), addr:$dst)]>; + +def MOV8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "mov.b\t{$src, $dst}", + [(store GR8:$src, addr:$dst)]>; +def MOV16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "mov.w\t{$src, $dst}", + [(store GR16:$src, addr:$dst)]>; + +def MOV8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "mov.b\t{$src, $dst}", + [(store (i8 (load addr:$src)), addr:$dst)]>; +def MOV16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "mov.w\t{$src, $dst}", + [(store (i16 (load addr:$src)), addr:$dst)]>; + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions + +let Constraints = "$src = $dst" in { + +let Defs = [SRW] in { + +let isCommutable = 1 in { // X = ADD Y, Z == X = ADD Z, Y + +def ADD8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def ADD16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src, GR16:$src2)), + (implicit SRW)]>; +} + +def ADD8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def ADD16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, +Constraints = "$base = $base_wb, $src = $dst" in { +def ADD8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), + (ins GR8:$src, GR16:$base), + "add.b\t{@$base+, $dst}", []>; +def ADD16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), + (ins GR16:$src, GR16:$base), + "add.w\t{@$base+, $dst}", []>; +} + + +def ADD8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src, imm:$src2)), + (implicit SRW)]>; +def ADD16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src, imm:$src2)), + (implicit SRW)]>; + +let Constraints = "" in { +def ADD8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "add.b\t{$src, $dst}", + [(store (add (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def ADD16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "add.w\t{$src, $dst}", + [(store (add (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def ADD8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "add.b\t{$src, $dst}", + [(store (add (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def ADD16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "add.w\t{$src, $dst}", + [(store (add (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def ADD8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "add.b\t{$src, $dst}", + [(store (add (load addr:$dst), + (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def ADD16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "add.w\t{$src, $dst}", + [(store (add (load addr:$dst), + (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +let Uses = [SRW] in { + +let isCommutable = 1 in { // X = ADDC Y, Z == X = ADDC Z, Y +def ADC8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def ADC16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src, GR16:$src2)), + (implicit SRW)]>; +} // isCommutable + +def ADC8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src, imm:$src2)), + (implicit SRW)]>; +def ADC16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src, imm:$src2)), + (implicit SRW)]>; + +def ADC8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def ADC16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let Constraints = "" in { +def ADC8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "addc.b\t{$src, $dst}", + [(store (adde (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def ADC16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "addc.w\t{$src, $dst}", + [(store (adde (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def ADC8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "addc.b\t{$src, $dst}", + [(store (adde (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def ADC16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "addc.w\t{$src, $dst}", + [(store (adde (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def ADC8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "addc.b\t{$src, $dst}", + [(store (adde (load addr:$dst), + (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def ADC16mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "addc.w\t{$src, $dst}", + [(store (adde (load addr:$dst), + (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +} // Uses = [SRW] + +let isCommutable = 1 in { // X = AND Y, Z == X = AND Z, Y +def AND8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def AND16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src, GR16:$src2)), + (implicit SRW)]>; +} + +def AND8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src, imm:$src2)), + (implicit SRW)]>; +def AND16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src, imm:$src2)), + (implicit SRW)]>; + +def AND8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def AND16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, +Constraints = "$base = $base_wb, $src = $dst" in { +def AND8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), + (ins GR8:$src, GR16:$base), + "and.b\t{@$base+, $dst}", []>; +def AND16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), + (ins GR16:$src, GR16:$base), + "and.w\t{@$base+, $dst}", []>; +} + +let Constraints = "" in { +def AND8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "and.b\t{$src, $dst}", + [(store (and (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def AND16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "and.w\t{$src, $dst}", + [(store (and (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def AND8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "and.b\t{$src, $dst}", + [(store (and (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def AND16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "and.w\t{$src, $dst}", + [(store (and (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def AND8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "and.b\t{$src, $dst}", + [(store (and (load addr:$dst), + (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def AND16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "and.w\t{$src, $dst}", + [(store (and (load addr:$dst), + (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +let isCommutable = 1 in { // X = OR Y, Z == X = OR Z, Y +def OR8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src, GR8:$src2))]>; +def OR16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src, GR16:$src2))]>; +} + +def OR8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src, imm:$src2))]>; +def OR16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src, imm:$src2))]>; + +def OR8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src, (load addr:$src2)))]>; +def OR16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src, (load addr:$src2)))]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, +Constraints = "$base = $base_wb, $src = $dst" in { +def OR8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), + (ins GR8:$src, GR16:$base), + "bis.b\t{@$base+, $dst}", []>; +def OR16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), + (ins GR16:$src, GR16:$base), + "bis.w\t{@$base+, $dst}", []>; +} + +let Constraints = "" in { +def OR8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "bis.b\t{$src, $dst}", + [(store (or (load addr:$dst), GR8:$src), addr:$dst)]>; +def OR16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "bis.w\t{$src, $dst}", + [(store (or (load addr:$dst), GR16:$src), addr:$dst)]>; + +def OR8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "bis.b\t{$src, $dst}", + [(store (or (load addr:$dst), (i8 imm:$src)), addr:$dst)]>; +def OR16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "bis.w\t{$src, $dst}", + [(store (or (load addr:$dst), (i16 imm:$src)), addr:$dst)]>; + +def OR8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "bis.b\t{$src, $dst}", + [(store (or (i8 (load addr:$dst)), + (i8 (load addr:$src))), addr:$dst)]>; +def OR16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "bis.w\t{$src, $dst}", + [(store (or (i16 (load addr:$dst)), + (i16 (load addr:$src))), addr:$dst)]>; +} + +// bic does not modify condition codes +def BIC8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "bic.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src, (not GR8:$src2)))]>; +def BIC16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "bic.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src, (not GR16:$src2)))]>; + +def BIC8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "bic.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src, (not (i8 (load addr:$src2)))))]>; +def BIC16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "bic.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src, (not (i16 (load addr:$src2)))))]>; + +let Constraints = "" in { +def BIC8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "bic.b\t{$src, $dst}", + [(store (and (load addr:$dst), (not GR8:$src)), addr:$dst)]>; +def BIC16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "bic.w\t{$src, $dst}", + [(store (and (load addr:$dst), (not GR16:$src)), addr:$dst)]>; + +def BIC8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "bic.b\t{$src, $dst}", + [(store (and (load addr:$dst), + (not (i8 (load addr:$src)))), addr:$dst)]>; +def BIC16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "bic.w\t{$src, $dst}", + [(store (and (load addr:$dst), + (not (i16 (load addr:$src)))), addr:$dst)]>; +} + +let isCommutable = 1 in { // X = XOR Y, Z == X = XOR Z, Y +def XOR8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def XOR16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src, GR16:$src2)), + (implicit SRW)]>; +} + +def XOR8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src, imm:$src2)), + (implicit SRW)]>; +def XOR16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src, imm:$src2)), + (implicit SRW)]>; + +def XOR8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def XOR16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, +Constraints = "$base = $base_wb, $src = $dst" in { +def XOR8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), + (ins GR8:$src, GR16:$base), + "xor.b\t{@$base+, $dst}", []>; +def XOR16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), + (ins GR16:$src, GR16:$base), + "xor.w\t{@$base+, $dst}", []>; +} + +let Constraints = "" in { +def XOR8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "xor.b\t{$src, $dst}", + [(store (xor (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def XOR16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "xor.w\t{$src, $dst}", + [(store (xor (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def XOR8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "xor.b\t{$src, $dst}", + [(store (xor (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def XOR16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "xor.w\t{$src, $dst}", + [(store (xor (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def XOR8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "xor.b\t{$src, $dst}", + [(store (xor (load addr:$dst), (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def XOR16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "xor.w\t{$src, $dst}", + [(store (xor (load addr:$dst), (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + + +def SUB8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def SUB16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src, GR16:$src2)), + (implicit SRW)]>; + +def SUB8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src, imm:$src2)), + (implicit SRW)]>; +def SUB16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src, imm:$src2)), + (implicit SRW)]>; + +def SUB8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def SUB16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let mayLoad = 1, hasExtraDefRegAllocReq = 1, +Constraints = "$base = $base_wb, $src = $dst" in { +def SUB8rm_POST : IForm8<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR8:$dst, GR16:$base_wb), + (ins GR8:$src, GR16:$base), + "sub.b\t{@$base+, $dst}", []>; +def SUB16rm_POST : IForm16<0x0, DstReg, SrcPostInc, Size2Bytes, + (outs GR16:$dst, GR16:$base_wb), + (ins GR16:$src, GR16:$base), + "sub.w\t{@$base+, $dst}", []>; +} + +let Constraints = "" in { +def SUB8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "sub.b\t{$src, $dst}", + [(store (sub (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def SUB16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "sub.w\t{$src, $dst}", + [(store (sub (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def SUB8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "sub.b\t{$src, $dst}", + [(store (sub (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def SUB16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "sub.w\t{$src, $dst}", + [(store (sub (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def SUB8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "sub.b\t{$src, $dst}", + [(store (sub (load addr:$dst), + (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def SUB16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "sub.w\t{$src, $dst}", + [(store (sub (load addr:$dst), + (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +let Uses = [SRW] in { +def SBC8rr : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src, GR8:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src, GR8:$src2)), + (implicit SRW)]>; +def SBC16rr : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src, GR16:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src, GR16:$src2)), + (implicit SRW)]>; + +def SBC8ri : I8ri<0x0, + (outs GR8:$dst), (ins GR8:$src, i8imm:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src, imm:$src2)), + (implicit SRW)]>; +def SBC16ri : I16ri<0x0, + (outs GR16:$dst), (ins GR16:$src, i16imm:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src, imm:$src2)), + (implicit SRW)]>; + +def SBC8rm : I8rm<0x0, + (outs GR8:$dst), (ins GR8:$src, memsrc:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src, (load addr:$src2))), + (implicit SRW)]>; +def SBC16rm : I16rm<0x0, + (outs GR16:$dst), (ins GR16:$src, memsrc:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src, (load addr:$src2))), + (implicit SRW)]>; + +let Constraints = "" in { +def SBC8mr : I8mr<0x0, + (outs), (ins memdst:$dst, GR8:$src), + "subc.b\t{$src, $dst}", + [(store (sube (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def SBC16mr : I16mr<0x0, + (outs), (ins memdst:$dst, GR16:$src), + "subc.w\t{$src, $dst}", + [(store (sube (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def SBC8mi : I8mi<0x0, + (outs), (ins memdst:$dst, i8imm:$src), + "subc.b\t{$src, $dst}", + [(store (sube (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def SBC16mi : I16mi<0x0, + (outs), (ins memdst:$dst, i16imm:$src), + "subc.w\t{$src, $dst}", + [(store (sube (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def SBC8mm : I8mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "subc.b\t{$src, $dst}", + [(store (sube (load addr:$dst), + (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def SBC16mm : I16mm<0x0, + (outs), (ins memdst:$dst, memsrc:$src), + "subc.w\t{$src, $dst}", + [(store (sube (load addr:$dst), + (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +} // Uses = [SRW] + +// FIXME: memory variant! +def SAR8r1 : II8r<0x0, + (outs GR8:$dst), (ins GR8:$src), + "rra.b\t$dst", + [(set GR8:$dst, (MSP430rra GR8:$src)), + (implicit SRW)]>; +def SAR16r1 : II16r<0x0, + (outs GR16:$dst), (ins GR16:$src), + "rra.w\t$dst", + [(set GR16:$dst, (MSP430rra GR16:$src)), + (implicit SRW)]>; + +def SHL8r1 : I8rr<0x0, + (outs GR8:$dst), (ins GR8:$src), + "rla.b\t$dst", + [(set GR8:$dst, (MSP430rla GR8:$src)), + (implicit SRW)]>; +def SHL16r1 : I16rr<0x0, + (outs GR16:$dst), (ins GR16:$src), + "rla.w\t$dst", + [(set GR16:$dst, (MSP430rla GR16:$src)), + (implicit SRW)]>; + +def SAR8r1c : Pseudo<(outs GR8:$dst), (ins GR8:$src), + "clrc\n\t" + "rrc.b\t$dst", + [(set GR8:$dst, (MSP430rrc GR8:$src)), + (implicit SRW)]>; +def SAR16r1c : Pseudo<(outs GR16:$dst), (ins GR16:$src), + "clrc\n\t" + "rrc.w\t$dst", + [(set GR16:$dst, (MSP430rrc GR16:$src)), + (implicit SRW)]>; + +// FIXME: Memory sext's ? +def SEXT16r : II16r<0x0, + (outs GR16:$dst), (ins GR16:$src), + "sxt\t$dst", + [(set GR16:$dst, (sext_inreg GR16:$src, i8)), + (implicit SRW)]>; + +} // Defs = [SRW] + +def ZEXT16r : I8rr<0x0, + (outs GR16:$dst), (ins GR16:$src), + "mov.b\t{$src, $dst}", + [(set GR16:$dst, (zext (trunc GR16:$src)))]>; + +// FIXME: Memory bitswaps? +def SWPB16r : II16r<0x0, + (outs GR16:$dst), (ins GR16:$src), + "swpb\t$dst", + [(set GR16:$dst, (bswap GR16:$src))]>; + +} // Constraints = "$src = $dst" + +// Integer comparisons +let Defs = [SRW] in { +def CMP8rr : I8rr<0x0, + (outs), (ins GR8:$src, GR8:$src2), + "cmp.b\t{$src2, $src}", + [(MSP430cmp GR8:$src, GR8:$src2), (implicit SRW)]>; +def CMP16rr : I16rr<0x0, + (outs), (ins GR16:$src, GR16:$src2), + "cmp.w\t{$src2, $src}", + [(MSP430cmp GR16:$src, GR16:$src2), (implicit SRW)]>; + +def CMP8ri : I8ri<0x0, + (outs), (ins GR8:$src, i8imm:$src2), + "cmp.b\t{$src2, $src}", + [(MSP430cmp GR8:$src, imm:$src2), (implicit SRW)]>; +def CMP16ri : I16ri<0x0, + (outs), (ins GR16:$src, i16imm:$src2), + "cmp.w\t{$src2, $src}", + [(MSP430cmp GR16:$src, imm:$src2), (implicit SRW)]>; + +def CMP8mi : I8mi<0x0, + (outs), (ins memsrc:$src, i8imm:$src2), + "cmp.b\t{$src2, $src}", + [(MSP430cmp (load addr:$src), + (i8 imm:$src2)), (implicit SRW)]>; +def CMP16mi : I16mi<0x0, + (outs), (ins memsrc:$src, i16imm:$src2), + "cmp.w\t{$src2, $src}", + [(MSP430cmp (load addr:$src), + (i16 imm:$src2)), (implicit SRW)]>; + +def CMP8rm : I8rm<0x0, + (outs), (ins GR8:$src, memsrc:$src2), + "cmp.b\t{$src2, $src}", + [(MSP430cmp GR8:$src, (load addr:$src2)), + (implicit SRW)]>; +def CMP16rm : I16rm<0x0, + (outs), (ins GR16:$src, memsrc:$src2), + "cmp.w\t{$src2, $src}", + [(MSP430cmp GR16:$src, (load addr:$src2)), + (implicit SRW)]>; + +def CMP8mr : I8mr<0x0, + (outs), (ins memsrc:$src, GR8:$src2), + "cmp.b\t{$src2, $src}", + [(MSP430cmp (load addr:$src), GR8:$src2), + (implicit SRW)]>; +def CMP16mr : I16mr<0x0, + (outs), (ins memsrc:$src, GR16:$src2), + "cmp.w\t{$src2, $src}", + [(MSP430cmp (load addr:$src), GR16:$src2), + (implicit SRW)]>; + + +// BIT TESTS, just sets condition codes +// Note that the C condition is set differently than when using CMP. +let isCommutable = 1 in { +def BIT8rr : I8rr<0x0, + (outs), (ins GR8:$src, GR8:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su GR8:$src, GR8:$src2), 0), + (implicit SRW)]>; +def BIT16rr : I16rr<0x0, + (outs), (ins GR16:$src, GR16:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su GR16:$src, GR16:$src2), 0), + (implicit SRW)]>; +} +def BIT8ri : I8ri<0x0, + (outs), (ins GR8:$src, i8imm:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su GR8:$src, imm:$src2), 0), + (implicit SRW)]>; +def BIT16ri : I16ri<0x0, + (outs), (ins GR16:$src, i16imm:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su GR16:$src, imm:$src2), 0), + (implicit SRW)]>; + +def BIT8rm : I8rm<0x0, + (outs), (ins GR8:$src, memdst:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su GR8:$src, (load addr:$src2)), 0), + (implicit SRW)]>; +def BIT16rm : I16rm<0x0, + (outs), (ins GR16:$src, memdst:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su GR16:$src, (load addr:$src2)), 0), + (implicit SRW)]>; + +def BIT8mr : I8mr<0x0, + (outs), (ins memsrc:$src, GR8:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su (load addr:$src), GR8:$src2), 0), + (implicit SRW)]>; +def BIT16mr : I16mr<0x0, + (outs), (ins memsrc:$src, GR16:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su (load addr:$src), GR16:$src2), 0), + (implicit SRW)]>; + +def BIT8mi : I8mi<0x0, + (outs), (ins memsrc:$src, i8imm:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su (load addr:$src), (i8 imm:$src2)), 0), + (implicit SRW)]>; +def BIT16mi : I16mi<0x0, + (outs), (ins memsrc:$src, i16imm:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su (load addr:$src), (i16 imm:$src2)), 0), + (implicit SRW)]>; + +def BIT8mm : I8mm<0x0, + (outs), (ins memsrc:$src, memsrc:$src2), + "bit.b\t{$src2, $src}", + [(MSP430cmp (and_su (i8 (load addr:$src)), + (load addr:$src2)), + 0), + (implicit SRW)]>; +def BIT16mm : I16mm<0x0, + (outs), (ins memsrc:$src, memsrc:$src2), + "bit.w\t{$src2, $src}", + [(MSP430cmp (and_su (i16 (load addr:$src)), + (load addr:$src2)), + 0), + (implicit SRW)]>; +} // Defs = [SRW] + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns + +// extload +def : Pat<(extloadi16i8 addr:$src), (MOVZX16rm8 addr:$src)>; + +// anyext +def : Pat<(i16 (anyext GR8:$src)), + (SUBREG_TO_REG (i16 0), GR8:$src, subreg_8bit)>; + +// truncs +def : Pat<(i8 (trunc GR16:$src)), + (EXTRACT_SUBREG GR16:$src, subreg_8bit)>; + +// GlobalAddress, ExternalSymbol +def : Pat<(i16 (MSP430Wrapper tglobaladdr:$dst)), (MOV16ri tglobaladdr:$dst)>; +def : Pat<(i16 (MSP430Wrapper texternalsym:$dst)), (MOV16ri texternalsym:$dst)>; +def : Pat<(i16 (MSP430Wrapper tblockaddress:$dst)), (MOV16ri tblockaddress:$dst)>; + +def : Pat<(add GR16:$src, (MSP430Wrapper tglobaladdr :$src2)), + (ADD16ri GR16:$src, tglobaladdr:$src2)>; +def : Pat<(add GR16:$src, (MSP430Wrapper texternalsym:$src2)), + (ADD16ri GR16:$src, texternalsym:$src2)>; +def : Pat<(add GR16:$src, (MSP430Wrapper tblockaddress:$src2)), + (ADD16ri GR16:$src, tblockaddress:$src2)>; + +def : Pat<(store (i16 (MSP430Wrapper tglobaladdr:$src)), addr:$dst), + (MOV16mi addr:$dst, tglobaladdr:$src)>; +def : Pat<(store (i16 (MSP430Wrapper texternalsym:$src)), addr:$dst), + (MOV16mi addr:$dst, texternalsym:$src)>; +def : Pat<(store (i16 (MSP430Wrapper tblockaddress:$src)), addr:$dst), + (MOV16mi addr:$dst, tblockaddress:$src)>; + +// calls +def : Pat<(MSP430call (i16 tglobaladdr:$dst)), + (CALLi tglobaladdr:$dst)>; +def : Pat<(MSP430call (i16 texternalsym:$dst)), + (CALLi texternalsym:$dst)>; + +// add and sub always produce carry +def : Pat<(addc GR16:$src, GR16:$src2), + (ADD16rr GR16:$src, GR16:$src2)>; +def : Pat<(addc GR16:$src, (load addr:$src2)), + (ADD16rm GR16:$src, addr:$src2)>; +def : Pat<(addc GR16:$src, imm:$src2), + (ADD16ri GR16:$src, imm:$src2)>; +def : Pat<(store (addc (load addr:$dst), GR16:$src), addr:$dst), + (ADD16mr addr:$dst, GR16:$src)>; +def : Pat<(store (addc (load addr:$dst), (i16 (load addr:$src))), addr:$dst), + (ADD16mm addr:$dst, addr:$src)>; + +def : Pat<(addc GR8:$src, GR8:$src2), + (ADD8rr GR8:$src, GR8:$src2)>; +def : Pat<(addc GR8:$src, (load addr:$src2)), + (ADD8rm GR8:$src, addr:$src2)>; +def : Pat<(addc GR8:$src, imm:$src2), + (ADD8ri GR8:$src, imm:$src2)>; +def : Pat<(store (addc (load addr:$dst), GR8:$src), addr:$dst), + (ADD8mr addr:$dst, GR8:$src)>; +def : Pat<(store (addc (load addr:$dst), (i8 (load addr:$src))), addr:$dst), + (ADD8mm addr:$dst, addr:$src)>; + +def : Pat<(subc GR16:$src, GR16:$src2), + (SUB16rr GR16:$src, GR16:$src2)>; +def : Pat<(subc GR16:$src, (load addr:$src2)), + (SUB16rm GR16:$src, addr:$src2)>; +def : Pat<(subc GR16:$src, imm:$src2), + (SUB16ri GR16:$src, imm:$src2)>; +def : Pat<(store (subc (load addr:$dst), GR16:$src), addr:$dst), + (SUB16mr addr:$dst, GR16:$src)>; +def : Pat<(store (subc (load addr:$dst), (i16 (load addr:$src))), addr:$dst), + (SUB16mm addr:$dst, addr:$src)>; + +def : Pat<(subc GR8:$src, GR8:$src2), + (SUB8rr GR8:$src, GR8:$src2)>; +def : Pat<(subc GR8:$src, (load addr:$src2)), + (SUB8rm GR8:$src, addr:$src2)>; +def : Pat<(subc GR8:$src, imm:$src2), + (SUB8ri GR8:$src, imm:$src2)>; +def : Pat<(store (subc (load addr:$dst), GR8:$src), addr:$dst), + (SUB8mr addr:$dst, GR8:$src)>; +def : Pat<(store (subc (load addr:$dst), (i8 (load addr:$src))), addr:$dst), + (SUB8mm addr:$dst, addr:$src)>; + +// peephole patterns +def : Pat<(and GR16:$src, 255), (ZEXT16r GR16:$src)>; +def : Pat<(MSP430cmp (trunc (and_su GR16:$src, GR16:$src2)), 0), + (BIT8rr (EXTRACT_SUBREG GR16:$src, subreg_8bit), + (EXTRACT_SUBREG GR16:$src2, subreg_8bit))>; diff --git a/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.cpp new file mode 100644 index 0000000..3f44944 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.cpp @@ -0,0 +1,26 @@ +//===-- MSP430MCAsmInfo.cpp - MSP430 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 MSP430MCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MSP430MCAsmInfo.h" +using namespace llvm; + +MSP430MCAsmInfo::MSP430MCAsmInfo(const Target &T, StringRef TT) { + PrivateGlobalPrefix = ".L"; + WeakRefDirective ="\t.weak\t"; + PCSymbol="."; + CommentString = ";"; + + AlignmentIsInBytes = false; + AllowNameToStartWithDigit = true; + UsesELFSectionDirectiveForBSS = true; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.h new file mode 100644 index 0000000..f3138a2 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430MCAsmInfo.h @@ -0,0 +1,29 @@ +//=====-- MSP430MCAsmInfo.h - MSP430 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 MSP430MCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430TARGETASMINFO_H +#define MSP430TARGETASMINFO_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + class Target; + + struct MSP430MCAsmInfo : public MCAsmInfo { + explicit MSP430MCAsmInfo(const Target &T, StringRef TT); + }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h new file mode 100644 index 0000000..383fd2e --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h @@ -0,0 +1,46 @@ +//===- MSP430MachineFuctionInfo.h - MSP430 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 MSP430-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430MACHINEFUNCTIONINFO_H +#define MSP430MACHINEFUNCTIONINFO_H + +#include "llvm/CodeGen/MachineFunction.h" + +namespace llvm { + +/// MSP430MachineFunctionInfo - This class is derived from MachineFunction and +/// contains private MSP430 target-specific information for each MachineFunction. +class MSP430MachineFunctionInfo : public MachineFunctionInfo { + /// CalleeSavedFrameSize - Size of the callee-saved register portion of the + /// stack frame in bytes. + unsigned CalleeSavedFrameSize; + + /// ReturnAddrIndex - FrameIndex for return slot. + int ReturnAddrIndex; + +public: + MSP430MachineFunctionInfo() : CalleeSavedFrameSize(0) {} + + explicit MSP430MachineFunctionInfo(MachineFunction &MF) + : CalleeSavedFrameSize(0), ReturnAddrIndex(0) {} + + unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } + void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } + + int getRAIndex() const { return ReturnAddrIndex; } + void setRAIndex(int Index) { ReturnAddrIndex = Index; } +}; + +} // End llvm namespace + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp new file mode 100644 index 0000000..3c3fa73 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp @@ -0,0 +1,381 @@ +//===- MSP430RegisterInfo.cpp - MSP430 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 MSP430 implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "msp430-reg-info" + +#include "MSP430.h" +#include "MSP430MachineFunctionInfo.h" +#include "MSP430RegisterInfo.h" +#include "MSP430TargetMachine.h" +#include "llvm/Function.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +// FIXME: Provide proper call frame setup / destroy opcodes. +MSP430RegisterInfo::MSP430RegisterInfo(MSP430TargetMachine &tm, + const TargetInstrInfo &tii) + : MSP430GenRegisterInfo(MSP430::ADJCALLSTACKDOWN, MSP430::ADJCALLSTACKUP), + TM(tm), TII(tii) { + StackAlign = TM.getFrameInfo()->getStackAlignment(); +} + +const unsigned* +MSP430RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + const Function* F = MF->getFunction(); + static const unsigned CalleeSavedRegs[] = { + MSP430::FPW, MSP430::R5W, MSP430::R6W, MSP430::R7W, + MSP430::R8W, MSP430::R9W, MSP430::R10W, MSP430::R11W, + 0 + }; + static const unsigned CalleeSavedRegsFP[] = { + MSP430::R5W, MSP430::R6W, MSP430::R7W, + MSP430::R8W, MSP430::R9W, MSP430::R10W, MSP430::R11W, + 0 + }; + static const unsigned CalleeSavedRegsIntr[] = { + MSP430::FPW, MSP430::R5W, MSP430::R6W, MSP430::R7W, + MSP430::R8W, MSP430::R9W, MSP430::R10W, MSP430::R11W, + MSP430::R12W, MSP430::R13W, MSP430::R14W, MSP430::R15W, + 0 + }; + static const unsigned CalleeSavedRegsIntrFP[] = { + MSP430::R5W, MSP430::R6W, MSP430::R7W, + MSP430::R8W, MSP430::R9W, MSP430::R10W, MSP430::R11W, + MSP430::R12W, MSP430::R13W, MSP430::R14W, MSP430::R15W, + 0 + }; + + if (hasFP(*MF)) + return (F->getCallingConv() == CallingConv::MSP430_INTR ? + CalleeSavedRegsIntrFP : CalleeSavedRegsFP); + else + return (F->getCallingConv() == CallingConv::MSP430_INTR ? + CalleeSavedRegsIntr : CalleeSavedRegs); + +} + +BitVector MSP430RegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + + // Mark 4 special registers as reserved. + Reserved.set(MSP430::PCW); + Reserved.set(MSP430::SPW); + Reserved.set(MSP430::SRW); + Reserved.set(MSP430::CGW); + + // Mark frame pointer as reserved if needed. + if (hasFP(MF)) + Reserved.set(MSP430::FPW); + + return Reserved; +} + +const TargetRegisterClass * +MSP430RegisterInfo::getPointerRegClass(unsigned Kind) const { + return &MSP430::GR16RegClass; +} + + +bool MSP430RegisterInfo::hasFP(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + + return (DisableFramePointerElim(MF) || + MF.getFrameInfo()->hasVarSizedObjects() || + MFI->isFrameAddressTaken()); +} + +bool MSP430RegisterInfo::hasReservedCallFrame(const MachineFunction &MF) const { + return !MF.getFrameInfo()->hasVarSizedObjects(); +} + +void MSP430RegisterInfo:: +eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const { + if (!hasReservedCallFrame(MF)) { + // If the stack pointer can be changed after prologue, turn the + // adjcallstackup instruction into a 'sub SPW, <amt>' and the + // adjcallstackdown instruction into 'add SPW, <amt>' + // TODO: consider using push / pop instead of sub + store / add + MachineInstr *Old = I; + uint64_t Amount = Old->getOperand(0).getImm(); + if (Amount != 0) { + // We need to keep the stack aligned properly. To do this, we round the + // amount of space needed for the outgoing arguments up to the next + // alignment boundary. + Amount = (Amount+StackAlign-1)/StackAlign*StackAlign; + + MachineInstr *New = 0; + if (Old->getOpcode() == getCallFrameSetupOpcode()) { + New = BuildMI(MF, Old->getDebugLoc(), + TII.get(MSP430::SUB16ri), MSP430::SPW) + .addReg(MSP430::SPW).addImm(Amount); + } else { + assert(Old->getOpcode() == getCallFrameDestroyOpcode()); + // factor out the amount the callee already popped. + uint64_t CalleeAmt = Old->getOperand(1).getImm(); + Amount -= CalleeAmt; + if (Amount) + New = BuildMI(MF, Old->getDebugLoc(), + TII.get(MSP430::ADD16ri), MSP430::SPW) + .addReg(MSP430::SPW).addImm(Amount); + } + + if (New) { + // The SRW implicit def is dead. + New->getOperand(3).setIsDead(); + + // Replace the pseudo instruction with a new instruction... + MBB.insert(I, New); + } + } + } else if (I->getOpcode() == getCallFrameDestroyOpcode()) { + // If we are performing frame pointer elimination and if the callee pops + // something off the stack pointer, add it back. + if (uint64_t CalleeAmt = I->getOperand(1).getImm()) { + MachineInstr *Old = I; + MachineInstr *New = + BuildMI(MF, Old->getDebugLoc(), TII.get(MSP430::SUB16ri), + MSP430::SPW).addReg(MSP430::SPW).addImm(CalleeAmt); + // The SRW implicit def is dead. + New->getOperand(3).setIsDead(); + + MBB.insert(I, New); + } + } + + MBB.erase(I); +} + +void +MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected"); + + unsigned i = 0; + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + DebugLoc dl = MI.getDebugLoc(); + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + int FrameIndex = MI.getOperand(i).getIndex(); + + unsigned BasePtr = (hasFP(MF) ? MSP430::FPW : MSP430::SPW); + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex); + + // Skip the saved PC + Offset += 2; + + if (!hasFP(MF)) + Offset += MF.getFrameInfo()->getStackSize(); + else + Offset += 2; // Skip the saved FPW + + // Fold imm into offset + Offset += MI.getOperand(i+1).getImm(); + + if (MI.getOpcode() == MSP430::ADD16ri) { + // This is actually "load effective address" of the stack slot + // instruction. We have only two-address instructions, thus we need to + // expand it into mov + add + + MI.setDesc(TII.get(MSP430::MOV16rr)); + MI.getOperand(i).ChangeToRegister(BasePtr, false); + + if (Offset == 0) + return; + + // We need to materialize the offset via add instruction. + unsigned DstReg = MI.getOperand(0).getReg(); + if (Offset < 0) + BuildMI(MBB, llvm::next(II), dl, TII.get(MSP430::SUB16ri), DstReg) + .addReg(DstReg).addImm(-Offset); + else + BuildMI(MBB, llvm::next(II), dl, TII.get(MSP430::ADD16ri), DstReg) + .addReg(DstReg).addImm(Offset); + + return; + } + + MI.getOperand(i).ChangeToRegister(BasePtr, false); + MI.getOperand(i+1).ChangeToImmediate(Offset); +} + +void +MSP430RegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF) + const { + // Create a frame entry for the FPW register that must be saved. + if (hasFP(MF)) { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(2, -4, true); + (void)FrameIdx; + assert(FrameIdx == MF.getFrameInfo()->getObjectIndexBegin() && + "Slot for FPW register must be last in order to be found!"); + } +} + + +void MSP430RegisterInfo::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); // Prolog goes in entry BB + MachineFrameInfo *MFI = MF.getFrameInfo(); + MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + + // Get the number of bytes to allocate from the FrameInfo. + uint64_t StackSize = MFI->getStackSize(); + + uint64_t NumBytes = 0; + if (hasFP(MF)) { + // Calculate required stack adjustment + uint64_t FrameSize = StackSize - 2; + NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize(); + + // Get the offset of the stack slot for the EBP register... which is + // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. + // Update the frame offset adjustment. + MFI->setOffsetAdjustment(-NumBytes); + + // Save FPW into the appropriate stack slot... + BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r)) + .addReg(MSP430::FPW, RegState::Kill); + + // Update FPW with the new base value... + BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::FPW) + .addReg(MSP430::SPW); + + // Mark the FramePtr as live-in in every block except the entry. + for (MachineFunction::iterator I = llvm::next(MF.begin()), E = MF.end(); + I != E; ++I) + I->addLiveIn(MSP430::FPW); + + } else + NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize(); + + // Skip the callee-saved push instructions. + while (MBBI != MBB.end() && (MBBI->getOpcode() == MSP430::PUSH16r)) + ++MBBI; + + if (MBBI != MBB.end()) + DL = MBBI->getDebugLoc(); + + if (NumBytes) { // adjust stack pointer: SPW -= numbytes + // If there is an SUB16ri of SPW immediately before this instruction, merge + // the two. + //NumBytes -= mergeSPUpdates(MBB, MBBI, true); + // If there is an ADD16ri or SUB16ri of SPW immediately after this + // instruction, merge the two instructions. + // mergeSPUpdatesDown(MBB, MBBI, &NumBytes); + + if (NumBytes) { + MachineInstr *MI = + BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SPW) + .addReg(MSP430::SPW).addImm(NumBytes); + // The SRW implicit def is dead. + MI->getOperand(3).setIsDead(); + } + } +} + +void MSP430RegisterInfo::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); + MachineBasicBlock::iterator MBBI = prior(MBB.end()); + unsigned RetOpcode = MBBI->getOpcode(); + DebugLoc DL = MBBI->getDebugLoc(); + + switch (RetOpcode) { + case MSP430::RET: + case MSP430::RETI: break; // These are ok + default: + llvm_unreachable("Can only insert epilog into returning blocks"); + } + + // Get the number of bytes to allocate from the FrameInfo + uint64_t StackSize = MFI->getStackSize(); + unsigned CSSize = MSP430FI->getCalleeSavedFrameSize(); + uint64_t NumBytes = 0; + + if (hasFP(MF)) { + // Calculate required stack adjustment + uint64_t FrameSize = StackSize - 2; + NumBytes = FrameSize - CSSize; + + // pop FPW. + BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::FPW); + } else + NumBytes = StackSize - CSSize; + + // Skip the callee-saved pop instructions. + while (MBBI != MBB.begin()) { + MachineBasicBlock::iterator PI = prior(MBBI); + unsigned Opc = PI->getOpcode(); + if (Opc != MSP430::POP16r && !PI->getDesc().isTerminator()) + break; + --MBBI; + } + + DL = MBBI->getDebugLoc(); + + // If there is an ADD16ri or SUB16ri of SPW immediately before this + // instruction, merge the two instructions. + //if (NumBytes || MFI->hasVarSizedObjects()) + // mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes); + + if (MFI->hasVarSizedObjects()) { + BuildMI(MBB, MBBI, DL, + TII.get(MSP430::MOV16rr), MSP430::SPW).addReg(MSP430::FPW); + if (CSSize) { + MachineInstr *MI = + BuildMI(MBB, MBBI, DL, + TII.get(MSP430::SUB16ri), MSP430::SPW) + .addReg(MSP430::SPW).addImm(CSSize); + // The SRW implicit def is dead. + MI->getOperand(3).setIsDead(); + } + } else { + // adjust stack pointer back: SPW += numbytes + if (NumBytes) { + MachineInstr *MI = + BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SPW) + .addReg(MSP430::SPW).addImm(NumBytes); + // The SRW implicit def is dead. + MI->getOperand(3).setIsDead(); + } + } +} + +unsigned MSP430RegisterInfo::getRARegister() const { + return MSP430::PCW; +} + +unsigned MSP430RegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return hasFP(MF) ? MSP430::FPW : MSP430::SPW; +} + +int MSP430RegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { + llvm_unreachable("Not implemented yet!"); + return 0; +} + +#include "MSP430GenRegisterInfo.inc" diff --git a/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.h new file mode 100644 index 0000000..4d2795b --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.h @@ -0,0 +1,67 @@ +//===- MSP430RegisterInfo.h - MSP430 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 MSP430 implementation of the MRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MSP430REGISTERINFO_H +#define LLVM_TARGET_MSP430REGISTERINFO_H + +#include "llvm/Target/TargetRegisterInfo.h" +#include "MSP430GenRegisterInfo.h.inc" + +namespace llvm { + +class TargetInstrInfo; +class MSP430TargetMachine; + +struct MSP430RegisterInfo : public MSP430GenRegisterInfo { +private: + MSP430TargetMachine &TM; + const TargetInstrInfo &TII; + + /// StackAlign - Default stack alignment. + /// + unsigned StackAlign; +public: + MSP430RegisterInfo(MSP430TargetMachine &tm, const TargetInstrInfo &tii); + + /// Code Generation virtual methods... + const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + const TargetRegisterClass* getPointerRegClass(unsigned Kind = 0) const; + + bool hasFP(const MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const; + + void eliminateCallFramePseudoInstr(MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) const; + + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; + + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; + + // Debug information queries. + unsigned getRARegister() const; + unsigned getFrameRegister(const MachineFunction &MF) const; + + //! Get DWARF debugging register number + int getDwarfRegNum(unsigned RegNum, bool isEH) const; +}; + +} // end namespace llvm + +#endif // LLVM_TARGET_MSP430REGISTERINFO_H diff --git a/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.td b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.td new file mode 100644 index 0000000..f8aec66 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430RegisterInfo.td @@ -0,0 +1,119 @@ +//===- MSP430RegisterInfo.td - MSP430 Register defs ----------*- tblgen -*-===// +// +// 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 MSP430 register file +//===----------------------------------------------------------------------===// + +class MSP430Reg<bits<4> num, string n> : Register<n> { + field bits<4> Num = num; + let Namespace = "MSP430"; +} + +class MSP430RegWithSubregs<bits<4> num, string n, list<Register> subregs> + : RegisterWithSubRegs<n, subregs> { + field bits<4> Num = num; + let Namespace = "MSP430"; +} + +//===----------------------------------------------------------------------===// +// Registers +//===----------------------------------------------------------------------===// + +def PCB : MSP430Reg<0, "r0">; +def SPB : MSP430Reg<1, "r1">; +def SRB : MSP430Reg<2, "r2">; +def CGB : MSP430Reg<3, "r3">; +def FPB : MSP430Reg<4, "r4">; +def R5B : MSP430Reg<5, "r5">; +def R6B : MSP430Reg<6, "r6">; +def R7B : MSP430Reg<7, "r7">; +def R8B : MSP430Reg<8, "r8">; +def R9B : MSP430Reg<9, "r9">; +def R10B : MSP430Reg<10, "r10">; +def R11B : MSP430Reg<11, "r11">; +def R12B : MSP430Reg<12, "r12">; +def R13B : MSP430Reg<13, "r13">; +def R14B : MSP430Reg<14, "r14">; +def R15B : MSP430Reg<15, "r15">; + +def subreg_8bit : SubRegIndex { let Namespace = "MSP430"; } + +let SubRegIndices = [subreg_8bit] in { +def PCW : MSP430RegWithSubregs<0, "r0", [PCB]>; +def SPW : MSP430RegWithSubregs<1, "r1", [SPB]>; +def SRW : MSP430RegWithSubregs<2, "r2", [SRB]>; +def CGW : MSP430RegWithSubregs<3, "r3", [CGB]>; +def FPW : MSP430RegWithSubregs<4, "r4", [FPB]>; +def R5W : MSP430RegWithSubregs<5, "r5", [R5B]>; +def R6W : MSP430RegWithSubregs<6, "r6", [R6B]>; +def R7W : MSP430RegWithSubregs<7, "r7", [R7B]>; +def R8W : MSP430RegWithSubregs<8, "r8", [R8B]>; +def R9W : MSP430RegWithSubregs<9, "r9", [R9B]>; +def R10W : MSP430RegWithSubregs<10, "r10", [R10B]>; +def R11W : MSP430RegWithSubregs<11, "r11", [R11B]>; +def R12W : MSP430RegWithSubregs<12, "r12", [R12B]>; +def R13W : MSP430RegWithSubregs<13, "r13", [R13B]>; +def R14W : MSP430RegWithSubregs<14, "r14", [R14B]>; +def R15W : MSP430RegWithSubregs<15, "r15", [R15B]>; +} + +def GR8 : RegisterClass<"MSP430", [i8], 8, + // Volatile registers + [R12B, R13B, R14B, R15B, R11B, R10B, R9B, R8B, R7B, R6B, R5B, + // Frame pointer, sometimes allocable + FPB, + // Volatile, but not allocable + PCB, SPB, SRB, CGB]> +{ + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + GR8Class::iterator + GR8Class::allocation_order_end(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const TargetRegisterInfo *RI = TM.getRegisterInfo(); + // Depending on whether the function uses frame pointer or not, last 5 or 4 + // registers on the list above are reserved + if (RI->hasFP(MF)) + return end()-5; + else + return end()-4; + } + }]; +} + +def GR16 : RegisterClass<"MSP430", [i16], 16, + // Volatile registers + [R12W, R13W, R14W, R15W, R11W, R10W, R9W, R8W, R7W, R6W, R5W, + // Frame pointer, sometimes allocable + FPW, + // Volatile, but not allocable + PCW, SPW, SRW, CGW]> +{ + let SubRegClasses = [(GR8 subreg_8bit)]; + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + GR16Class::iterator + GR16Class::allocation_order_end(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const TargetRegisterInfo *RI = TM.getRegisterInfo(); + // Depending on whether the function uses frame pointer or not, last 5 or 4 + // registers on the list above are reserved + if (RI->hasFP(MF)) + return end()-5; + else + return end()-4; + } + }]; +} + diff --git a/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.cpp b/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.cpp new file mode 100644 index 0000000..24f45fa --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.cpp @@ -0,0 +1,23 @@ +//===-- MSP430SelectionDAGInfo.cpp - MSP430 SelectionDAG Info -------------===// +// +// 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 MSP430SelectionDAGInfo class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "msp430-selectiondag-info" +#include "MSP430TargetMachine.h" +using namespace llvm; + +MSP430SelectionDAGInfo::MSP430SelectionDAGInfo(const MSP430TargetMachine &TM) + : TargetSelectionDAGInfo(TM) { +} + +MSP430SelectionDAGInfo::~MSP430SelectionDAGInfo() { +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.h b/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.h new file mode 100644 index 0000000..fa81948 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430SelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- MSP430SelectionDAGInfo.h - MSP430 SelectionDAG 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 defines the MSP430 subclass for TargetSelectionDAGInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430SELECTIONDAGINFO_H +#define MSP430SELECTIONDAGINFO_H + +#include "llvm/Target/TargetSelectionDAGInfo.h" + +namespace llvm { + +class MSP430TargetMachine; + +class MSP430SelectionDAGInfo : public TargetSelectionDAGInfo { +public: + explicit MSP430SelectionDAGInfo(const MSP430TargetMachine &TM); + ~MSP430SelectionDAGInfo(); +}; + +} + +#endif diff --git a/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.cpp b/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.cpp new file mode 100644 index 0000000..1346cb9 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.cpp @@ -0,0 +1,25 @@ +//===- MSP430Subtarget.cpp - MSP430 Subtarget 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 implements the MSP430 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#include "MSP430Subtarget.h" +#include "MSP430.h" +#include "MSP430GenSubtarget.inc" + +using namespace llvm; + +MSP430Subtarget::MSP430Subtarget(const std::string &TT, const std::string &FS) { + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.h b/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.h new file mode 100644 index 0000000..1070544 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430Subtarget.h @@ -0,0 +1,38 @@ +//====-- MSP430Subtarget.h - Define Subtarget for the MSP430 ---*- 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 MSP430 specific subclass of TargetSubtarget. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_MSP430_SUBTARGET_H +#define LLVM_TARGET_MSP430_SUBTARGET_H + +#include "llvm/Target/TargetSubtarget.h" + +#include <string> + +namespace llvm { + +class MSP430Subtarget : public TargetSubtarget { + bool ExtendedInsts; +public: + /// This constructor initializes the data members to match that + /// of the specified triple. + /// + MSP430Subtarget(const std::string &TT, const std::string &FS); + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. + std::string ParseSubtargetFeatures(const std::string &FS, + const std::string &CPU); +}; +} // End llvm namespace + +#endif // LLVM_TARGET_MSP430_SUBTARGET_H diff --git a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp new file mode 100644 index 0000000..99877c8 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -0,0 +1,52 @@ +//===-- MSP430TargetMachine.cpp - Define TargetMachine for MSP430 ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Top-level implementation for the MSP430 target. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "MSP430MCAsmInfo.h" +#include "MSP430TargetMachine.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +extern "C" void LLVMInitializeMSP430Target() { + // Register the target. + RegisterTargetMachine<MSP430TargetMachine> X(TheMSP430Target); + RegisterAsmInfo<MSP430MCAsmInfo> Z(TheMSP430Target); +} + +MSP430TargetMachine::MSP430TargetMachine(const Target &T, + const std::string &TT, + const std::string &FS) : + LLVMTargetMachine(T, TT), + Subtarget(TT, FS), + // FIXME: Check TargetData string. + DataLayout("e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16"), + InstrInfo(*this), TLInfo(*this), TSInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsDown, 2, -2) { } + + +bool MSP430TargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Install an instruction selector. + PM.add(createMSP430ISelDag(*this, OptLevel)); + return false; +} + +bool MSP430TargetMachine::addPreEmitPass(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Must run branch selection immediately preceding the asm printer. + PM.add(createMSP430BranchSelectionPass()); + return false; +} diff --git a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.h b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.h new file mode 100644 index 0000000..b93edfd --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.h @@ -0,0 +1,69 @@ +//==-- MSP430TargetMachine.h - Define TargetMachine for MSP430 ---*- 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 MSP430 specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_TARGET_MSP430_TARGETMACHINE_H +#define LLVM_TARGET_MSP430_TARGETMACHINE_H + +#include "MSP430InstrInfo.h" +#include "MSP430ISelLowering.h" +#include "MSP430SelectionDAGInfo.h" +#include "MSP430RegisterInfo.h" +#include "MSP430Subtarget.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +/// MSP430TargetMachine +/// +class MSP430TargetMachine : public LLVMTargetMachine { + MSP430Subtarget Subtarget; + const TargetData DataLayout; // Calculates type size & alignment + MSP430InstrInfo InstrInfo; + MSP430TargetLowering TLInfo; + MSP430SelectionDAGInfo TSInfo; + + // MSP430 does not have any call stack frame, therefore not having + // any MSP430 specific FrameInfo class. + TargetFrameInfo FrameInfo; + +public: + MSP430TargetMachine(const Target &T, const std::string &TT, + const std::string &FS); + + virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } + virtual const MSP430InstrInfo *getInstrInfo() const { return &InstrInfo; } + virtual const TargetData *getTargetData() const { return &DataLayout;} + virtual const MSP430Subtarget *getSubtargetImpl() const { return &Subtarget; } + + virtual const TargetRegisterInfo *getRegisterInfo() const { + return &InstrInfo.getRegisterInfo(); + } + + virtual const MSP430TargetLowering *getTargetLowering() const { + return &TLInfo; + } + + virtual const MSP430SelectionDAGInfo* getSelectionDAGInfo() const { + return &TSInfo; + } + + virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel); +}; // MSP430TargetMachine. + +} // end namespace llvm + +#endif // LLVM_TARGET_MSP430_TARGETMACHINE_H diff --git a/contrib/llvm/lib/Target/MSP430/Makefile b/contrib/llvm/lib/Target/MSP430/Makefile new file mode 100644 index 0000000..b1f33d6 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/Makefile @@ -0,0 +1,24 @@ +##===- lib/Target/MSP430/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 = LLVMMSP430CodeGen +TARGET = MSP430 + +# Make sure that tblgen is run, first thing. +BUILT_SOURCES = MSP430GenRegisterInfo.h.inc MSP430GenRegisterNames.inc \ + MSP430GenRegisterInfo.inc MSP430GenInstrNames.inc \ + MSP430GenInstrInfo.inc MSP430GenAsmWriter.inc \ + MSP430GenDAGISel.inc MSP430GenCallingConv.inc \ + MSP430GenSubtarget.inc + +DIRS = AsmPrinter TargetInfo + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/Target/MSP430/README.txt b/contrib/llvm/lib/Target/MSP430/README.txt new file mode 100644 index 0000000..5b9634b --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/README.txt @@ -0,0 +1,40 @@ +//===---------------------------------------------------------------------===// +// MSP430 backend. +//===---------------------------------------------------------------------===// + +DISCLAIMER: Thid backend should be considered as highly experimental. I never +seen nor worked with this MCU, all information was gathered from datasheet +only. The original intention of making this backend was to write documentation +of form "How to write backend for dummies" :) Thes notes hopefully will be +available pretty soon. + +Some things are incomplete / not implemented yet (this list surely is not +complete as well): + +1. Verify, how stuff is handling implicit zext with 8 bit operands (this might +be modelled currently in improper way - should we need to mark the superreg as +def for every 8 bit instruction?). + +2. Libcalls: multiplication, division, remainder. Note, that calling convention +for libcalls is incomptible with calling convention of libcalls of msp430-gcc +(these cannot be used though due to license restriction). + +3. Implement multiplication / division by constant (dag combiner hook?). + +4. Implement non-constant shifts. + +5. Implement varargs stuff. + +6. Verify and fix (if needed) how's stuff playing with i32 / i64. + +7. Implement floating point stuff (softfp?) + +8. Implement instruction encoding for (possible) direct code emission in the +future. + +9. Since almost all instructions set flags - implement brcond / select in better +way (currently they emit explicit comparison). + +10. Handle imm in comparisons in better way (see comment in MSP430InstrInfo.td) + +11. Implement hooks for better memory op folding, etc. diff --git a/contrib/llvm/lib/Target/MSP430/TargetInfo/CMakeLists.txt b/contrib/llvm/lib/Target/MSP430/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000..1d408d0 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/TargetInfo/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) + +add_llvm_library(LLVMMSP430Info + MSP430TargetInfo.cpp + ) + +add_dependencies(LLVMMSP430Info MSP430Table_gen) diff --git a/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp b/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp new file mode 100644 index 0000000..f9ca5c4 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/TargetInfo/MSP430TargetInfo.cpp @@ -0,0 +1,20 @@ +//===-- MSP430TargetInfo.cpp - MSP430 Target Implementation ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "llvm/Module.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +Target llvm::TheMSP430Target; + +extern "C" void LLVMInitializeMSP430TargetInfo() { + RegisterTarget<Triple::msp430> + X(TheMSP430Target, "msp430", "MSP430 [experimental]"); +} diff --git a/contrib/llvm/lib/Target/MSP430/TargetInfo/Makefile b/contrib/llvm/lib/Target/MSP430/TargetInfo/Makefile new file mode 100644 index 0000000..abb08f2 --- /dev/null +++ b/contrib/llvm/lib/Target/MSP430/TargetInfo/Makefile @@ -0,0 +1,15 @@ +##===- lib/Target/MSP430/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 = LLVMMSP430Info + +# 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 |