diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 |
commit | 4a142eb28942073eb27a112b5ca1cca3f01beb9c (patch) | |
tree | 22cc59e4b240d84c3a5a60531119c4eca914a256 /lib/Target/MSP430 | |
parent | 5cd822fa9bbb9622241e3bf4d7674ed49ccde5b9 (diff) |
Diffstat (limited to 'lib/Target/MSP430')
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp | 63 | ||||
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp | 116 | ||||
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h | 46 | ||||
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp | 147 | ||||
-rw-r--r-- | lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h | 49 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430.h | 14 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430ISelDAGToDAG.cpp | 292 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430ISelLowering.cpp | 27 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430InstrInfo.cpp | 165 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430InstrInfo.h | 30 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430InstrInfo.td | 4 | ||||
-rw-r--r-- | lib/Target/MSP430/MSP430TargetMachine.cpp | 2 |
13 files changed, 853 insertions, 104 deletions
diff --git a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt index 6e6688746463..f1eb8851b656 100644 --- a/lib/Target/MSP430/AsmPrinter/CMakeLists.txt +++ b/lib/Target/MSP430/AsmPrinter/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) add_llvm_library(LLVMMSP430AsmPrinter + MSP430InstPrinter.cpp MSP430AsmPrinter.cpp + MSP430MCInstLower.cpp ) add_dependencies(LLVMMSP430AsmPrinter MSP430CodeGenTable_gen) diff --git a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp index 852019febf5e..ace358e86d77 100644 --- a/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp +++ b/lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp @@ -15,7 +15,9 @@ #define DEBUG_TYPE "asm-printer" #include "MSP430.h" #include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" #include "MSP430MCAsmInfo.h" +#include "MSP430MCInstLower.h" #include "MSP430TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -26,12 +28,14 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Mangler.h" @@ -41,6 +45,10 @@ using namespace llvm; STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt<bool> +EnableMCInst("enable-msp430-mcinst-printer", cl::Hidden, + cl::desc("enable experimental mcinst gunk in the msp430 backend")); + namespace { class VISIBILITY_HIDDEN MSP430AsmPrinter : public AsmPrinter { public: @@ -52,8 +60,14 @@ namespace { return "MSP430 Assembly Printer"; } + void printMCInst(const MCInst *MI) { + MSP430InstPrinter(O, *MAI).printInstruction(MI); + } void printOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); + void printPCRelImmOperand(const MachineInstr *MI, int OpNum) { + printOperand(MI, OpNum); + } void printSrcMemOperand(const MachineInstr *MI, int OpNum, const char* Modifier = 0); void printCCOperand(const MachineInstr *MI, int OpNum); @@ -67,6 +81,7 @@ namespace { bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode); + void printInstructionThroughMCStreamer(const MachineInstr *MI); void emitFunctionHeader(const MachineFunction &MF); bool runOnMachineFunction(MachineFunction &F); @@ -148,7 +163,11 @@ void MSP430AsmPrinter::printMachineInstruction(const MachineInstr *MI) { processDebugLoc(MI, true); // Call the autogenerated instruction printer routines. - printInstruction(MI); + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + } else { + printInstruction(MI); + } if (VerboseAsm && !MI->getDebugLoc().isUnknown()) EmitComments(*MI); @@ -231,22 +250,22 @@ void MSP430AsmPrinter::printCCOperand(const MachineInstr *MI, int OpNum) { default: llvm_unreachable("Unsupported CC code"); break; - case MSP430::COND_E: + case MSP430CC::COND_E: O << "eq"; break; - case MSP430::COND_NE: + case MSP430CC::COND_NE: O << "ne"; break; - case MSP430::COND_HS: + case MSP430CC::COND_HS: O << "hs"; break; - case MSP430::COND_LO: + case MSP430CC::COND_LO: O << "lo"; break; - case MSP430::COND_GE: + case MSP430CC::COND_GE: O << "ge"; break; - case MSP430::COND_L: + case MSP430CC::COND_L: O << 'l'; break; } @@ -275,6 +294,36 @@ bool MSP430AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } +//===----------------------------------------------------------------------===// +void MSP430AsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) +{ + + MSP430MCInstLower MCInstLowering(OutContext, *Mang, *this); + + switch (MI->getOpcode()) { + case TargetInstrInfo::DBG_LABEL: + case TargetInstrInfo::EH_LABEL: + case TargetInstrInfo::GC_LABEL: + printLabel(MI); + return; + case TargetInstrInfo::KILL: + return; + case TargetInstrInfo::INLINEASM: + O << '\t'; + printInlineAsm(MI); + return; + case TargetInstrInfo::IMPLICIT_DEF: + printImplicitDef(MI); + return; + default: break; + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + + printMCInst(&TmpInst); +} + // Force static initialization. extern "C" void LLVMInitializeMSP430AsmPrinter() { RegisterAsmPrinter<MSP430AsmPrinter> X(TheMSP430Target); diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp new file mode 100644 index 000000000000..a3ecc674dc40 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp @@ -0,0 +1,116 @@ +//===-- MSP430InstPrinter.cpp - Convert MSP430 MCInst to assembly syntax --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "MSP430.h" +#include "MSP430InstrInfo.h" +#include "MSP430InstPrinter.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + + +// Include the auto-generated portion of the assembly writer. +#define MachineInstr MCInst +#define MSP430AsmPrinter MSP430InstPrinter // FIXME: REMOVE. +#define NO_ASM_WRITER_BOILERPLATE +#include "MSP430GenAsmWriter.inc" +#undef MachineInstr +#undef MSP430AsmPrinter + +void MSP430InstPrinter::printInst(const MCInst *MI) { + printInstruction(MI); +} + +void MSP430InstPrinter::printPCRelImmOperand(const MCInst *MI, unsigned OpNo) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) + O << Op.getImm(); + else { + assert(Op.isExpr() && "unknown pcrel immediate operand"); + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << '#' << Op.getImm(); + } else { + assert(Op.isExpr() && "unknown operand kind in printOperand"); + O << '#'; + Op.getExpr()->print(O, &MAI); + } +} + +void MSP430InstPrinter::printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier) { + const MCOperand &Base = MI->getOperand(OpNo); + const MCOperand &Disp = MI->getOperand(OpNo+1); + + // FIXME: move global to displacement field! + if (Base.isExpr()) { + O << '&'; + Base.getExpr()->print(O, &MAI); + } else if (Disp.isImm() && !Base.isReg()) + printOperand(MI, OpNo); + else if (Base.isReg()) { + if (Disp.getImm()) { + O << Disp.getImm() << '('; + printOperand(MI, OpNo); + O << ')'; + } else { + O << '@'; + printOperand(MI, OpNo); + } + } else { + Base.dump(); + Disp.dump(); + llvm_unreachable("Unsupported memory operand"); + } +} + +void MSP430InstPrinter::printCCOperand(const MCInst *MI, unsigned OpNo) { + unsigned CC = MI->getOperand(OpNo).getImm(); + + switch (CC) { + default: + llvm_unreachable("Unsupported CC code"); + break; + case MSP430CC::COND_E: + O << "eq"; + break; + case MSP430CC::COND_NE: + O << "ne"; + break; + case MSP430CC::COND_HS: + O << "hs"; + break; + case MSP430CC::COND_LO: + O << "lo"; + break; + case MSP430CC::COND_GE: + O << "ge"; + break; + case MSP430CC::COND_L: + O << 'l'; + break; + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h new file mode 100644 index 000000000000..2fac800fcd79 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h @@ -0,0 +1,46 @@ +//===-- MSP430InstPrinter.h - Convert MSP430 MCInst to assembly syntax ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints a MSP430 MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430INSTPRINTER_H +#define MSP430INSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm +{ + + class MCOperand; + + class MSP430InstPrinter : public MCInstPrinter { + public: + MSP430InstPrinter(raw_ostream &O, const MCAsmInfo &MAI) : + MCInstPrinter(O, MAI){ + } + + virtual void printInst(const MCInst *MI); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printPCRelImmOperand(const MCInst *MI, unsigned OpNo); + void printSrcMemOperand(const MCInst *MI, unsigned OpNo, + const char *Modifier = 0); + void printCCOperand(const MCInst *MI, unsigned OpNo); + + }; +} + +#endif diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp new file mode 100644 index 000000000000..f505b239b631 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp @@ -0,0 +1,147 @@ +//===-- MSP430MCInstLower.cpp - Convert MSP430 MachineInstr to an MCInst---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower MSP430 MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "MSP430MCInstLower.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Mangler.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +MCSymbol *MSP430MCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + const GlobalValue *GV = MO.getGlobal(); + + SmallString<128> Name; + Mang.getNameWithPrefix(Name, GV, false); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + SmallString<128> Name; + Name += Printer.MAI->getGlobalPrefix(); + Name += MO.getSymbolName(); + + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *MSP430MCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' + << MO.getIndex(); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand MSP430MCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case 0: break; + } + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + +void MSP430MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + Printer.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h new file mode 100644 index 000000000000..a2b99ae83c01 --- /dev/null +++ b/lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h @@ -0,0 +1,49 @@ +//===-- MSP430MCInstLower.h - Lower MachineInstr to MCInst ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef MSP430_MCINSTLOWER_H +#define MSP430_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + + /// MSP430MCInstLower - This class is used to lower an MachineInstr + /// into an MCInst. +class VISIBILITY_HIDDEN MSP430MCInstLower { + MCContext &Ctx; + Mangler &Mang; + + AsmPrinter &Printer; +public: + MSP430MCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; +}; + +} + +#endif diff --git a/lib/Target/MSP430/MSP430.h b/lib/Target/MSP430/MSP430.h index d9f5f8629541..1ff178d99d90 100644 --- a/lib/Target/MSP430/MSP430.h +++ b/lib/Target/MSP430/MSP430.h @@ -17,6 +17,20 @@ #include "llvm/Target/TargetMachine.h" +namespace MSP430CC { + // MSP430 specific condition code. + enum CondCodes { + COND_E = 0, // aka COND_Z + COND_NE = 1, // aka COND_NZ + COND_HS = 2, // aka COND_C + COND_LO = 3, // aka COND_NC + COND_GE = 4, + COND_L = 5, + + COND_INVALID = -1 + }; +} + namespace llvm { class MSP430TargetMachine; class FunctionPass; diff --git a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp index 4195a88f8de0..b7d928249c02 100644 --- a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -26,6 +26,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -34,6 +35,14 @@ using namespace llvm; +#ifndef NDEBUG +static cl::opt<bool> +ViewRMWDAGs("view-msp430-rmw-dags", cl::Hidden, + cl::desc("Pop up a window to show isel dags after RMW preprocess")); +#else +static const bool ViewRMWDAGs = false; +#endif + STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor"); /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine @@ -56,6 +65,9 @@ namespace { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + bool IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const; + virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps); @@ -64,6 +76,7 @@ namespace { #include "MSP430GenDAGISel.inc" private: + DenseMap<SDNode*, SDNode*> RMWStores; void PreprocessForRMW(); SDNode *Select(SDValue Op); bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp); @@ -130,7 +143,6 @@ bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, return true; } - bool MSP430DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps) { @@ -148,31 +160,54 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, return false; } +bool MSP430DAGToDAGISel::IsLegalAndProfitableToFold(SDNode *N, SDNode *U, + SDNode *Root) const { + if (OptLevel == CodeGenOpt::None) return false; + + /// RMW preprocessing creates the following code: + /// [Load1] + /// ^ ^ + /// / | + /// / | + /// [Load2] | + /// ^ ^ | + /// | | | + /// | \-| + /// | | + /// | [Op] + /// | ^ + /// | | + /// \ / + /// \ / + /// [Store] + /// + /// The path Store => Load2 => Load1 is via chain. Note that in general it is + /// not allowed to fold Load1 into Op (and Store) since it will creates a + /// cycle. However, this is perfectly legal for the loads moved below the + /// TokenFactor by PreprocessForRMW. Query the map Store => Load1 (created + /// during preprocessing) to determine whether it's legal to introduce such + /// "cycle" for a moment. + DenseMap<SDNode*, SDNode*>::iterator I = RMWStores.find(Root); + if (I != RMWStores.end() && I->second == N) + return true; + + // Proceed to 'generic' cycle finder code + return SelectionDAGISel::IsLegalAndProfitableToFold(N, U, Root); +} + + /// MoveBelowTokenFactor - Replace TokenFactor operand with load's chain operand /// and move load below the TokenFactor. Replace store's chain operand with /// load's chain result. -/// Shamelessly stolen from X86. static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, SDValue Store, SDValue TF) { SmallVector<SDValue, 4> Ops; - bool isRMW = false; - SDValue TF0, TF1, NewTF; for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) - if (Load.getNode() == TF.getOperand(i).getNode()) { - TF0 = Load.getOperand(0); - Ops.push_back(TF0); - } else { - TF1 = TF.getOperand(i); - Ops.push_back(TF1); - if (LoadSDNode* LD = dyn_cast<LoadSDNode>(TF1)) - isRMW = !LD->isVolatile(); - } - - if (isRMW && TF1.getOperand(0).getNode() == TF0.getNode()) - NewTF = TF0; - else - NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); - + if (Load.getNode() == TF.getOperand(i).getNode()) + Ops.push_back(Load.getOperand(0)); + else + Ops.push_back(TF.getOperand(i)); + SDValue NewTF = CurDAG->UpdateNodeOperands(TF, &Ops[0], Ops.size()); SDValue NewLoad = CurDAG->UpdateNodeOperands(Load, NewTF, Load.getOperand(1), Load.getOperand(2)); @@ -180,12 +215,43 @@ static void MoveBelowTokenFactor(SelectionDAG *CurDAG, SDValue Load, Store.getOperand(2), Store.getOperand(3)); } -/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. The chain -/// produced by the load must only be used by the store's chain operand, -/// otherwise this may produce a cycle in the DAG. -/// Shamelessly stolen from X86. FIXME: Should we make this function common? -static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, - SDValue &Load) { +/// MoveBelowTokenFactor2 - Replace TokenFactor operand with load's chain operand +/// and move load below the TokenFactor. Replace store's chain operand with +/// load's chain result. This a version which sinks two loads below token factor. +/// Look into PreprocessForRMW comments for explanation of transform. +static void MoveBelowTokenFactor2(SelectionDAG *CurDAG, + SDValue Load1, SDValue Load2, + SDValue Store, SDValue TF) { + SmallVector<SDValue, 4> Ops; + for (unsigned i = 0, e = TF.getNode()->getNumOperands(); i != e; ++i) { + SDNode* N = TF.getOperand(i).getNode(); + if (Load2.getNode() == N) + Ops.push_back(Load2.getOperand(0)); + else if (Load1.getNode() != N) + Ops.push_back(TF.getOperand(i)); + } + + SDValue NewTF = SDValue(CurDAG->MorphNodeTo(TF.getNode(), + TF.getOpcode(), + TF.getNode()->getVTList(), + &Ops[0], Ops.size()), TF.getResNo()); + SDValue NewLoad2 = CurDAG->UpdateNodeOperands(Load2, NewTF, + Load2.getOperand(1), + Load2.getOperand(2)); + + SDValue NewLoad1 = CurDAG->UpdateNodeOperands(Load1, NewLoad2.getValue(1), + Load1.getOperand(1), + Load1.getOperand(2)); + + CurDAG->UpdateNodeOperands(Store, + NewLoad1.getValue(1), + Store.getOperand(1), + Store.getOperand(2), Store.getOperand(3)); +} + +/// isAllowedToSink - return true if N a load which can be moved below token +/// factor. Basically, the load should be non-volatile and has single use. +static bool isLoadAllowedToSink(SDValue N, SDValue Chain) { if (N.getOpcode() == ISD::BIT_CONVERT) N = N.getOperand(0); @@ -199,10 +265,19 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, if (ExtType != ISD::NON_EXTLOAD && ExtType != ISD::EXTLOAD) return false; - if (N.hasOneUse() && - LD->hasNUsesOfValue(1, 1) && - N.getOperand(1) == Address && - LD->isOperandOf(Chain.getNode())) { + return (N.hasOneUse() && + LD->hasNUsesOfValue(1, 1) && + LD->isOperandOf(Chain.getNode())); +} + + +/// isRMWLoad - Return true if N is a load that's part of RMW sub-DAG. +/// The chain produced by the load must only be used by the store's chain +/// operand, otherwise this may produce a cycle in the DAG. +static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, + SDValue &Load) { + if (isLoadAllowedToSink(N, Chain) && + N.getOperand(1) == Address) { Load = N; return true; } @@ -210,57 +285,140 @@ static bool isRMWLoad(SDValue N, SDValue Chain, SDValue Address, } /// PreprocessForRMW - Preprocess the DAG to make instruction selection better. -/// Shamelessly stolen from X86. +/// This is only run if not in -O0 mode. +/// This allows the instruction selector to pick more read-modify-write +/// instructions. This is a common case: +/// +/// [Load chain] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// / \- +/// / | +/// [TokenFactor] [Op] +/// ^ ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// The fact the store's chain operand != load's chain will prevent the +/// (store (op (load))) instruction from being selected. We can transform it to: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load] +/// ^ ^ +/// | | +/// | \- +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// We also recognize the case where second operand of Op is load as well and +/// move it below token factor as well creating DAG as follows: +/// +/// [Load chain] +/// ^ +/// | +/// [TokenFactor] +/// ^ +/// | +/// [Load1] +/// ^ ^ +/// / | +/// / | +/// [Load2] | +/// ^ ^ | +/// | | | +/// | \-| +/// | | +/// | [Op] +/// | ^ +/// | | +/// \ / +/// \ / +/// [Store] +/// +/// This allows selection of mem-mem instructions. Yay! + void MSP430DAGToDAGISel::PreprocessForRMW() { for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), E = CurDAG->allnodes_end(); I != E; ++I) { if (!ISD::isNON_TRUNCStore(I)) continue; - SDValue Chain = I->getOperand(0); + if (Chain.getNode()->getOpcode() != ISD::TokenFactor) continue; - SDValue N1 = I->getOperand(1); // Value to store - SDValue N2 = I->getOperand(2); // Address of store - - if (!N1.hasOneUse()) + SDValue N1 = I->getOperand(1); + SDValue N2 = I->getOperand(2); + if ((N1.getValueType().isFloatingPoint() && + !N1.getValueType().isVector()) || + !N1.hasOneUse()) continue; - bool RModW = false; - SDValue Load; + unsigned RModW = 0; + SDValue Load1, Load2; unsigned Opcode = N1.getNode()->getOpcode(); switch (Opcode) { - case ISD::ADD: - case ISD::AND: - case ISD::OR: - case ISD::XOR: - case ISD::ADDC: - case ISD::ADDE: { - SDValue N10 = N1.getOperand(0); - SDValue N11 = N1.getOperand(1); - RModW = isRMWLoad(N10, Chain, N2, Load); - - if (!RModW && isRMWLoad(N11, Chain, N2, Load)) { - // Swap the operands, making the RMW load the first operand seems - // to help selection and prevent token chain loops. - N1 = CurDAG->UpdateNodeOperands(N1, N11, N10); - RModW = true; - } - break; + case ISD::ADD: + case ISD::AND: + case ISD::OR: + case ISD::XOR: + case ISD::ADDC: + case ISD::ADDE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; + } else if (isRMWLoad(N11, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N10, Chain)) { + Load2 = N10; + RModW = 2; + } else + RModW = 1; } - case ISD::SUB: - case ISD::SUBC: - case ISD::SUBE: { - SDValue N10 = N1.getOperand(0); - RModW = isRMWLoad(N10, Chain, N2, Load); - break; + break; + } + case ISD::SUB: + case ISD::SUBC: + case ISD::SUBE: { + SDValue N10 = N1.getOperand(0); + SDValue N11 = N1.getOperand(1); + if (isRMWLoad(N10, Chain, N2, Load1)) { + if (isLoadAllowedToSink(N11, Chain)) { + Load2 = N11; + RModW = 2; + } else + RModW = 1; } + break; + } } - if (RModW) { - MoveBelowTokenFactor(CurDAG, Load, SDValue(I, 0), Chain); - ++NumLoadMoved; + NumLoadMoved += RModW; + if (RModW == 1) + MoveBelowTokenFactor(CurDAG, Load1, SDValue(I, 0), Chain); + else if (RModW == 2) { + MoveBelowTokenFactor2(CurDAG, Load1, Load2, SDValue(I, 0), Chain); + SDNode* Store = I; + RMWStores[Store] = Load2.getNode(); } } } @@ -268,8 +426,15 @@ void MSP430DAGToDAGISel::PreprocessForRMW() { /// InstructionSelect - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. void MSP430DAGToDAGISel::InstructionSelect() { + std::string BlockName; + if (ViewRMWDAGs) + BlockName = MF->getFunction()->getNameStr() + ":" + + BB->getBasicBlock()->getNameStr(); + PreprocessForRMW(); + if (ViewRMWDAGs) CurDAG->viewGraph("RMW preprocessed:" + BlockName); + DEBUG(errs() << "Selection DAG after RMW preprocessing:\n"); DEBUG(CurDAG->dump()); @@ -282,6 +447,7 @@ void MSP430DAGToDAGISel::InstructionSelect() { DEBUG(errs() << "===== Instruction selection ends:\n"); CurDAG->RemoveDeadNodes(); + RMWStores.clear(); } SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp index b56f069b54de..34e6d2c948bd 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -567,44 +567,45 @@ SDValue MSP430TargetLowering::LowerExternalSymbol(SDValue Op, return DAG.getNode(MSP430ISD::Wrapper, dl, getPointerTy(), Result);; } -static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, unsigned &TargetCC, +static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC, ISD::CondCode CC, DebugLoc dl, SelectionDAG &DAG) { // FIXME: Handle bittests someday assert(!LHS.getValueType().isFloatingPoint() && "We don't handle FP yet"); // FIXME: Handle jump negative someday - TargetCC = MSP430::COND_INVALID; + MSP430CC::CondCodes TCC = MSP430CC::COND_INVALID; switch (CC) { default: llvm_unreachable("Invalid integer condition!"); case ISD::SETEQ: - TargetCC = MSP430::COND_E; // aka COND_Z + TCC = MSP430CC::COND_E; // aka COND_Z break; case ISD::SETNE: - TargetCC = MSP430::COND_NE; // aka COND_NZ + TCC = MSP430CC::COND_NE; // aka COND_NZ break; case ISD::SETULE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETUGE: - TargetCC = MSP430::COND_HS; // aka COND_C + TCC = MSP430CC::COND_HS; // aka COND_C break; case ISD::SETUGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETULT: - TargetCC = MSP430::COND_LO; // aka COND_NC + TCC = MSP430CC::COND_LO; // aka COND_NC break; case ISD::SETLE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETGE: - TargetCC = MSP430::COND_GE; + TCC = MSP430CC::COND_GE; break; case ISD::SETGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETLT: - TargetCC = MSP430::COND_L; + TCC = MSP430CC::COND_L; break; } + TargetCC = DAG.getConstant(TCC, MVT::i8); return DAG.getNode(MSP430ISD::CMP, dl, MVT::Flag, LHS, RHS); } @@ -617,13 +618,11 @@ SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { SDValue Dest = Op.getOperand(4); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; 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); + Chain, Dest, TargetCC, Flag); } SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { @@ -634,14 +633,14 @@ SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); DebugLoc dl = Op.getDebugLoc(); - unsigned TargetCC = MSP430::COND_INVALID; + SDValue TargetCC; SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); SmallVector<SDValue, 4> Ops; Ops.push_back(TrueV); Ops.push_back(FalseV); - Ops.push_back(DAG.getConstant(TargetCC, MVT::i8)); + Ops.push_back(TargetCC); Ops.push_back(Flag); return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); diff --git a/lib/Target/MSP430/MSP430InstrInfo.cpp b/lib/Target/MSP430/MSP430InstrInfo.cpp index 37fbb6d9999b..a6d9638cf598 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.cpp +++ b/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -151,6 +151,163 @@ MSP430InstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, return true; } +unsigned MSP430InstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->getOpcode() != MSP430::JMP && + I->getOpcode() != MSP430::JCC) + break; + // Remove the branch. + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +bool MSP430InstrInfo:: +ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid Xbranch condition!"); + + MSP430CC::CondCodes CC = static_cast<MSP430CC::CondCodes>(Cond[0].getImm()); + + switch (CC) { + default: + assert(0 && "Invalid branch condition!"); + break; + case MSP430CC::COND_E: + CC = MSP430CC::COND_NE; + break; + case MSP430CC::COND_NE: + CC = MSP430CC::COND_E; + break; + case MSP430CC::COND_L: + CC = MSP430CC::COND_GE; + break; + case MSP430CC::COND_GE: + CC = MSP430CC::COND_L; + break; + case MSP430CC::COND_HS: + CC = MSP430CC::COND_LO; + break; + case MSP430CC::COND_LO: + CC = MSP430CC::COND_HS; + break; + } + + Cond[0].setImm(CC); + return false; +} + +bool MSP430InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB)const{ + if (MBB.empty()) return false; + + switch (MBB.back().getOpcode()) { + case MSP430::RET: // Return. + case MSP430::JMP: // Uncond branch. + return true; + default: return false; + } +} + +bool MSP430InstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.isTerminator()) return false; + + // Conditional branch is a special case. + if (TID.isBranch() && !TID.isBarrier()) + return true; + if (!TID.isPredicable()) + return true; + return !isPredicated(MI); +} + +bool MSP430InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) + return true; + + // Handle unconditional branches. + if (I->getOpcode() == MSP430::JMP) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (next(I) != MBB.end()) + next(I)->eraseFromParent(); + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + assert(I->getOpcode() == MSP430::JCC && "Invalid conditional branch"); + MSP430CC::CondCodes BranchCode = + static_cast<MSP430CC::CondCodes>(I->getOperand(1).getImm()); + if (BranchCode == MSP430CC::COND_INVALID) + return true; // Can't handle weird stuff. + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) + return true; + + MSP430CC::CondCodes OldBranchCode = (MSP430CC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) + continue; + + return true; + } + + return false; +} + unsigned MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, @@ -172,7 +329,13 @@ MSP430InstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, // Conditional branch. unsigned Count = 0; - llvm_unreachable("Implement conditional branches!"); + BuildMI(&MBB, dl, get(MSP430::JCC)).addMBB(TBB).addImm(Cond[0].getImm()); + ++Count; + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + BuildMI(&MBB, dl, get(MSP430::JMP)).addMBB(FBB); + ++Count; + } return Count; } diff --git a/lib/Target/MSP430/MSP430InstrInfo.h b/lib/Target/MSP430/MSP430InstrInfo.h index e07aacad9dc2..35e35db01c49 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.h +++ b/lib/Target/MSP430/MSP430InstrInfo.h @@ -21,20 +21,6 @@ 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; @@ -73,9 +59,19 @@ public: MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI) const; - virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - const SmallVectorImpl<MachineOperand> &Cond) const; + // Branch folding goodness + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const; + bool BlockHasNoFallThrough(const MachineBasicBlock &MBB) const; + bool isUnpredicatedTerminator(const MachineInstr *MI) const; + bool AnalyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const; + + unsigned RemoveBranch(MachineBasicBlock &MBB) const; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + const SmallVectorImpl<MachineOperand> &Cond) const; }; diff --git a/lib/Target/MSP430/MSP430InstrInfo.td b/lib/Target/MSP430/MSP430InstrInfo.td index f7e0d2bad638..e202175561cb 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.td +++ b/lib/Target/MSP430/MSP430InstrInfo.td @@ -71,7 +71,9 @@ def memdst : Operand<i16> { } // Branch targets have OtherVT type. -def brtarget : Operand<OtherVT>; +def brtarget : Operand<OtherVT> { + let PrintMethod = "printPCRelImmOperand"; +} // Operand for printing out a condition code. def cc : Operand<i8> { diff --git a/lib/Target/MSP430/MSP430TargetMachine.cpp b/lib/Target/MSP430/MSP430TargetMachine.cpp index 5e21f8ea29ef..da54507ab66c 100644 --- a/lib/Target/MSP430/MSP430TargetMachine.cpp +++ b/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -32,7 +32,7 @@ MSP430TargetMachine::MSP430TargetMachine(const Target &T, LLVMTargetMachine(T, TT), Subtarget(TT, FS), // FIXME: Check TargetData string. - DataLayout("e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"), + DataLayout("e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32"), InstrInfo(*this), TLInfo(*this), FrameInfo(TargetFrameInfo::StackGrowsDown, 2, -2) { } |