static const bool ViewRMWDAGs = false;
#endif
+static cl::opt<bool>
+EnablePostIncOps("enable-msp430-post-inc-ops", cl::Hidden);
+
STATISTIC(NumLoadMoved, "Number of loads moved below TokenFactor");
void PreprocessForRMW();
SDNode *Select(SDValue Op);
SDNode *SelectIndexedLoad(SDValue Op);
+ SDNode *SelectIndexedBinOp(SDValue Op, SDValue N1, SDValue N2,
+ unsigned Opc8, unsigned Opc16);
+
bool SelectAddr(SDValue Op, SDValue Addr, SDValue &Base, SDValue &Disp);
#ifndef NDEBUG
}
-SDNode *MSP430DAGToDAGISel::SelectIndexedLoad(SDValue Op) {
- LoadSDNode *LD = cast<LoadSDNode>(Op);
+static bool isValidIndexedLoad(const LoadSDNode *LD) {
ISD::MemIndexedMode AM = LD->getAddressingMode();
if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD)
- return NULL;
+ return false;
EVT VT = LD->getMemoryVT();
- unsigned Opcode = 0;
switch (VT.getSimpleVT().SimpleTy) {
case MVT::i8:
// Sanity check
if (cast<ConstantSDNode>(LD->getOffset())->getZExtValue() != 1)
- return NULL;
+ return false;
- Opcode = MSP430::MOV8rm_POST;
break;
case MVT::i16:
// Sanity check
if (cast<ConstantSDNode>(LD->getOffset())->getZExtValue() != 2)
- return NULL;
+ return false;
+
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+SDNode *MSP430DAGToDAGISel::SelectIndexedLoad(SDValue Op) {
+ LoadSDNode *LD = cast<LoadSDNode>(Op);
+ if (!isValidIndexedLoad(LD))
+ return NULL;
+
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+
+ unsigned Opcode = 0;
+ switch (VT.SimpleTy) {
+ case MVT::i8:
+ Opcode = MSP430::MOV8rm_POST;
+ break;
+ case MVT::i16:
Opcode = MSP430::MOV16rm_POST;
break;
default:
return NULL;
}
- return CurDAG->getMachineNode(Opcode, Op.getDebugLoc(),
- VT.getSimpleVT().SimpleTy, MVT::i16, MVT::Other,
- LD->getBasePtr(), LD->getChain());
+ return CurDAG->getMachineNode(Opcode, Op.getDebugLoc(),
+ VT, MVT::i16, MVT::Other,
+ LD->getBasePtr(), LD->getChain());
}
+SDNode *MSP430DAGToDAGISel::SelectIndexedBinOp(SDValue Op,
+ SDValue N1, SDValue N2,
+ unsigned Opc8, unsigned Opc16) {
+ if (N1.getOpcode() == ISD::LOAD &&
+ N1.hasOneUse() &&
+ IsLegalAndProfitableToFold(N1.getNode(), Op.getNode(), Op.getNode())) {
+ LoadSDNode *LD = cast<LoadSDNode>(N1);
+ if (!isValidIndexedLoad(LD))
+ return NULL;
+
+ MVT VT = LD->getMemoryVT().getSimpleVT();
+ unsigned Opc = (VT == MVT::i16 ? Opc16 : Opc8);
+ MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1);
+ MemRefs0[0] = cast<MemSDNode>(N1)->getMemOperand();
+ SDValue Ops0[] = { N2, LD->getBasePtr(), LD->getChain() };
+ SDNode *ResNode =
+ CurDAG->SelectNodeTo(Op.getNode(), Opc,
+ VT, MVT::i16, MVT::Other,
+ Ops0, 3);
+ cast<MachineSDNode>(ResNode)->setMemRefs(MemRefs0, MemRefs0 + 1);
+ ReplaceUses(SDValue(N1.getNode(), 2), SDValue(ResNode, 3));
+ return ResNode;
+ }
+
+ return NULL;
+}
+
+
/// InstructionSelect - This callback is invoked by
/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
void MSP430DAGToDAGISel::InstructionSelect() {
return ResNode;
// Other cases are autogenerated.
break;
+ case ISD::ADD:
+ if (EnablePostIncOps) {
+ if (SDNode *ResNode =
+ SelectIndexedBinOp(Op,
+ Op.getOperand(0), Op.getOperand(1),
+ MSP430::ADD8rm_POST, MSP430::ADD16rm_POST))
+ return ResNode;
+ else if (SDNode *ResNode =
+ SelectIndexedBinOp(Op, Op.getOperand(1), Op.getOperand(0),
+ MSP430::ADD8rm_POST, MSP430::ADD16rm_POST))
+ return ResNode;
+ }
+
+ // Other cases are autogenerated.
+ break;
}
// Select the default instruction
[(set GR16:$dst, (add GR16:$src1, (load addr:$src2))),
(implicit SRW)]>;
+let mayLoad = 1, hasExtraDefRegAllocReq = 1,
+Constraints = "$base = $base_wb, $src1 = $dst" in {
+def ADD8rm_POST : Pseudo<(outs GR8:$dst, GR16:$base_wb), (ins GR8:$src1, GR16:$base),
+ "add.b\t{@$base+, $dst}", []>;
+def ADD16rm_POST : Pseudo<(outs GR16:$dst, GR16:$base_wb), (ins GR16:$src1, GR16:$base),
+ "add.w\t{@$base+, $dst}", []>;
+}
+
+
def ADD8ri : Pseudo<(outs GR8:$dst), (ins GR8:$src1, i8imm:$src2),
"add.b\t{$src2, $dst}",
[(set GR8:$dst, (add GR8:$src1, imm:$src2)),