diff options
| author | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
|---|---|---|
| committer | Ed Schouten <ed@FreeBSD.org> | 2009-06-02 17:52:33 +0000 |
| commit | 009b1c42aa6266385f2c37e227516b24077e6dd7 (patch) | |
| tree | 64ba909838c23261cace781ece27d106134ea451 /lib/Target/MSP430 | |
Notes
Diffstat (limited to 'lib/Target/MSP430')
24 files changed, 3537 insertions, 0 deletions
diff --git a/lib/Target/MSP430/CMakeLists.txt b/lib/Target/MSP430/CMakeLists.txt new file mode 100644 index 000000000000..67017733cd9c --- /dev/null +++ b/lib/Target/MSP430/CMakeLists.txt @@ -0,0 +1,23 @@ +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(MSP430 + MSP430AsmPrinter.cpp + MSP430FrameInfo.cpp + MSP430InstrInfo.cpp + MSP430ISelDAGToDAG.cpp + MSP430ISelLowering.cpp + MSP430RegisterInfo.cpp + MSP430Subtarget.cpp + MSP430TargetAsmInfo.cpp + MSP430TargetMachine.cpp + ) diff --git a/lib/Target/MSP430/MSP430.h b/lib/Target/MSP430/MSP430.h new file mode 100644 index 000000000000..ed0cd0496aaa --- /dev/null +++ b/lib/Target/MSP430/MSP430.h @@ -0,0 +1,40 @@ +//==-- 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 llvm { + class MSP430TargetMachine; + class FunctionPass; + class raw_ostream; + + FunctionPass *createMSP430ISelDag(MSP430TargetMachine &TM, + CodeGenOpt::Level OptLevel); + FunctionPass *createMSP430CodePrinterPass(raw_ostream &o, + MSP430TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose); +} // 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/lib/Target/MSP430/MSP430.td b/lib/Target/MSP430/MSP430.td new file mode 100644 index 000000000000..89313ab59c1b --- /dev/null +++ b/lib/Target/MSP430/MSP430.td @@ -0,0 +1,60 @@ +//===- 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 {} + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def MSP430 : Target { + let InstructionSet = MSP430InstrInfo; +} + diff --git a/lib/Target/MSP430/MSP430AsmPrinter.cpp b/lib/Target/MSP430/MSP430AsmPrinter.cpp new file mode 100644 index 000000000000..71b785bb4fe5 --- /dev/null +++ b/lib/Target/MSP430/MSP430AsmPrinter.cpp @@ -0,0 +1,267 @@ +//===-- 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 "MSP430TargetMachine.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DwarfWriter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetData.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Mangler.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +STATISTIC(EmittedInsts, "Number of machine instrs printed"); + +namespace { + class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter { + public: + MSP430AsmPrinter(raw_ostream &O, MSP430TargetMachine &TM, + const TargetAsmInfo *TAI, + CodeGenOpt::Level OL, bool V) + : AsmPrinter(O, TM, TAI, OL, V) {} + + virtual const char *getPassName() const { + return "MSP430 Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int OpNum, + const char* Modifier = 0); + void printSrcMemOperand(const MachineInstr *MI, int OpNum, + const char* Modifier = 0); + void printCCOperand(const MachineInstr *MI, int OpNum); + bool printInstruction(const MachineInstr *MI); // autogenerated. + void printMachineInstruction(const MachineInstr * MI); + + void emitFunctionHeader(const MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + + void getAnalysisUsage(AnalysisUsage &AU) const { + AsmPrinter::getAnalysisUsage(AU); + AU.setPreservesAll(); + } + }; +} // end of anonymous namespace + +#include "MSP430GenAsmWriter.inc" + +/// createMSP430CodePrinterPass - Returns a pass that prints the MSP430 +/// assembly code for a MachineFunction to the given output stream, +/// using the given target machine description. This should work +/// regardless of whether the function is in SSA form. +/// +FunctionPass *llvm::createMSP430CodePrinterPass(raw_ostream &o, + MSP430TargetMachine &tm, + CodeGenOpt::Level OptLevel, + bool verbose) { + return new MSP430AsmPrinter(o, tm, tm.getTargetAsmInfo(), OptLevel, verbose); +} + +bool MSP430AsmPrinter::doInitialization(Module &M) { + Mang = new Mangler(M, "", TAI->getPrivateGlobalPrefix()); + return false; // success +} + + +bool MSP430AsmPrinter::doFinalization(Module &M) { + return AsmPrinter::doFinalization(M); +} + +void MSP430AsmPrinter::emitFunctionHeader(const MachineFunction &MF) { + const Function *F = MF.getFunction(); + + SwitchToSection(TAI->SectionForGlobal(F)); + + unsigned FnAlign = 4; + if (F->hasFnAttr(Attribute::OptimizeForSize)) + FnAlign = 1; + + EmitAlignment(FnAlign, F); + + switch (F->getLinkage()) { + default: assert(0 && "Unknown linkage type!"); + case Function::InternalLinkage: // Symbols default to internal. + case Function::PrivateLinkage: + break; + case Function::ExternalLinkage: + O << "\t.globl\t" << CurrentFnName << '\n'; + break; + case Function::LinkOnceAnyLinkage: + case Function::LinkOnceODRLinkage: + case Function::WeakAnyLinkage: + case Function::WeakODRLinkage: + O << "\t.weak\t" << CurrentFnName << '\n'; + break; + } + + printVisibility(CurrentFnName, F->getVisibility()); + + O << "\t.type\t" << CurrentFnName << ",@function\n" + << CurrentFnName << ":\n"; +} + +bool MSP430AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + SetupMachineFunction(MF); + O << "\n\n"; + + // Print the 'header' of function + emitFunctionHeader(MF); + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + if (!VerboseAsm && (I->pred_empty() || I->isOnlyReachableByFallthrough())) { + // This is an entry block or a block that's only reachable via a + // fallthrough edge. In non-VerboseAsm mode, don't print the label. + } else { + printBasicBlockLabel(I, true, true, VerboseAsm); + O << '\n'; + } + + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) + // Print the assembly for the instruction. + printMachineInstruction(II); + } + + if (TAI->hasDotTypeDotSizeDirective()) + O << "\t.size\t" << CurrentFnName << ", .-" << CurrentFnName << '\n'; + + O.flush(); + + // We didn't modify anything + return false; +} + +void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) { + ++EmittedInsts; + + // Call the autogenerated instruction printer routines. + if (printInstruction(MI)) + return; + + assert(0 && "Should not happen"); +} + +void MSP430AsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + const char* Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + switch (MO.getType()) { + case MachineOperand::MO_Register: + assert (TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && + "Virtual registers should be already mapped!"); + O << TM.getRegisterInfo()->get(MO.getReg()).AsmName; + return; + case MachineOperand::MO_Immediate: + if (!Modifier || strcmp(Modifier, "nohash")) + O << '#'; + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + printBasicBlockLabel(MO.getMBB()); + return; + case MachineOperand::MO_GlobalAddress: { + bool isMemOp = Modifier && !strcmp(Modifier, "mem"); + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + std::string Name = Mang->getValueName(MO.getGlobal()); + assert(MO.getOffset() == 0 && "No offsets allowed!"); + + if (isCallOp) + O << '#'; + else if (isMemOp) + O << '&'; + + O << Name; + + return; + } + case MachineOperand::MO_ExternalSymbol: { + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + std::string Name(TAI->getGlobalPrefix()); + Name += MO.getSymbolName(); + if (isCallOp) + O << '#'; + O << Name; + return; + } + default: + assert(0 && "Not implemented yet!"); + } +} + +void MSP430AsmPrinter::printSrcMemOperand(const MachineInstr *MI, int OpNum, + const char* Modifier) { + const MachineOperand &Base = MI->getOperand(OpNum); + const MachineOperand &Disp = MI->getOperand(OpNum+1); + + if (Base.isGlobal()) + printOperand(MI, OpNum, "mem"); + else if (Disp.isImm() && !Base.getReg()) + printOperand(MI, OpNum); + else if (Base.getReg()) { + if (Disp.getImm()) { + printOperand(MI, OpNum + 1, "nohash"); + O << '('; + printOperand(MI, OpNum); + O << ')'; + } else { + O << '@'; + printOperand(MI, OpNum); + } + } else + assert(0 && "Unsupported memory operand"); +} + +void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { + unsigned CC = MI->getOperand(OpNum).getImm(); + + switch (CC) { + default: + assert(0 && "Unsupported CC code"); + break; + case MSP430::COND_E: + O << "eq"; + break; + case MSP430::COND_NE: + O << "ne"; + break; + case MSP430::COND_HS: + O << "hs"; + break; + case MSP430::COND_LO: + O << "lo"; + break; + case MSP430::COND_GE: + O << "ge"; + break; + case MSP430::COND_L: + O << 'l'; + break; + } +} diff --git a/lib/Target/MSP430/MSP430CallingConv.td b/lib/Target/MSP430/MSP430CallingConv.td new file mode 100644 index 000000000000..ad27cc9122a8 --- /dev/null +++ b/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/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp new file mode 100644 index 000000000000..bf49ec0bff46 --- /dev/null +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -0,0 +1,194 @@ +//===-- 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 "MSP430ISelLowering.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" +using namespace llvm; + +/// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine +/// instructions for SelectionDAG operations. +/// +namespace { + class MSP430DAGToDAGISel : public SelectionDAGISel { + MSP430TargetLowering &Lowering; + const MSP430Subtarget &Subtarget; + + public: + MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel), + Lowering(*TM.getTargetLowering()), + Subtarget(*TM.getSubtargetImpl()) { } + + virtual void InstructionSelect(); + + virtual const char *getPassName() const { + return "MSP430 DAG->DAG Pattern Instruction Selection"; + } + + // Include the pieces autogenerated from the target description. + #include "MSP430GenDAGISel.inc" + + private: + SDNode *Select(SDValue Op); + bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp); + + #ifndef NDEBUG + unsigned Indent; + #endif + }; +} // 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); +} + +// FIXME: This is pretty dummy routine and needs to be rewritten in the future. +bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, + SDValue &Base, SDValue &Disp) { + // Try to match frame address first. + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); + Disp = CurDAG->getTargetConstant(0, MVT::i16); + return true; + } + + switch (Addr.getOpcode()) { + case ISD::ADD: + // Operand is a result from ADD with constant operand which fits into i16. + if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { + uint64_t CVal = CN->getZExtValue(); + // Offset should fit into 16 bits. + if (((CVal << 48) >> 48) == CVal) { + SDValue N0 = Addr.getOperand(0); + if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N0)) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); + else + Base = N0; + + Disp = CurDAG->getTargetConstant(CVal, MVT::i16); + return true; + } + } + break; + case MSP430ISD::Wrapper: + SDValue N0 = Addr.getOperand(0); + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) { + Base = CurDAG->getTargetGlobalAddress(G->getGlobal(), + MVT::i16, G->getOffset()); + Disp = CurDAG->getTargetConstant(0, MVT::i16); + return true; + } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(N0)) { + Base = CurDAG->getTargetExternalSymbol(E->getSymbol(), MVT::i16); + Disp = CurDAG->getTargetConstant(0, MVT::i16); + } + break; + }; + + Base = Addr; + Disp = CurDAG->getTargetConstant(0, MVT::i16); + + return true; +} + + + +/// InstructionSelect - This callback is invoked by +/// SelectionDAGISel when it has created a SelectionDAG for us to codegen. +void MSP430DAGToDAGISel::InstructionSelect() { + DEBUG(BB->dump()); + + // Codegen the basic block. +#ifndef NDEBUG + DOUT << "===== Instruction selection begins:\n"; + Indent = 0; +#endif + SelectRoot(*CurDAG); +#ifndef NDEBUG + DOUT << "===== Instruction selection ends:\n"; +#endif + + CurDAG->RemoveDeadNodes(); +} + +SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { + SDNode *Node = Op.getNode(); + DebugLoc dl = Op.getDebugLoc(); + + // Dump information about the Node being selected + #ifndef NDEBUG + DOUT << std::string(Indent, ' ') << "Selecting: "; + DEBUG(Node->dump(CurDAG)); + DOUT << "\n"; + Indent += 2; + #endif + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "== "; + DEBUG(Node->dump(CurDAG)); + DOUT << "\n"; + Indent -= 2; + #endif + return NULL; + } + + // Few custom selection stuff. + switch (Node->getOpcode()) { + default: break; + case ISD::FrameIndex: { + assert(Op.getValueType() == 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->getTargetNode(MSP430::ADD16ri, dl, MVT::i16, + TFI, CurDAG->getTargetConstant(0, MVT::i16)); + } + } + + // Select the default instruction + SDNode *ResNode = SelectCode(Op); + + #ifndef NDEBUG + DOUT << std::string(Indent-2, ' ') << "=> "; + if (ResNode == NULL || ResNode == Op.getNode()) + DEBUG(Op.getNode()->dump(CurDAG)); + else + DEBUG(ResNode->dump(CurDAG)); + DOUT << "\n"; + Indent -= 2; + #endif + + return ResNode; +} diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp new file mode 100644 index 000000000000..14db20e5fcd6 --- /dev/null +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -0,0 +1,670 @@ +//===-- 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 "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/ValueTypes.h" +#include "llvm/Support/Debug.h" +#include "llvm/ADT/VectorExtras.h" +using namespace llvm; + +MSP430TargetLowering::MSP430TargetLowering(MSP430TargetMachine &tm) : + TargetLowering(tm), Subtarget(*tm.getSubtargetImpl()), TM(tm) { + + // 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(SchedulingForLatency); + + 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::RET, MVT::Other, Custom); + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::ExternalSymbol, MVT::i16, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BRIND, 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, Expand); + setOperationAction(ISD::SETCC, MVT::i16, Expand); + 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); + + // FIXME: Implement efficiently multiplication by a constant + 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::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); +} + +SDValue MSP430TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { + switch (Op.getOpcode()) { + case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); + case ISD::SHL: // FALLTHROUGH + case ISD::SRL: + case ISD::SRA: return LowerShifts(Op, DAG); + case ISD::RET: return LowerRET(Op, DAG); + case ISD::CALL: return LowerCALL(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::ExternalSymbol: return LowerExternalSymbol(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); + default: + assert(0 && "unimplemented operand"); + return SDValue(); + } +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +#include "MSP430GenCallingConv.inc" + +SDValue MSP430TargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, + SelectionDAG &DAG) { + unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); + switch (CC) { + default: + assert(0 && "Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + return LowerCCCArguments(Op, DAG); + } +} + +SDValue MSP430TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { + CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); + unsigned CallingConv = TheCall->getCallingConv(); + switch (CallingConv) { + default: + assert(0 && "Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + return LowerCCCCallTo(Op, DAG, CallingConv); + } +} + +/// 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 Op, + SelectionDAG &DAG) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + SDValue Root = Op.getOperand(0); + bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; + unsigned CC = MF.getFunction()->getCallingConv(); + DebugLoc dl = Op.getDebugLoc(); + + // Assign locations to all of the incoming arguments. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_MSP430); + + assert(!isVarArg && "Varargs not supported yet"); + + SmallVector<SDValue, 16> ArgValues; + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // Arguments passed in registers + MVT RegVT = VA.getLocVT(); + switch (RegVT.getSimpleVT()) { + default: + cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " + << RegVT.getSimpleVT() + << "\n"; + abort(); + case MVT::i16: + unsigned VReg = + RegInfo.createVirtualRegister(MSP430::GR16RegisterClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Root, 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); + + ArgValues.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) { + cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " + << VA.getLocVT().getSimpleVT() + << "\n"; + } + // Create the frame index object for this incoming parameter... + int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset()); + + // Create the SelectionDAG nodes corresponding to a load + //from this parameter + SDValue FIN = DAG.getFrameIndex(FI, MVT::i16); + ArgValues.push_back(DAG.getLoad(VA.getLocVT(), dl, Root, FIN, + PseudoSourceValue::getFixedStack(FI), 0)); + } + } + + ArgValues.push_back(Root); + + // Return the new list of results. + return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), + &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); +} + +SDValue MSP430TargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { + // CCValAssign - represent the assignment of the return value to a location + SmallVector<CCValAssign, 16> RVLocs; + unsigned CC = DAG.getMachineFunction().getFunction()->getCallingConv(); + bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); + DebugLoc dl = Op.getDebugLoc(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs); + + // Analize return values of ISD::RET + CCInfo.AnalyzeReturn(Op.getNode(), 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()); + } + + // The chain is always operand #0 + SDValue Chain = Op.getOperand(0); + 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!"); + + // ISD::RET => ret chain, (regnum1,val1), ... + // So i*2+1 index only the regnums + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), + Op.getOperand(i*2+1), Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + } + + if (Flag.getNode()) + return DAG.getNode(MSP430ISD::RET_FLAG, dl, MVT::Other, Chain, Flag); + + // Return Void + return DAG.getNode(MSP430ISD::RET_FLAG, 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 Op, SelectionDAG &DAG, + unsigned CC) { + CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); + SDValue Chain = TheCall->getChain(); + SDValue Callee = TheCall->getCallee(); + bool isVarArg = TheCall->isVarArg(); + DebugLoc dl = Op.getDebugLoc(); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector<CCValAssign, 16> ArgLocs; + CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); + + CCInfo.AnalyzeCallOperands(TheCall, 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]; + + // Arguments start after the 5 first operands of ISD::CALL + SDValue Arg = TheCall->getArg(i); + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: assert(0 && "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())); + } + } + + // 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(), 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 SDValue(LowerCallResult(Chain, InFlag, TheCall, CC, DAG), + Op.getResNo()); +} + +/// LowerCallResult - Lower the result values of an ISD::CALL into the +/// appropriate copies out of appropriate physical registers. This assumes that +/// Chain/InFlag are the input chain/flag to use, and that TheCall is the call +/// being lowered. Returns a SDNode with the same number of values as the +/// ISD::CALL. +SDNode* +MSP430TargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, + CallSDNode *TheCall, + unsigned CallingConv, + SelectionDAG &DAG) { + bool isVarArg = TheCall->isVarArg(); + DebugLoc dl = TheCall->getDebugLoc(); + + // Assign locations to each value returned by this call. + SmallVector<CCValAssign, 16> RVLocs; + CCState CCInfo(CallingConv, isVarArg, getTargetMachine(), RVLocs); + + CCInfo.AnalyzeCallResult(TheCall, RetCC_MSP430); + SmallVector<SDValue, 8> ResultVals; + + // 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); + ResultVals.push_back(Chain.getValue(0)); + } + + ResultVals.push_back(Chain); + + // Merge everything together with a MERGE_VALUES node. + return DAG.getNode(ISD::MERGE_VALUES, dl, TheCall->getVTList(), + &ResultVals[0], ResultVals.size()).getNode(); +} + +SDValue MSP430TargetLowering::LowerShifts(SDValue Op, + SelectionDAG &DAG) { + unsigned Opc = Op.getOpcode(); + SDNode* N = Op.getNode(); + MVT VT = Op.getValueType(); + DebugLoc dl = N->getDebugLoc(); + + // We currently only lower shifts of constant argument. + if (!isa<ConstantSDNode>(N->getOperand(1))) + return SDValue(); + + 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 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, getPointerTy(), Offset); + return DAG.getNode(MSP430ISD::Wrapper, Op.getDebugLoc(), + getPointerTy(), Result); +} + +SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op, + SelectionDAG &DAG) { + 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);; +} + +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, unsigned &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 + TargetCC = MSP430::COND_INVALID; + switch (CC) { + default: assert(0 && "Invalid integer condition!"); + case ISD::SETEQ: + TargetCC = MSP430::COND_E; // aka COND_Z + break; + case ISD::SETNE: + TargetCC = MSP430::COND_NE; // aka COND_NZ + break; + case ISD::SETULE: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETUGE: + TargetCC = MSP430::COND_HS; // aka COND_C + break; + case ISD::SETUGT: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETULT: + TargetCC = MSP430::COND_LO; // aka COND_NC + break; + case ISD::SETLE: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETGE: + TargetCC = MSP430::COND_GE; + break; + case ISD::SETGT: + std::swap(LHS, RHS); // FALLTHROUGH + case ISD::SETLT: + TargetCC = MSP430::COND_L; + break; + } + + return DAG.getNode(MSP430ISD::CMP, dl, MVT::Flag, LHS, RHS); +} + + +SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { + 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(); + + unsigned TargetCC = MSP430::COND_INVALID; + SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); + + return DAG.getNode(MSP430ISD::BR_CC, dl, Op.getValueType(), + Chain, + Dest, DAG.getConstant(TargetCC, MVT::i8), + Flag); +} + +SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { + 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(); + + unsigned TargetCC = MSP430::COND_INVALID; + 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(DAG.getConstant(TargetCC, MVT::i8)); + Ops.push_back(Flag); + + return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); +} + +SDValue MSP430TargetLowering::LowerSIGN_EXTEND(SDValue Op, + SelectionDAG &DAG) { + SDValue Val = Op.getOperand(0); + MVT 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())); +} + +const char *MSP430TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch (Opcode) { + default: return NULL; + case MSP430ISD::RET_FLAG: return "MSP430ISD::RET_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"; + } +} + +//===----------------------------------------------------------------------===// +// Other Lowering Code +//===----------------------------------------------------------------------===// + +MachineBasicBlock* +MSP430TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + assert((MI->getOpcode() == MSP430::Select16 || + MI->getOpcode() == 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); + BuildMI(BB, dl, TII.get(MSP430::JCC)) + .addMBB(copy1MBB) + .addImm(MI->getOperand(3).getImm()); + 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->transferSuccessors(BB); + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(copy0MBB); + BB->addSuccessor(copy1MBB); + + // 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, dl, TII.get(MSP430::PHI), + MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return BB; +} diff --git a/lib/Target/MSP430/MSP430ISelLowering.h b/lib/Target/MSP430/MSP430ISelLowering.h new file mode 100644 index 000000000000..404534dde89e --- /dev/null +++ b/lib/Target/MSP430/MSP430ISelLowering.h @@ -0,0 +1,103 @@ +//==-- 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, + + /// Y = R{R,L}A X, rotate right (left) arithmetically + RRA, RLA, + + /// Y = RRC X, rotate right via carry + RRC, + + /// CALL/TAILCALL - 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 + }; + } + + 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); + + /// getTargetNodeName - This method returns the name of a target specific + /// DAG node. + virtual const char *getTargetNodeName(unsigned Opcode) const; + + SDValue LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG); + SDValue LowerCALL(SDValue Op, SelectionDAG &DAG); + SDValue LowerRET(SDValue Op, SelectionDAG &DAG); + SDValue LowerCCCArguments(SDValue Op, SelectionDAG &DAG); + SDValue LowerShifts(SDValue Op, SelectionDAG &DAG); + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG); + SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG); + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG); + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG); + SDValue LowerSIGN_EXTEND(SDValue Op, SelectionDAG &DAG); + + SDValue LowerCCCCallTo(SDValue Op, SelectionDAG &DAG, + unsigned CC); + SDNode* LowerCallResult(SDValue Chain, SDValue InFlag, + CallSDNode *TheCall, + unsigned CallingConv, SelectionDAG &DAG); + + MachineBasicBlock* EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const; + + private: + const MSP430Subtarget &Subtarget; + const MSP430TargetMachine &TM; + }; +} // namespace llvm + +#endif // LLVM_TARGET_MSP430_ISELLOWERING_H diff --git a/lib/Target/MSP430/MSP430InstrFormats.td b/lib/Target/MSP430/MSP430InstrFormats.td new file mode 100644 index 000000000000..61b339901648 --- /dev/null +++ b/lib/Target/MSP430/MSP430InstrFormats.td @@ -0,0 +1,67 @@ +//===- 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 +// + +// Generic MSP430 Format +class MSP430Inst<dag outs, dag ins, string asmstr> : Instruction { + field bits<16> Inst; + + let Namespace = "MSP430"; + + dag OutOperandList = outs; + dag InOperandList = ins; + + let AsmString = asmstr; +} + +// FIXME: Create different classes for different addressing modes. + +// MSP430 Double Operand (Format I) Instructions +class IForm<bits<4> opcode, bit ad, bit bw, bits<2> as, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, asmstr> { + let Pattern = pattern; + + let Inst{12-15} = opcode; + let Inst{7} = ad; + let Inst{6} = bw; + let Inst{4-5} = as; +} + +// MSP430 Single Operand (Format II) Instructions +class IIForm<bits<9> opcode, bit bw, bits<2> ad, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, asmstr> { + let Pattern = pattern; + + let Inst{7-15} = opcode; + let Inst{6} = bw; + let Inst{4-5} = ad; +} + +// MSP430 Conditional Jumps Instructions +class CJForm<bits<3> opcode, bits<3> cond, bit s, + dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, asmstr> { + let Pattern = pattern; + + let Inst{13-15} = opcode; + let Inst{10-12} = cond; + let Inst{9} = s; +} + +// Pseudo instructions +class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> + : MSP430Inst<outs, ins, asmstr> { + let Pattern = pattern; + let Inst{15-0} = 0; +} diff --git a/lib/Target/MSP430/MSP430InstrInfo.cpp b/lib/Target/MSP430/MSP430InstrInfo.cpp new file mode 100644 index 000000000000..91112c3d732f --- /dev/null +++ b/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -0,0 +1,177 @@ +//===- 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" + +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 { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == &MSP430::GR16RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV16mr)) + .addFrameIndex(FrameIdx).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)); + else if (RC == &MSP430::GR8RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV8mr)) + .addFrameIndex(FrameIdx).addImm(0) + .addReg(SrcReg, getKillRegState(isKill)); + else + assert(0 && "Cannot store this register to stack slot!"); +} + +void MSP430InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC) const{ + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + if (RC == &MSP430::GR16RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV16rm)) + .addReg(DestReg).addFrameIndex(FrameIdx).addImm(0); + else if (RC == &MSP430::GR8RegClass) + BuildMI(MBB, MI, DL, get(MSP430::MOV8rm)) + .addReg(DestReg).addFrameIndex(FrameIdx).addImm(0); + else + assert(0 && "Cannot store this register to stack slot!"); +} + +bool MSP430InstrInfo::copyRegToReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const { + DebugLoc DL = DebugLoc::getUnknownLoc(); + if (I != MBB.end()) DL = I->getDebugLoc(); + + if (DestRC == SrcRC) { + unsigned Opc; + if (DestRC == &MSP430::GR16RegClass) { + Opc = MSP430::MOV16rr; + } else if (DestRC == &MSP430::GR8RegClass) { + Opc = MSP430::MOV8rr; + } else { + return false; + } + + BuildMI(MBB, I, DL, get(Opc), DestReg).addReg(SrcReg); + return true; + } + + return false; +} + +bool +MSP430InstrInfo::isMoveInstr(const MachineInstr& MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const { + SrcSubIdx = DstSubIdx = 0; // No sub-registers yet. + + switch (MI.getOpcode()) { + default: + return false; + case MSP430::MOV8rr: + case MSP430::MOV16rr: + assert(MI.getNumOperands() >= 2 && + MI.getOperand(0).isReg() && + MI.getOperand(1).isReg() && + "invalid register-register move instruction"); + SrcReg = MI.getOperand(1).getReg(); + DstReg = MI.getOperand(0).getReg(); + return true; + } +} + +bool +MSP430InstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI) const { + if (CSI.empty()) + return false; + + DebugLoc DL = DebugLoc::getUnknownLoc(); + 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 { + if (CSI.empty()) + return false; + + DebugLoc DL = DebugLoc::getUnknownLoc(); + 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::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const { + // FIXME this should probably have a DebugLoc operand + DebugLoc dl = DebugLoc::getUnknownLoc(); + + // 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; + assert(0 && "Implement conditional branches!"); + + return Count; +} diff --git a/lib/Target/MSP430/MSP430InstrInfo.h b/lib/Target/MSP430/MSP430InstrInfo.h new file mode 100644 index 000000000000..e07aacad9dc2 --- /dev/null +++ b/lib/Target/MSP430/MSP430InstrInfo.h @@ -0,0 +1,84 @@ +//===- 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; + +namespace MSP430 { + // MSP430 specific condition code. + enum CondCode { + 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 + }; +} + +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; } + + bool copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + unsigned DestReg, unsigned SrcReg, + const TargetRegisterClass *DestRC, + const TargetRegisterClass *SrcRC) const; + + bool isMoveInstr(const MachineInstr& MI, + unsigned &SrcReg, unsigned &DstReg, + unsigned &SrcSubIdx, unsigned &DstSubIdx) const; + + virtual void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIndex, + const TargetRegisterClass *RC) const; + virtual void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIdx, + const TargetRegisterClass *RC) const; + + virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI) const; + virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector<CalleeSavedInfo> &CSI) const; + + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; + +}; + +} + +#endif diff --git a/lib/Target/MSP430/MSP430InstrInfo.td b/lib/Target/MSP430/MSP430InstrInfo.td new file mode 100644 index 000000000000..39c08e40be46 --- /dev/null +++ b/lib/Target/MSP430/MSP430InstrInfo.td @@ -0,0 +1,901 @@ +//===- 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>]>; + +//===----------------------------------------------------------------------===// +// MSP430 Specific Node Definitions. +//===----------------------------------------------------------------------===// +def MSP430retflag : SDNode<"MSP430ISD::RET_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]>; +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]>; + +//===----------------------------------------------------------------------===// +// 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); +} + +// Branch targets have OtherVT type. +def brtarget : Operand<OtherVT>; + +// 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))>; + +//===----------------------------------------------------------------------===// +// 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 usesCustomDAGSchedInserter = 1 in { + def Select8 : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2, i8imm:$cc), + "# Select8 PSEUDO", + [(set GR8:$dst, + (MSP430selectcc GR8:$src1, GR8:$src2, imm:$cc))]>; + def Select16 : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2, i8imm:$cc), + "# Select16 PSEUDO", + [(set GR16:$dst, + (MSP430selectcc GR16:$src1, GR16:$src2, imm:$cc))]>; +} + +let neverHasSideEffects = 1 in +def NOP : Pseudo<(outs), (ins), "nop", []>; + +//===----------------------------------------------------------------------===// +// Control Flow Instructions... +// + +// FIXME: Provide proper encoding! +let isReturn = 1, isTerminator = 1 in { + def RET : Pseudo<(outs), (ins), "ret", [(MSP430retflag)]>; +} + +let isBranch = 1, isTerminator = 1 in { + +// Direct branch +let isBarrier = 1 in + def JMP : Pseudo<(outs), (ins brtarget:$dst), + "jmp\t$dst", + [(br bb:$dst)]>; + +// Conditional branches +let Uses = [SRW] in + def JCC : Pseudo<(outs), (ins brtarget:$dst, cc:$cc), + "j$cc $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 : Pseudo<(outs), (ins i16imm:$dst, variable_ops), + "call\t${dst:call}", [(MSP430call imm:$dst)]>; + def CALLr : Pseudo<(outs), (ins GR16:$dst, variable_ops), + "call\t$dst", [(MSP430call GR16:$dst)]>; + def CALLm : Pseudo<(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 : Pseudo<(outs GR16:$reg), (ins), "pop.w\t$reg", []>; + +let mayStore = 1 in +def PUSH16r : Pseudo<(outs), (ins GR16:$reg), "push.w\t$reg",[]>; +} + +//===----------------------------------------------------------------------===// +// Move Instructions + +// FIXME: Provide proper encoding! +let neverHasSideEffects = 1 in { +def MOV8rr : Pseudo<(outs GR8:$dst), (ins GR8:$src), + "mov.b\t{$src, $dst}", + []>; +def MOV16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src), + "mov.w\t{$src, $dst}", + []>; +} + +// FIXME: Provide proper encoding! +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def MOV8ri : Pseudo<(outs GR8:$dst), (ins i8imm:$src), + "mov.b\t{$src, $dst}", + [(set GR8:$dst, imm:$src)]>; +def MOV16ri : Pseudo<(outs GR16:$dst), (ins i16imm:$src), + "mov.w\t{$src, $dst}", + [(set GR16:$dst, imm:$src)]>; +} + +let canFoldAsLoad = 1, isReMaterializable = 1, mayHaveSideEffects = 1 in { +def MOV8rm : Pseudo<(outs GR8:$dst), (ins memsrc:$src), + "mov.b\t{$src, $dst}", + [(set GR8:$dst, (load addr:$src))]>; +def MOV16rm : Pseudo<(outs GR16:$dst), (ins memsrc:$src), + "mov.w\t{$src, $dst}", + [(set GR16:$dst, (load addr:$src))]>; +} + +def MOVZX16rr8 : Pseudo<(outs GR16:$dst), (ins GR8:$src), + "mov.b\t{$src, $dst}", + [(set GR16:$dst, (zext GR8:$src))]>; +def MOVZX16rm8 : Pseudo<(outs GR16:$dst), (ins memsrc:$src), + "mov.b\t{$src, $dst}", + [(set GR16:$dst, (zextloadi16i8 addr:$src))]>; + +// 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() != TargetInstrInfo::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 : Pseudo<(outs), (ins memdst:$dst, i8imm:$src), + "mov.b\t{$src, $dst}", + [(store (i8 imm:$src), addr:$dst)]>; +def MOV16mi : Pseudo<(outs), (ins memdst:$dst, i16imm:$src), + "mov.w\t{$src, $dst}", + [(store (i16 imm:$src), addr:$dst)]>; + +def MOV8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "mov.b\t{$src, $dst}", + [(store GR8:$src, addr:$dst)]>; +def MOV16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "mov.w\t{$src, $dst}", + [(store GR16:$src, addr:$dst)]>; + +//===----------------------------------------------------------------------===// +// Arithmetic Instructions + +let isTwoAddress = 1 in { + +let Defs = [SRW] in { + +let isCommutable = 1 in { // X = ADD Y, Z == X = ADD Z, Y +// FIXME: Provide proper encoding! +def ADD8rr : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def ADD16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src1, GR16:$src2)), + (implicit SRW)]>; +} + +def ADD8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def ADD16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +def ADD8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "add.b\t{$src2, $dst}", + [(set GR8:$dst, (add GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def ADD16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "add.w\t{$src2, $dst}", + [(set GR16:$dst, (add GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def ADD8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "add.b\t{$src, $dst}", + [(store (add (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def ADD16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "add.w\t{$src, $dst}", + [(store (add (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def ADD8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def ADC16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src1, GR16:$src2)), + (implicit SRW)]>; +} // isCommutable + +def ADC8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def ADC16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +def ADC8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "addc.b\t{$src2, $dst}", + [(set GR8:$dst, (adde GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def ADC16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "addc.w\t{$src2, $dst}", + [(set GR16:$dst, (adde GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def ADC8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "addc.b\t{$src, $dst}", + [(store (adde (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def ADC16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "addc.w\t{$src, $dst}", + [(store (adde (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def ADC8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def AND16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src1, GR16:$src2)), + (implicit SRW)]>; +} + +def AND8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def AND16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +def AND8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "and.b\t{$src2, $dst}", + [(set GR8:$dst, (and GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def AND16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "and.w\t{$src2, $dst}", + [(set GR16:$dst, (and GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def AND8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "and.b\t{$src, $dst}", + [(store (and (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def AND16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "and.w\t{$src, $dst}", + [(store (and (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def AND8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 = XOR Y, Z == X = XOR Z, Y +def XOR8rr : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def XOR16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src1, GR16:$src2)), + (implicit SRW)]>; +} + +def XOR8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def XOR16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +def XOR8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "xor.b\t{$src2, $dst}", + [(set GR8:$dst, (xor GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def XOR16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "xor.w\t{$src2, $dst}", + [(set GR16:$dst, (xor GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def XOR8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "xor.b\t{$src, $dst}", + [(store (xor (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def XOR16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "xor.w\t{$src, $dst}", + [(store (xor (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def XOR8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def SUB16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src1, GR16:$src2)), + (implicit SRW)]>; + +def SUB8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def SUB16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +def SUB8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "sub.b\t{$src2, $dst}", + [(set GR8:$dst, (sub GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def SUB16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "sub.w\t{$src2, $dst}", + [(set GR16:$dst, (sub GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def SUB8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "sub.b\t{$src, $dst}", + [(store (sub (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def SUB16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "sub.w\t{$src, $dst}", + [(store (sub (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def SUB8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src1, GR8:$src2)), + (implicit SRW)]>; +def SBC16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src1, GR16:$src2)), + (implicit SRW)]>; + +def SBC8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src1, imm:$src2)), + (implicit SRW)]>; +def SBC16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src1, imm:$src2)), + (implicit SRW)]>; + +def SBC8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "subc.b\t{$src2, $dst}", + [(set GR8:$dst, (sube GR8:$src1, (load addr:$src2))), + (implicit SRW)]>; +def SBC16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "subc.w\t{$src2, $dst}", + [(set GR16:$dst, (sube GR16:$src1, (load addr:$src2))), + (implicit SRW)]>; + +let isTwoAddress = 0 in { +def SBC8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "subc.b\t{$src, $dst}", + [(store (sube (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def SBC16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "subc.w\t{$src, $dst}", + [(store (sube (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def SBC8mi : Pseudo<(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 : Pseudo<(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 : Pseudo<(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 : Pseudo<(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: Provide proper encoding! +def SAR8r1 : Pseudo<(outs GR8:$dst), (ins GR8:$src), + "rra.b\t$dst", + [(set GR8:$dst, (MSP430rra GR8:$src)), + (implicit SRW)]>; +def SAR16r1 : Pseudo<(outs GR16:$dst), (ins GR16:$src), + "rra.w\t$dst", + [(set GR16:$dst, (MSP430rra GR16:$src)), + (implicit SRW)]>; + +def SHL8r1 : Pseudo<(outs GR8:$dst), (ins GR8:$src), + "rla.b\t$dst", + [(set GR8:$dst, (MSP430rla GR8:$src)), + (implicit SRW)]>; +def SHL16r1 : Pseudo<(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)]>; + +def SEXT16r : Pseudo<(outs GR16:$dst), (ins GR16:$src), + "sxt\t$dst", + [(set GR16:$dst, (sext_inreg GR16:$src, i8)), + (implicit SRW)]>; + +} // Defs = [SRW] + +def SWPB16r : Pseudo<(outs GR16:$dst), (ins GR16:$src), + "swpb\t$dst", + [(set GR16:$dst, (bswap GR16:$src))]>; + +let isCommutable = 1 in { // X = OR Y, Z == X = OR Z, Y +def OR8rr : Pseudo<(outs GR8:$dst), (ins GR8:$src1, GR8:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src1, GR8:$src2))]>; +def OR16rr : Pseudo<(outs GR16:$dst), (ins GR16:$src1, GR16:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src1, GR16:$src2))]>; +} + +def OR8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src1, imm:$src2))]>; +def OR16ri : Pseudo<(outs GR16:$dst), (ins GR16:$src1, i16imm:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src1, imm:$src2))]>; + +def OR8rm : Pseudo<(outs GR8:$dst), (ins GR8:$src1, memsrc:$src2), + "bis.b\t{$src2, $dst}", + [(set GR8:$dst, (or GR8:$src1, (load addr:$src2)))]>; +def OR16rm : Pseudo<(outs GR16:$dst), (ins GR16:$src1, memsrc:$src2), + "bis.w\t{$src2, $dst}", + [(set GR16:$dst, (or GR16:$src1, (load addr:$src2)))]>; + +let isTwoAddress = 0 in { +def OR8mr : Pseudo<(outs), (ins memdst:$dst, GR8:$src), + "bis.b\t{$src, $dst}", + [(store (or (load addr:$dst), GR8:$src), addr:$dst), + (implicit SRW)]>; +def OR16mr : Pseudo<(outs), (ins memdst:$dst, GR16:$src), + "bis.w\t{$src, $dst}", + [(store (or (load addr:$dst), GR16:$src), addr:$dst), + (implicit SRW)]>; + +def OR8mi : Pseudo<(outs), (ins memdst:$dst, i8imm:$src), + "bis.b\t{$src, $dst}", + [(store (or (load addr:$dst), (i8 imm:$src)), addr:$dst), + (implicit SRW)]>; +def OR16mi : Pseudo<(outs), (ins memdst:$dst, i16imm:$src), + "bis.w\t{$src, $dst}", + [(store (or (load addr:$dst), (i16 imm:$src)), addr:$dst), + (implicit SRW)]>; + +def OR8mm : Pseudo<(outs), (ins memdst:$dst, memsrc:$src), + "bis.b\t{$src, $dst}", + [(store (or (load addr:$dst), (i8 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +def OR16mm : Pseudo<(outs), (ins memdst:$dst, memsrc:$src), + "bis.w\t{$src, $dst}", + [(store (or (load addr:$dst), (i16 (load addr:$src))), addr:$dst), + (implicit SRW)]>; +} + +} // isTwoAddress = 1 + +// Integer comparisons +let Defs = [SRW] in { +def CMP8rr : Pseudo<(outs), (ins GR8:$src1, GR8:$src2), + "cmp.b\t{$src1, $src2}", + [(MSP430cmp GR8:$src1, GR8:$src2), (implicit SRW)]>; +def CMP16rr : Pseudo<(outs), (ins GR16:$src1, GR16:$src2), + "cmp.w\t{$src1, $src2}", + [(MSP430cmp GR16:$src1, GR16:$src2), (implicit SRW)]>; + +def CMP8ir : Pseudo<(outs), (ins i8imm:$src1, GR8:$src2), + "cmp.b\t{$src1, $src2}", + [(MSP430cmp imm:$src1, GR8:$src2), (implicit SRW)]>; +def CMP16ir : Pseudo<(outs), (ins i16imm:$src1, GR16:$src2), + "cmp.w\t{$src1, $src2}", + [(MSP430cmp imm:$src1, GR16:$src2), (implicit SRW)]>; + +def CMP8im : Pseudo<(outs), (ins i8imm:$src1, memsrc:$src2), + "cmp.b\t{$src1, $src2}", + [(MSP430cmp (i8 imm:$src1), (load addr:$src2)), (implicit SRW)]>; +def CMP16im : Pseudo<(outs), (ins i16imm:$src1, memsrc:$src2), + "cmp.w\t{$src1, $src2}", + [(MSP430cmp (i16 imm:$src1), (load addr:$src2)), (implicit SRW)]>; + +// FIXME: imm is allowed only on src operand, not on dst. + +//def CMP8ri : Pseudo<(outs), (ins GR8:$src1, i8imm:$src2), +// "cmp.b\t{$src1, $src2}", +// [(MSP430cmp GR8:$src1, imm:$src2), (implicit SRW)]>; +//def CMP16ri : Pseudo<(outs), (ins GR16:$src1, i16imm:$src2), +// "cmp.w\t{$src1, $src2}", +// [(MSP430cmp GR16:$src1, imm:$src2), (implicit SRW)]>; + +//def CMP8mi : Pseudo<(outs), (ins memsrc:$src1, i8imm:$src2), +// "cmp.b\t{$src1, $src2}", +// [(MSP430cmp (load addr:$src1), (i8 imm:$src2)), (implicit SRW)]>; +//def CMP16mi : Pseudo<(outs), (ins memsrc:$src1, i16imm:$src2), +// "cmp.w\t{$src1, $src2}", +// [(MSP430cmp (load addr:$src1), (i16 imm:$src2)), (implicit SRW)]>; + + +// Imm 0, +1, +2, +4, +8 are encoded via constant generator registers. +// That's why we can use them as dest operands. +// We don't define new class for them, since they would need special encoding +// in the future. + +def CMP8ri0 : Pseudo<(outs), (ins GR8:$src1), + "cmp.b\t{$src1, #0}", + [(MSP430cmp GR8:$src1, 0), (implicit SRW)]>; +def CMP16ri0: Pseudo<(outs), (ins GR16:$src1), + "cmp.w\t{$src1, #0}", + [(MSP430cmp GR16:$src1, 0), (implicit SRW)]>; +def CMP8ri1 : Pseudo<(outs), (ins GR8:$src1), + "cmp.b\t{$src1, #1}", + [(MSP430cmp GR8:$src1, 1), (implicit SRW)]>; +def CMP16ri1: Pseudo<(outs), (ins GR16:$src1), + "cmp.w\t{$src1, #1}", + [(MSP430cmp GR16:$src1, 1), (implicit SRW)]>; +def CMP8ri2 : Pseudo<(outs), (ins GR8:$src1), + "cmp.b\t{$src1, #2}", + [(MSP430cmp GR8:$src1, 2), (implicit SRW)]>; +def CMP16ri2: Pseudo<(outs), (ins GR16:$src1), + "cmp.w\t{$src1, #2}", + [(MSP430cmp GR16:$src1, 2), (implicit SRW)]>; +def CMP8ri4 : Pseudo<(outs), (ins GR8:$src1), + "cmp.b\t{$src1, #4}", + [(MSP430cmp GR8:$src1, 4), (implicit SRW)]>; +def CMP16ri4: Pseudo<(outs), (ins GR16:$src1), + "cmp.w\t{$src1, #4}", + [(MSP430cmp GR16:$src1, 4), (implicit SRW)]>; +def CMP8ri8 : Pseudo<(outs), (ins GR8:$src1), + "cmp.b\t{$src1, #8}", + [(MSP430cmp GR8:$src1, 8), (implicit SRW)]>; +def CMP16ri8: Pseudo<(outs), (ins GR16:$src1), + "cmp.w\t{$src1, #8}", + [(MSP430cmp GR16:$src1, 8), (implicit SRW)]>; + +def CMP8rm : Pseudo<(outs), (ins GR8:$src1, memsrc:$src2), + "cmp.b\t{$src1, $src2}", + [(MSP430cmp GR8:$src1, (load addr:$src2)), (implicit SRW)]>; +def CMP16rm : Pseudo<(outs), (ins GR16:$src1, memsrc:$src2), + "cmp.w\t{$src1, $src2}", + [(MSP430cmp GR16:$src1, (load addr:$src2)), (implicit SRW)]>; + +def CMP8mr : Pseudo<(outs), (ins memsrc:$src1, GR8:$src2), + "cmp.b\t{$src1, $src2}", + [(MSP430cmp (load addr:$src1), GR8:$src2), (implicit SRW)]>; +def CMP16mr : Pseudo<(outs), (ins memsrc:$src1, GR16:$src2), + "cmp.w\t{$src1, $src2}", + [(MSP430cmp (load addr:$src1), GR16:$src2), (implicit SRW)]>; + +def CMP8mi0 : Pseudo<(outs), (ins memsrc:$src1), + "cmp.b\t{$src1, #0}", + [(MSP430cmp (load addr:$src1), (i8 0)), (implicit SRW)]>; +def CMP16mi0: Pseudo<(outs), (ins memsrc:$src1), + "cmp.w\t{$src1, #0}", + [(MSP430cmp (load addr:$src1), (i16 0)), (implicit SRW)]>; +def CMP8mi1 : Pseudo<(outs), (ins memsrc:$src1), + "cmp.b\t{$src1, #1}", + [(MSP430cmp (load addr:$src1), (i8 1)), (implicit SRW)]>; +def CMP16mi1: Pseudo<(outs), (ins memsrc:$src1), + "cmp.w\t{$src1, #1}", + [(MSP430cmp (load addr:$src1), (i16 1)), (implicit SRW)]>; +def CMP8mi2 : Pseudo<(outs), (ins memsrc:$src1), + "cmp.b\t{$src1, #2}", + [(MSP430cmp (load addr:$src1), (i8 2)), (implicit SRW)]>; +def CMP16mi2: Pseudo<(outs), (ins memsrc:$src1), + "cmp.w\t{$src1, #2}", + [(MSP430cmp (load addr:$src1), (i16 2)), (implicit SRW)]>; +def CMP8mi4 : Pseudo<(outs), (ins memsrc:$src1), + "cmp.b\t{$src1, #4}", + [(MSP430cmp (load addr:$src1), (i8 4)), (implicit SRW)]>; +def CMP16mi4: Pseudo<(outs), (ins memsrc:$src1), + "cmp.w\t{$src1, #4}", + [(MSP430cmp (load addr:$src1), (i16 4)), (implicit SRW)]>; +def CMP8mi8 : Pseudo<(outs), (ins memsrc:$src1), + "cmp.b\t{$src1, #8}", + [(MSP430cmp (load addr:$src1), (i8 8)), (implicit SRW)]>; +def CMP16mi8: Pseudo<(outs), (ins memsrc:$src1), + "cmp.w\t{$src1, #8}", + [(MSP430cmp (load addr:$src1), (i16 8)), (implicit SRW)]>; + +} // Defs = [SRW] + +//===----------------------------------------------------------------------===// +// Non-Instruction Patterns + +// extload +def : Pat<(extloadi16i8 addr:$src), (MOVZX16rm8 addr:$src)>; + +// anyext +def : Pat<(anyext addr:$src), (MOVZX16rr8 GR8:$src)>; + +// 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<(add GR16:$src1, (MSP430Wrapper tglobaladdr :$src2)), + (ADD16ri GR16:$src1, tglobaladdr:$src2)>; +def : Pat<(add GR16:$src1, (MSP430Wrapper texternalsym:$src2)), + (ADD16ri GR16:$src1, texternalsym:$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)>; + +// 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:$src1, GR16:$src2), + (ADD16rr GR16:$src1, GR16:$src2)>; +def : Pat<(addc GR16:$src1, (load addr:$src2)), + (ADD16rm GR16:$src1, addr:$src2)>; +def : Pat<(addc GR16:$src1, imm:$src2), + (ADD16ri GR16:$src1, 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:$src1, GR8:$src2), + (ADD8rr GR8:$src1, GR8:$src2)>; +def : Pat<(addc GR8:$src1, (load addr:$src2)), + (ADD8rm GR8:$src1, addr:$src2)>; +def : Pat<(addc GR8:$src1, imm:$src2), + (ADD8ri GR8:$src1, 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:$src1, GR16:$src2), + (SUB16rr GR16:$src1, GR16:$src2)>; +def : Pat<(subc GR16:$src1, (load addr:$src2)), + (SUB16rm GR16:$src1, addr:$src2)>; +def : Pat<(subc GR16:$src1, imm:$src2), + (SUB16ri GR16:$src1, 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:$src1, GR8:$src2), + (SUB8rr GR8:$src1, GR8:$src2)>; +def : Pat<(subc GR8:$src1, (load addr:$src2)), + (SUB8rm GR8:$src1, addr:$src2)>; +def : Pat<(subc GR8:$src1, imm:$src2), + (SUB8ri GR8:$src1, 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)>; diff --git a/lib/Target/MSP430/MSP430MachineFunctionInfo.h b/lib/Target/MSP430/MSP430MachineFunctionInfo.h new file mode 100644 index 000000000000..b94d7e44cace --- /dev/null +++ b/lib/Target/MSP430/MSP430MachineFunctionInfo.h @@ -0,0 +1,39 @@ +//===- 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; + +public: + MSP430MachineFunctionInfo() : CalleeSavedFrameSize(0) {} + + MSP430MachineFunctionInfo(MachineFunction &MF) : CalleeSavedFrameSize(0) {} + + unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } + void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } +}; + +} // End llvm namespace + +#endif diff --git a/lib/Target/MSP430/MSP430RegisterInfo.cpp b/lib/Target/MSP430/MSP430RegisterInfo.cpp new file mode 100644 index 000000000000..ef6f99756c2e --- /dev/null +++ b/lib/Target/MSP430/MSP430RegisterInfo.cpp @@ -0,0 +1,355 @@ +//===- 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/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" + +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 { + static const unsigned CalleeSavedRegs[] = { + MSP430::FPW, MSP430::R5W, MSP430::R6W, MSP430::R7W, + MSP430::R8W, MSP430::R9W, MSP430::R10W, MSP430::R11W, + 0 + }; + + return CalleeSavedRegs; +} + +const TargetRegisterClass* const* +MSP430RegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const { + static const TargetRegisterClass * const CalleeSavedRegClasses[] = { + &MSP430::GR16RegClass, &MSP430::GR16RegClass, + &MSP430::GR16RegClass, &MSP430::GR16RegClass, + &MSP430::GR16RegClass, &MSP430::GR16RegClass, + &MSP430::GR16RegClass, &MSP430::GR16RegClass, + 0 + }; + + return CalleeSavedRegClasses; +} + +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() const { + return &MSP430::GR16RegClass; +} + + +bool MSP430RegisterInfo::hasFP(const MachineFunction &MF) const { + return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects(); +} + +bool MSP430RegisterInfo::hasReservedCallFrame(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, next(II), dl, TII.get(MSP430::SUB16ri), DstReg) + .addReg(DstReg).addImm(-Offset); + else + BuildMI(MBB, 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); + assert(FrameIdx == MF.getFrameInfo()->getObjectIndexBegin() && + "Slot for FPW register must be last in order to be found!"); + FrameIdx = 0; + } +} + + +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::getUnknownLoc()); + + // 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 = 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: break; // These are ok + default: + assert(0 && "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. + MachineBasicBlock::iterator LastCSPop = MBBI; + 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()) { + assert(0 && "Not implemented yet!"); + } 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(MachineFunction &MF) const { + return hasFP(MF) ? MSP430::FPW : MSP430::SPW; +} + +int MSP430RegisterInfo::getDwarfRegNum(unsigned RegNum, bool isEH) const { + assert(0 && "Not implemented yet!"); +} + +#include "MSP430GenRegisterInfo.inc" diff --git a/lib/Target/MSP430/MSP430RegisterInfo.h b/lib/Target/MSP430/MSP430RegisterInfo.h new file mode 100644 index 000000000000..a210e36e001d --- /dev/null +++ b/lib/Target/MSP430/MSP430RegisterInfo.h @@ -0,0 +1,70 @@ +//===- 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; + + const TargetRegisterClass* const* + getCalleeSavedRegClasses(const MachineFunction *MF = 0) const; + + BitVector getReservedRegs(const MachineFunction &MF) const; + const TargetRegisterClass* getPointerRegClass() const; + + bool hasFP(const MachineFunction &MF) const; + bool hasReservedCallFrame(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(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/lib/Target/MSP430/MSP430RegisterInfo.td b/lib/Target/MSP430/MSP430RegisterInfo.td new file mode 100644 index 000000000000..4078626ea2dd --- /dev/null +++ b/lib/Target/MSP430/MSP430RegisterInfo.td @@ -0,0 +1,122 @@ +//===- 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 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 : SubRegSet<1, [PCW, SPW, SRW, CGW, FPW, + R5W, R6W, R7W, R8W, R9W, R10W, R11W, R12W, R13W, R14W, R15W], + [PCB, SPB, SRB, CGB, FPB, + R5B, R6B, R7B, R8B, R9B, R10B, R11B, R12B, R13B, R14B, R15B]>; + +def subreg_8bit : PatLeaf<(i32 1)>; + +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 SubRegClassList = [GR8]; + 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/lib/Target/MSP430/MSP430Subtarget.cpp b/lib/Target/MSP430/MSP430Subtarget.cpp new file mode 100644 index 000000000000..ef9e10339bc3 --- /dev/null +++ b/lib/Target/MSP430/MSP430Subtarget.cpp @@ -0,0 +1,27 @@ +//===- 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" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +MSP430Subtarget::MSP430Subtarget(const TargetMachine &TM, const Module &M, + const std::string &FS) { + std::string CPU = "generic"; + + // Parse features string. + ParseSubtargetFeatures(FS, CPU); +} diff --git a/lib/Target/MSP430/MSP430Subtarget.h b/lib/Target/MSP430/MSP430Subtarget.h new file mode 100644 index 000000000000..96c8108b71bc --- /dev/null +++ b/lib/Target/MSP430/MSP430Subtarget.h @@ -0,0 +1,41 @@ +//====-- 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 Module; +class TargetMachine; + +class MSP430Subtarget : public TargetSubtarget { + bool ExtendedInsts; +public: + /// This constructor initializes the data members to match that + /// of the specified module. + /// + MSP430Subtarget(const TargetMachine &TM, const Module &M, + 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/lib/Target/MSP430/MSP430TargetAsmInfo.cpp b/lib/Target/MSP430/MSP430TargetAsmInfo.cpp new file mode 100644 index 000000000000..ab181de13f94 --- /dev/null +++ b/lib/Target/MSP430/MSP430TargetAsmInfo.cpp @@ -0,0 +1,22 @@ +//===-- MSP430TargetAsmInfo.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 MSP430TargetAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "MSP430TargetAsmInfo.h" +#include "MSP430TargetMachine.h" + +using namespace llvm; + +MSP430TargetAsmInfo::MSP430TargetAsmInfo(const MSP430TargetMachine &TM) + : ELFTargetAsmInfo(TM) { + AlignmentIsInBytes = false; +} diff --git a/lib/Target/MSP430/MSP430TargetAsmInfo.h b/lib/Target/MSP430/MSP430TargetAsmInfo.h new file mode 100644 index 000000000000..b58d5c9c764c --- /dev/null +++ b/lib/Target/MSP430/MSP430TargetAsmInfo.h @@ -0,0 +1,31 @@ +//=====-- MSP430TargetAsmInfo.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 MSP430TargetAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430TARGETASMINFO_H +#define MSP430TARGETASMINFO_H + +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/ELFTargetAsmInfo.h" + +namespace llvm { + + // Forward declaration. + class MSP430TargetMachine; + + struct MSP430TargetAsmInfo : public ELFTargetAsmInfo { + explicit MSP430TargetAsmInfo(const MSP430TargetMachine &TM); + }; + +} // namespace llvm + +#endif diff --git a/lib/Target/MSP430/MSP430TargetMachine.cpp b/lib/Target/MSP430/MSP430TargetMachine.cpp new file mode 100644 index 000000000000..78869463f3a2 --- /dev/null +++ b/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -0,0 +1,76 @@ +//===-- 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 "MSP430TargetAsmInfo.h" +#include "MSP430TargetMachine.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetMachineRegistry.h" + +using namespace llvm; + +/// MSP430TargetMachineModule - Note that this is used on hosts that +/// cannot link in a library unless there are references into the +/// library. In particular, it seems that it is not possible to get +/// things to work on Win32 without this. Though it is unused, do not +/// remove it. +extern "C" int MSP430TargetMachineModule; +int MSP430TargetMachineModule = 0; + + +// Register the targets +static RegisterTarget<MSP430TargetMachine> +X("msp430", "MSP430 [experimental]"); + +MSP430TargetMachine::MSP430TargetMachine(const Module &M, + const std::string &FS) : + Subtarget(*this, M, FS), + // FIXME: Check TargetData string. + DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"), + InstrInfo(*this), TLInfo(*this), + FrameInfo(TargetFrameInfo::StackGrowsDown, 2, -2) { } + +const TargetAsmInfo *MSP430TargetMachine::createTargetAsmInfo() const { + return new MSP430TargetAsmInfo(*this); +} + +bool MSP430TargetMachine::addInstSelector(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + // Install an instruction selector. + PM.add(createMSP430ISelDag(*this, OptLevel)); + return false; +} + +bool MSP430TargetMachine::addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, + bool Verbose, + raw_ostream &Out) { + // Output assembly language. + PM.add(createMSP430CodePrinterPass(Out, *this, OptLevel, Verbose)); + return false; +} + +unsigned MSP430TargetMachine::getModuleMatchQuality(const Module &M) { + std::string TT = M.getTargetTriple(); + + // We strongly match msp430 + if (TT.size() >= 6 && TT[0] == 'm' && TT[1] == 's' && TT[2] == 'p' && + TT[3] == '4' && TT[4] == '3' && TT[5] == '0') + return 20; + + return 0; +} + diff --git a/lib/Target/MSP430/MSP430TargetMachine.h b/lib/Target/MSP430/MSP430TargetMachine.h new file mode 100644 index 000000000000..d9ffa2b5ac8f --- /dev/null +++ b/lib/Target/MSP430/MSP430TargetMachine.h @@ -0,0 +1,68 @@ +//==-- 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 "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; + + // MSP430 does not have any call stack frame, therefore not having + // any MSP430 specific FrameInfo class. + TargetFrameInfo FrameInfo; + +protected: + virtual const TargetAsmInfo *createTargetAsmInfo() const; + +public: + MSP430TargetMachine(const Module &M, 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 MSP430TargetLowering *getTargetLowering() const { + return const_cast<MSP430TargetLowering*>(&TLInfo); + } + + virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); + virtual bool addAssemblyEmitter(PassManagerBase &PM, + CodeGenOpt::Level OptLevel, bool Verbose, + raw_ostream &Out); + static unsigned getModuleMatchQuality(const Module &M); +}; // MSP430TargetMachine. + +} // end namespace llvm + +#endif // LLVM_TARGET_MSP430_TARGETMACHINE_H diff --git a/lib/Target/MSP430/Makefile b/lib/Target/MSP430/Makefile new file mode 100644 index 000000000000..45cb3aa45b85 --- /dev/null +++ b/lib/Target/MSP430/Makefile @@ -0,0 +1,21 @@ +##===- 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 = LLVMMSP430 +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 + +include $(LEVEL)/Makefile.common + diff --git a/lib/Target/MSP430/README.txt b/lib/Target/MSP430/README.txt new file mode 100644 index 000000000000..b14e93d84d6a --- /dev/null +++ b/lib/Target/MSP430/README.txt @@ -0,0 +1,42 @@ +//===---------------------------------------------------------------------===// +// 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): + +0. Implement asmprinting for variables :) + +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. |
