//===----------------------------------------------------------------------===//
#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/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
-#include "llvm/Target/TargetLowering.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-#include <queue>
-#include <set>
+#include "llvm/Target/TargetLowering.h"
using namespace llvm;
/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
///
namespace {
class XCoreDAGToDAGISel : public SelectionDAGISel {
- XCoreTargetLowering &Lowering;
- const XCoreSubtarget &Subtarget;
public:
- XCoreDAGToDAGISel(XCoreTargetMachine &TM)
- : SelectionDAGISel(TM),
- Lowering(*TM.getTargetLowering()),
- Subtarget(*TM.getSubtargetImpl()) { }
+ XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
+ : SelectionDAGISel(TM, OptLevel) {}
+
+ SDNode *Select(SDNode *N) override;
+ SDNode *SelectBRIND(SDNode *N);
- SDNode *Select(SDValue Op);
-
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
- inline SDValue getI32Imm(unsigned Imm) {
- return CurDAG->getTargetConstant(Imm, MVT::i32);
+ inline SDValue getI32Imm(unsigned Imm, SDLoc dl) {
+ return CurDAG->getTargetConstant(Imm, dl, 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(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);
-
- virtual void InstructionSelect();
+ bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
- virtual const char *getPassName() const {
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
+ std::vector<SDValue> &OutOps) override;
+
+ const char *getPassName() const override {
return "XCore DAG->DAG Pattern Instruction Selection";
}
/// createXCoreISelDag - This pass converts a legalized DAG into a
/// XCore-specific DAG, ready for instruction scheduling.
///
-FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM) {
- return new XCoreDAGToDAGISel(TM);
+FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
+ CodeGenOpt::Level OptLevel) {
+ return new XCoreDAGToDAGISel(TM, OptLevel);
}
-bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
- FrameIndexSDNode *FIN = 0;
+bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
+ SDValue &Offset) {
+ FrameIndexSDNode *FIN = nullptr;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
- Offset = CurDAG->getTargetConstant(0, MVT::i32);
+ Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
return true;
}
if (Addr.getOpcode() == ISD::ADD) {
- ConstantSDNode *CN = 0;
+ ConstantSDNode *CN = nullptr;
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
&& (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
&& (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);
+ Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),
+ MVT::i32);
return true;
}
}
return false;
}
-bool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
- if (Addr.getOpcode() == XCoreISD::DPRelativeWrapper) {
- Base = Addr.getOperand(0);
- Offset = CurDAG->getTargetConstant(0, MVT::i32);
- return true;
- }
- if (Addr.getOpcode() == ISD::ADD) {
- ConstantSDNode *CN = 0;
- if ((Addr.getOperand(0).getOpcode() == XCoreISD::DPRelativeWrapper)
- && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
- && (CN->getSExtValue() % 4 == 0)) {
- // Constant word offset from a object in the data region
- Base = Addr.getOperand(0).getOperand(0);
- Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
- return true;
+bool XCoreDAGToDAGISel::
+SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
+ std::vector<SDValue> &OutOps) {
+ SDValue Reg;
+ switch (ConstraintID) {
+ default: return true;
+ case InlineAsm::Constraint_m: // Memory.
+ switch (Op.getOpcode()) {
+ default: return true;
+ case XCoreISD::CPRelativeWrapper:
+ Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
+ break;
+ case XCoreISD::DPRelativeWrapper:
+ Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
+ break;
}
}
+ OutOps.push_back(Reg);
+ OutOps.push_back(Op.getOperand(0));
return false;
}
-bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Op, SDValue Addr,
- SDValue &Base, SDValue &Offset) {
- if (Addr.getOpcode() == XCoreISD::CPRelativeWrapper) {
- Base = Addr.getOperand(0);
- Offset = CurDAG->getTargetConstant(0, MVT::i32);
- return true;
- }
- if (Addr.getOpcode() == ISD::ADD) {
- ConstantSDNode *CN = 0;
- if ((Addr.getOperand(0).getOpcode() == XCoreISD::CPRelativeWrapper)
- && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
- && (CN->getSExtValue() % 4 == 0)) {
- // Constant word offset from a object in the data region
- Base = Addr.getOperand(0).getOperand(0);
- Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
- return true;
+SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
+ SDLoc dl(N);
+ 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((uint32_t)Val), dl);
+ 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),
+ getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));
+ 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(*MF),
+ MachineMemOperand::MOLoad, 4, 4);
+ cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
+ return node;
+ }
+ break;
}
- return false;
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ case XCoreISD::CRC8: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
+ return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
+ Ops);
+ }
+ case ISD::BRIND:
+ if (SDNode *ResNode = SelectBRIND(N))
+ return ResNode;
+ break;
+ // Other cases are autogenerated.
+ }
+ return SelectCode(N);
}
-/// 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();
+/// 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));
+ }
+ }
+ if (!found)
+ return SDValue();
+ return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
}
-SDNode *XCoreDAGToDAGISel::Select(SDValue Op) {
- SDNode *N = Op.getNode();
- DebugLoc dl = N->getDebugLoc();
- EVT 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->getMachineNode(XCore::MKMSK_rus, dl,
- MVT::i32, MskSize);
- }
- else if (! Predicate_immU16(N)) {
- unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
- SDValue CPIdx =
- CurDAG->getTargetConstantPool(ConstantInt::get(
- Type::getInt32Ty(*CurDAG->getContext()), Val),
- TLI.getPointerTy());
- return CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
- MVT::Other, CPIdx,
- CurDAG->getEntryNode());
- }
- break;
- }
- case ISD::SMUL_LOHI: {
- // FIXME fold addition into the macc instruction
- SDValue Zero(CurDAG->getMachineNode(XCore::LDC_ru6, dl, MVT::i32,
- CurDAG->getTargetConstant(0, MVT::i32)), 0);
- SDValue Ops[] = { Zero, Zero, Op.getOperand(0), Op.getOperand(1) };
- SDNode *ResNode = CurDAG->getMachineNode(XCore::MACCS_l4r, dl,
- MVT::i32, MVT::i32, Ops, 4);
- ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1));
- ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0));
- return NULL;
- }
- case ISD::UMUL_LOHI: {
- // FIXME fold addition into the macc / lmul instruction
- SDValue Zero(CurDAG->getMachineNode(XCore::LDC_ru6, dl, MVT::i32,
- CurDAG->getTargetConstant(0, MVT::i32)), 0);
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Zero, Zero };
- SDNode *ResNode = CurDAG->getMachineNode(XCore::LMUL_l6r, dl, 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: {
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Op.getOperand(2) };
- return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
- Ops, 3);
- }
- case XCoreISD::LSUB: {
- SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
- Op.getOperand(2) };
- return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
- Ops, 3);
- }
- // Other cases are autogenerated.
- }
+SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
+ SDLoc dl(N);
+ // (brind (int_xcore_checkevent (addr)))
+ SDValue Chain = N->getOperand(0);
+ SDValue Addr = N->getOperand(1);
+ if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
+ return nullptr;
+ unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
+ if (IntNo != Intrinsic::xcore_checkevent)
+ return nullptr;
+ 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 nullptr;
+ 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, dl);
+ 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 SelectCode(Op);
+ return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
}