Home | History | Annotate | Download | only in XCore
      1 //===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines an instruction selector for the XCore target.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "XCore.h"
     15 #include "XCoreTargetMachine.h"
     16 #include "llvm/CodeGen/MachineFrameInfo.h"
     17 #include "llvm/CodeGen/MachineFunction.h"
     18 #include "llvm/CodeGen/MachineInstrBuilder.h"
     19 #include "llvm/CodeGen/MachineRegisterInfo.h"
     20 #include "llvm/CodeGen/SelectionDAG.h"
     21 #include "llvm/CodeGen/SelectionDAGISel.h"
     22 #include "llvm/IR/CallingConv.h"
     23 #include "llvm/IR/Constants.h"
     24 #include "llvm/IR/DerivedTypes.h"
     25 #include "llvm/IR/Function.h"
     26 #include "llvm/IR/Intrinsics.h"
     27 #include "llvm/IR/LLVMContext.h"
     28 #include "llvm/Support/Compiler.h"
     29 #include "llvm/Support/Debug.h"
     30 #include "llvm/Support/ErrorHandling.h"
     31 #include "llvm/Support/raw_ostream.h"
     32 #include "llvm/Target/TargetLowering.h"
     33 using namespace llvm;
     34 
     35 /// XCoreDAGToDAGISel - XCore specific code to select XCore machine
     36 /// instructions for SelectionDAG operations.
     37 ///
     38 namespace {
     39   class XCoreDAGToDAGISel : public SelectionDAGISel {
     40     const XCoreSubtarget &Subtarget;
     41 
     42   public:
     43     XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
     44       : SelectionDAGISel(TM, OptLevel),
     45         Subtarget(*TM.getSubtargetImpl()) { }
     46 
     47     SDNode *Select(SDNode *N) override;
     48     SDNode *SelectBRIND(SDNode *N);
     49 
     50     /// getI32Imm - Return a target constant with the specified value, of type
     51     /// i32.
     52     inline SDValue getI32Imm(unsigned Imm) {
     53       return CurDAG->getTargetConstant(Imm, MVT::i32);
     54     }
     55 
     56     inline bool immMskBitp(SDNode *inN) const {
     57       ConstantSDNode *N = cast<ConstantSDNode>(inN);
     58       uint32_t value = (uint32_t)N->getZExtValue();
     59       if (!isMask_32(value)) {
     60         return false;
     61       }
     62       int msksize = 32 - countLeadingZeros(value);
     63       return (msksize >= 1 && msksize <= 8) ||
     64               msksize == 16 || msksize == 24 || msksize == 32;
     65     }
     66 
     67     // Complex Pattern Selectors.
     68     bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
     69 
     70     bool SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
     71                                       std::vector<SDValue> &OutOps) override;
     72 
     73     const char *getPassName() const override {
     74       return "XCore DAG->DAG Pattern Instruction Selection";
     75     }
     76 
     77     // Include the pieces autogenerated from the target description.
     78   #include "XCoreGenDAGISel.inc"
     79   };
     80 }  // end anonymous namespace
     81 
     82 /// createXCoreISelDag - This pass converts a legalized DAG into a
     83 /// XCore-specific DAG, ready for instruction scheduling.
     84 ///
     85 FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
     86                                        CodeGenOpt::Level OptLevel) {
     87   return new XCoreDAGToDAGISel(TM, OptLevel);
     88 }
     89 
     90 bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
     91                                        SDValue &Offset) {
     92   FrameIndexSDNode *FIN = nullptr;
     93   if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
     94     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
     95     Offset = CurDAG->getTargetConstant(0, MVT::i32);
     96     return true;
     97   }
     98   if (Addr.getOpcode() == ISD::ADD) {
     99     ConstantSDNode *CN = nullptr;
    100     if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
    101       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    102       && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
    103       // Constant positive word offset from frame index
    104       Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
    105       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    106       return true;
    107     }
    108   }
    109   return false;
    110 }
    111 
    112 bool XCoreDAGToDAGISel::
    113 SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
    114                              std::vector<SDValue> &OutOps) {
    115   SDValue Reg;
    116   switch (ConstraintCode) {
    117   default: return true;
    118   case 'm': // Memory.
    119     switch (Op.getOpcode()) {
    120     default: return true;
    121     case XCoreISD::CPRelativeWrapper:
    122       Reg = CurDAG->getRegister(XCore::CP, MVT::i32);
    123       break;
    124     case XCoreISD::DPRelativeWrapper:
    125       Reg = CurDAG->getRegister(XCore::DP, MVT::i32);
    126       break;
    127     }
    128   }
    129   OutOps.push_back(Reg);
    130   OutOps.push_back(Op.getOperand(0));
    131   return false;
    132 }
    133 
    134 SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
    135   SDLoc dl(N);
    136   switch (N->getOpcode()) {
    137   default: break;
    138   case ISD::Constant: {
    139     uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
    140     if (immMskBitp(N)) {
    141       // Transformation function: get the size of a mask
    142       // Look for the first non-zero bit
    143       SDValue MskSize = getI32Imm(32 - countLeadingZeros((uint32_t)Val));
    144       return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
    145                                     MVT::i32, MskSize);
    146     }
    147     else if (!isUInt<16>(Val)) {
    148       SDValue CPIdx =
    149         CurDAG->getTargetConstantPool(ConstantInt::get(
    150                               Type::getInt32Ty(*CurDAG->getContext()), Val),
    151                                       getTargetLowering()->getPointerTy());
    152       SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
    153                                             MVT::Other, CPIdx,
    154                                             CurDAG->getEntryNode());
    155       MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
    156       MemOp[0] = MF->getMachineMemOperand(
    157         MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
    158       cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
    159       return node;
    160     }
    161     break;
    162   }
    163   case XCoreISD::LADD: {
    164     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    165                         N->getOperand(2) };
    166     return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
    167                                   Ops);
    168   }
    169   case XCoreISD::LSUB: {
    170     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    171                         N->getOperand(2) };
    172     return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
    173                                   Ops);
    174   }
    175   case XCoreISD::MACCU: {
    176     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    177                       N->getOperand(2), N->getOperand(3) };
    178     return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
    179                                   Ops);
    180   }
    181   case XCoreISD::MACCS: {
    182     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    183                       N->getOperand(2), N->getOperand(3) };
    184     return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
    185                                   Ops);
    186   }
    187   case XCoreISD::LMUL: {
    188     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    189                       N->getOperand(2), N->getOperand(3) };
    190     return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
    191                                   Ops);
    192   }
    193   case XCoreISD::CRC8: {
    194     SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
    195     return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
    196                                   Ops);
    197   }
    198   case ISD::BRIND:
    199     if (SDNode *ResNode = SelectBRIND(N))
    200       return ResNode;
    201     break;
    202   // Other cases are autogenerated.
    203   }
    204   return SelectCode(N);
    205 }
    206 
    207 /// Given a chain return a new chain where any appearance of Old is replaced
    208 /// by New. There must be at most one instruction between Old and Chain and
    209 /// this instruction must be a TokenFactor. Returns an empty SDValue if
    210 /// these conditions don't hold.
    211 static SDValue
    212 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
    213 {
    214   if (Chain == Old)
    215     return New;
    216   if (Chain->getOpcode() != ISD::TokenFactor)
    217     return SDValue();
    218   SmallVector<SDValue, 8> Ops;
    219   bool found = false;
    220   for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    221     if (Chain->getOperand(i) == Old) {
    222       Ops.push_back(New);
    223       found = true;
    224     } else {
    225       Ops.push_back(Chain->getOperand(i));
    226     }
    227   }
    228   if (!found)
    229     return SDValue();
    230   return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);
    231 }
    232 
    233 SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
    234   SDLoc dl(N);
    235   // (brind (int_xcore_checkevent (addr)))
    236   SDValue Chain = N->getOperand(0);
    237   SDValue Addr = N->getOperand(1);
    238   if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    239     return nullptr;
    240   unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
    241   if (IntNo != Intrinsic::xcore_checkevent)
    242     return nullptr;
    243   SDValue nextAddr = Addr->getOperand(2);
    244   SDValue CheckEventChainOut(Addr.getNode(), 1);
    245   if (!CheckEventChainOut.use_empty()) {
    246     // If the chain out of the checkevent intrinsic is an operand of the
    247     // indirect branch or used in a TokenFactor which is the operand of the
    248     // indirect branch then build a new chain which uses the chain coming into
    249     // the checkevent intrinsic instead.
    250     SDValue CheckEventChainIn = Addr->getOperand(0);
    251     SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
    252                                       CheckEventChainIn);
    253     if (!NewChain.getNode())
    254       return nullptr;
    255     Chain = NewChain;
    256   }
    257   // Enable events on the thread using setsr 1 and then disable them immediately
    258   // after with clrsr 1. If any resources owned by the thread are ready an event
    259   // will be taken. If no resource is ready we branch to the address which was
    260   // the operand to the checkevent intrinsic.
    261   SDValue constOne = getI32Imm(1);
    262   SDValue Glue =
    263     SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
    264                                    constOne, Chain), 0);
    265   Glue =
    266     SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
    267                                    constOne, Glue), 0);
    268   if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
    269       nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    270     return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
    271                                 nextAddr->getOperand(0), Glue);
    272   }
    273   return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
    274 }
    275