//===----------------------------------------------------------------------===//
#include "XCore.h"
-#include "XCoreISelLowering.h"
#include "XCoreTargetMachine.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
#include "llvm/CallingConv.h"
#include "llvm/Constants.h"
+#include "llvm/LLVMContext.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
-#include <queue>
-#include <set>
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
///
namespace {
class XCoreDAGToDAGISel : public SelectionDAGISel {
- XCoreTargetLowering &Lowering;
+ const XCoreTargetLowering &Lowering;
const XCoreSubtarget &Subtarget;
public:
XCoreDAGToDAGISel(XCoreTargetMachine &TM)
- : SelectionDAGISel(*TM.getTargetLowering()),
+ : SelectionDAGISel(TM),
Lowering(*TM.getTargetLowering()),
Subtarget(*TM.getSubtargetImpl()) { }
- SDNode *Select(SDValue Op);
-
+ SDNode *Select(SDNode *N);
+ SDNode *SelectBRIND(SDNode *N);
+
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
inline SDValue getI32Imm(unsigned Imm) {
return CurDAG->getTargetConstant(Imm, MVT::i32);
}
+ inline bool immMskBitp(SDNode *inN) const {
+ ConstantSDNode *N = cast<ConstantSDNode>(inN);
+ uint32_t value = (uint32_t)N->getZExtValue();
+ if (!isMask_32(value)) {
+ return false;
+ }
+ int msksize = 32 - CountLeadingZeros_32(value);
+ return (msksize >= 1 && msksize <= 8) ||
+ msksize == 16 || msksize == 24 || msksize == 32;
+ }
+
// Complex Pattern Selectors.
- bool SelectADDRspii(SDValue Op, SDValue Addr, SDValue &Base,
- SDValue &Offset);
- bool SelectADDRdpii(SDValue Op, SDValue Addr, SDValue &Base,
- SDValue &Offset);
- bool SelectADDRcpii(SDValue Op, SDValue Addr, SDValue &Base,
- SDValue &Offset);
+ bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
+ bool SelectADDRdpii(SDValue Addr, SDValue &Base, SDValue &Offset);
+ bool SelectADDRcpii(SDValue Addr, SDValue &Base, SDValue &Offset);
- virtual void InstructionSelect();
-
virtual const char *getPassName() const {
return "XCore DAG->DAG Pattern Instruction Selection";
}
return new XCoreDAGToDAGISel(TM);
}
-bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
+bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
FrameIndexSDNode *FIN = 0;
- if (FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return true;
ConstantSDNode *CN = 0;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
&& (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
- && (CN->getSExtValue() % 4 == 0)) {
- // Constant word offset from frame pointer
+ && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
+ // Constant positive word offset from frame index
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
return true;
return false;
}
-bool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
+bool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
if (Addr.getOpcode() == XCoreISD::DPRelativeWrapper) {
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return false;
}
-bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
+bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
if (Addr.getOpcode() == XCoreISD::CPRelativeWrapper) {
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(0, MVT::i32);
return false;
}
-/// InstructionSelect - This callback is invoked by
-/// SelectionDAGISel when it has created a SelectionDAG for us to codegen.
-void XCoreDAGToDAGISel::
-InstructionSelect() {
- DEBUG(BB->dump());
-
- // Select target instructions for the DAG.
- SelectRoot(*CurDAG);
-
- CurDAG->RemoveDeadNodes();
+SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
+ DebugLoc dl = N->getDebugLoc();
+ switch (N->getOpcode()) {
+ default: break;
+ case ISD::Constant: {
+ uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
+ if (immMskBitp(N)) {
+ // Transformation function: get the size of a mask
+ // Look for the first non-zero bit
+ SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
+ return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
+ MVT::i32, MskSize);
+ }
+ else if (!isUInt<16>(Val)) {
+ SDValue CPIdx =
+ CurDAG->getTargetConstantPool(ConstantInt::get(
+ Type::getInt32Ty(*CurDAG->getContext()), Val),
+ TLI.getPointerTy());
+ SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
+ MVT::Other, CPIdx,
+ CurDAG->getEntryNode());
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = MF->getMachineMemOperand(
+ MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
+ cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
+ return node;
+ }
+ break;
+ }
+ case XCoreISD::LADD: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2) };
+ return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
+ Ops, 3);
+ }
+ case XCoreISD::LSUB: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2) };
+ return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
+ Ops, 3);
+ }
+ case XCoreISD::MACCU: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case XCoreISD::MACCS: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case XCoreISD::LMUL: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case ISD::INTRINSIC_WO_CHAIN: {
+ unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
+ switch (IntNo) {
+ case Intrinsic::xcore_crc8:
+ SDValue Ops[] = { N->getOperand(1), N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
+ Ops, 3);
+ }
+ break;
+ }
+ case ISD::BRIND:
+ if (SDNode *ResNode = SelectBRIND(N))
+ return ResNode;
+ break;
+ // Other cases are autogenerated.
+ }
+ return SelectCode(N);
}
-SDNode *XCoreDAGToDAGISel::Select(SDValue Op) {
- SDNode *N = Op.getNode();
- MVT NVT = N->getValueType(0);
- if (NVT == MVT::i32) {
- switch (N->getOpcode()) {
- default: break;
- case ISD::Constant: {
- if (Predicate_immMskBitp(N)) {
- SDValue MskSize = Transform_msksize_xform(N);
- return CurDAG->getTargetNode(XCore::MKMSK_rus, MVT::i32, MskSize);
- }
- else if (! Predicate_immU16(N)) {
- unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
- SDValue CPIdx =
- CurDAG->getTargetConstantPool(ConstantInt::get(Type::Int32Ty, Val),
- TLI.getPointerTy());
- return CurDAG->getTargetNode(XCore::LDWCP_lru6, MVT::i32, MVT::Other,
- CPIdx, CurDAG->getEntryNode());
- }
- break;
- }
- case ISD::SMUL_LOHI: {
- // FIXME fold addition into the macc instruction
- if (!Subtarget.isXS1A()) {
- SDValue Zero(CurDAG->getTargetNode(XCore::LDC_ru6, MVT::i32,
- CurDAG->getTargetConstant(0, MVT::i32)), 0);
- SDValue Ops[] = { Zero, Zero, Op.getOperand(0), Op.getOperand(1) };
- SDNode *ResNode = CurDAG->getTargetNode(XCore::MACCS_l4r, MVT::i32,
- MVT::i32, Ops, 4);
- ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1));
- ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0));
- return NULL;
- }
- break;
- }
- case ISD::UMUL_LOHI: {
- // FIXME fold addition into the macc / lmul instruction
- SDValue Zero(CurDAG->getTargetNode(XCore::LDC_ru6, MVT::i32,
- CurDAG->getTargetConstant(0, MVT::i32)), 0);
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Zero, Zero };
- SDNode *ResNode = CurDAG->getTargetNode(XCore::LMUL_l6r, MVT::i32,
- MVT::i32, Ops, 4);
- ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1));
- ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0));
- return NULL;
- }
- case XCoreISD::LADD: {
- if (!Subtarget.isXS1A()) {
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Op.getOperand(2) };
- return CurDAG->getTargetNode(XCore::LADD_l5r, MVT::i32, MVT::i32,
- Ops, 3);
- }
- break;
- }
- case XCoreISD::LSUB: {
- if (!Subtarget.isXS1A()) {
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Op.getOperand(2) };
- return CurDAG->getTargetNode(XCore::LSUB_l5r, MVT::i32, MVT::i32,
- Ops, 3);
- }
- break;
- }
- // Other cases are autogenerated.
+/// Given a chain return a new chain where any appearance of Old is replaced
+/// by New. There must be at most one instruction between Old and Chain and
+/// this instruction must be a TokenFactor. Returns an empty SDValue if
+/// these conditions don't hold.
+static SDValue
+replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
+{
+ if (Chain == Old)
+ return New;
+ if (Chain->getOpcode() != ISD::TokenFactor)
+ return SDValue();
+ SmallVector<SDValue, 8> Ops;
+ bool found = false;
+ for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
+ if (Chain->getOperand(i) == Old) {
+ Ops.push_back(New);
+ found = true;
+ } else {
+ Ops.push_back(Chain->getOperand(i));
}
}
- return SelectCode(Op);
+ if (!found)
+ return SDValue();
+ return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
+ &Ops[0], Ops.size());
+}
+
+SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
+ DebugLoc dl = N->getDebugLoc();
+ // (brind (int_xcore_checkevent (addr)))
+ SDValue Chain = N->getOperand(0);
+ SDValue Addr = N->getOperand(1);
+ if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
+ return 0;
+ unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
+ if (IntNo != Intrinsic::xcore_checkevent)
+ return 0;
+ SDValue nextAddr = Addr->getOperand(2);
+ SDValue CheckEventChainOut(Addr.getNode(), 1);
+ if (!CheckEventChainOut.use_empty()) {
+ // If the chain out of the checkevent intrinsic is an operand of the
+ // indirect branch or used in a TokenFactor which is the operand of the
+ // indirect branch then build a new chain which uses the chain coming into
+ // the checkevent intrinsic instead.
+ SDValue CheckEventChainIn = Addr->getOperand(0);
+ SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
+ CheckEventChainIn);
+ if (!NewChain.getNode())
+ return 0;
+ Chain = NewChain;
+ }
+ // Enable events on the thread using setsr 1 and then disable them immediately
+ // after with clrsr 1. If any resources owned by the thread are ready an event
+ // will be taken. If no resource is ready we branch to the address which was
+ // the operand to the checkevent intrinsic.
+ SDValue constOne = getI32Imm(1);
+ SDValue Glue =
+ SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
+ constOne, Chain), 0);
+ Glue =
+ SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
+ constOne, Glue), 0);
+ if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
+ nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
+ return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
+ nextAddr->getOperand(0), Glue);
+ }
+ return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
}