summaryrefslogtreecommitdiffstats
path: root/lib/Target/MSP430/MSP430ISelDAGToDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/MSP430/MSP430ISelDAGToDAG.cpp')
-rw-r--r--lib/Target/MSP430/MSP430ISelDAGToDAG.cpp189
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;
}
OpenPOWER on IntegriCloud