diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
commit | cd749a9c07f1de2fb8affde90537efa4bc3e7c54 (patch) | |
tree | b21f6de4e08b89bb7931806bab798fc2a5e3a686 /lib/Target/MSP430/MSP430ISelDAGToDAG.cpp | |
parent | 72621d11de5b873f1695f391eb95f0b336c3d2d4 (diff) | |
download | FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.zip FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.tar.gz |
Update llvm to r84119.
Diffstat (limited to 'lib/Target/MSP430/MSP430ISelDAGToDAG.cpp')
-rw-r--r-- | lib/Target/MSP430/MSP430ISelDAGToDAG.cpp | 189 |
1 files changed, 164 insertions, 25 deletions
diff --git a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp index bf49ec0..4195a88 100644 --- a/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp +++ b/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp @@ -28,8 +28,14 @@ #include "llvm/Target/TargetLowering.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/Statistic.h" + using namespace llvm; +STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor"); + /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine /// instructions for SelectionDAG operations. /// @@ -50,10 +56,15 @@ namespace { return "MSP430 DAG->DAG Pattern Instruction Selection"; } + virtual bool + SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps); + // Include the pieces autogenerated from the target description. #include "MSP430GenDAGISel.inc" private: + void PreprocessForRMW(); SDNode *Select(SDValue Op); bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp); @@ -120,21 +131,155 @@ bool MSP430DAGToDAGISel::SelectAddr(SDValue Op, SDValue Addr, } +bool MSP430DAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, + std::vector<SDValue> &OutOps) { + SDValue Op0, Op1; + switch (ConstraintCode) { + default: return true; + case 'm': // memory + if (!SelectAddr(Op, Op, Op0, Op1)) + return true; + break; + } + + OutOps.push_back(Op0); + OutOps.push_back(Op1); + return false; +} + +/// 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()); + + SDValue NewLoad = CurDAG->UpdateNodeOperands(Load, NewTF, + Load.getOperand(1), + Load.getOperand(2)); + CurDAG->UpdateNodeOperands(Store, NewLoad.getValue(1), Store.getOperand(1), + 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) { + if (N.getOpcode() == ISD::BIT_CONVERT) + N = N.getOperand(0); + + LoadSDNode *LD = dyn_cast<LoadSDNode>(N); + if (!LD || LD->isVolatile()) + return false; + if (LD->getAddressingMode() != ISD::UNINDEXED) + return false; + + ISD::LoadExtType ExtType = LD->getExtensionType(); + 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())) { + Load = N; + return true; + } + return false; +} + +/// PreprocessForRMW - Preprocess the DAG to make instruction selection better. +/// Shamelessly stolen from X86. +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()) + continue; + + bool RModW = false; + SDValue Load; + 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::SUB: + case ISD::SUBC: + case ISD::SUBE: { + SDValue N10 = N1.getOperand(0); + RModW = isRMWLoad(N10, Chain, N2, Load); + break; + } + } + + if (RModW) { + MoveBelowTokenFactor(CurDAG, Load, SDValue(I, 0), Chain); + ++NumLoadMoved; + } + } +} /// InstructionSelect - This callback is invoked by /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. void MSP430DAGToDAGISel::InstructionSelect() { + PreprocessForRMW(); + + DEBUG(errs() << "Selection DAG after RMW preprocessing:\n"); + DEBUG(CurDAG->dump()); + DEBUG(BB->dump()); // Codegen the basic block. -#ifndef NDEBUG - DOUT << "===== Instruction selection begins:\n"; - Indent = 0; -#endif + DEBUG(errs() << "===== Instruction selection begins:\n"); + DEBUG(Indent = 0); SelectRoot(*CurDAG); -#ifndef NDEBUG - DOUT << "===== Instruction selection ends:\n"; -#endif + DEBUG(errs() << "===== Instruction selection ends:\n"); CurDAG->RemoveDeadNodes(); } @@ -144,21 +289,17 @@ SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { DebugLoc dl = Op.getDebugLoc(); // Dump information about the Node being selected - #ifndef NDEBUG - DOUT << std::string(Indent, ' ') << "Selecting: "; + DEBUG(errs().indent(Indent) << "Selecting: "); DEBUG(Node->dump(CurDAG)); - DOUT << "\n"; - Indent += 2; - #endif + DEBUG(errs() << "\n"); + DEBUG(Indent += 2); // 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 + DEBUG(errs().indent(Indent-2) << "== "; + Node->dump(CurDAG); + errs() << "\n"); + DEBUG(Indent -= 2); return NULL; } @@ -172,23 +313,21 @@ SDNode *MSP430DAGToDAGISel::Select(SDValue Op) { 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)); + return CurDAG->getMachineNode(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, ' ') << "=> "; + DEBUG(errs() << 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 + DEBUG(errs() << "\n"); + DEBUG(Indent -= 2); return ResNode; } |