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/DerivedTypes.h"
     17 #include "llvm/Function.h"
     18 #include "llvm/Intrinsics.h"
     19 #include "llvm/CallingConv.h"
     20 #include "llvm/Constants.h"
     21 #include "llvm/LLVMContext.h"
     22 #include "llvm/CodeGen/MachineFrameInfo.h"
     23 #include "llvm/CodeGen/MachineFunction.h"
     24 #include "llvm/CodeGen/MachineInstrBuilder.h"
     25 #include "llvm/CodeGen/MachineRegisterInfo.h"
     26 #include "llvm/CodeGen/SelectionDAG.h"
     27 #include "llvm/CodeGen/SelectionDAGISel.h"
     28 #include "llvm/Target/TargetLowering.h"
     29 #include "llvm/Support/Compiler.h"
     30 #include "llvm/Support/Debug.h"
     31 #include "llvm/Support/ErrorHandling.h"
     32 #include "llvm/Support/raw_ostream.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 XCoreTargetLowering &Lowering;
     41     const XCoreSubtarget &Subtarget;
     42 
     43   public:
     44     XCoreDAGToDAGISel(XCoreTargetMachine &TM)
     45       : SelectionDAGISel(TM),
     46         Lowering(*TM.getTargetLowering()),
     47         Subtarget(*TM.getSubtargetImpl()) { }
     48 
     49     SDNode *Select(SDNode *N);
     50     SDNode *SelectBRIND(SDNode *N);
     51 
     52     /// getI32Imm - Return a target constant with the specified value, of type
     53     /// i32.
     54     inline SDValue getI32Imm(unsigned Imm) {
     55       return CurDAG->getTargetConstant(Imm, MVT::i32);
     56     }
     57 
     58     inline bool immMskBitp(SDNode *inN) const {
     59       ConstantSDNode *N = cast<ConstantSDNode>(inN);
     60       uint32_t value = (uint32_t)N->getZExtValue();
     61       if (!isMask_32(value)) {
     62         return false;
     63       }
     64       int msksize = 32 - CountLeadingZeros_32(value);
     65       return (msksize >= 1 && msksize <= 8) ||
     66               msksize == 16 || msksize == 24 || msksize == 32;
     67     }
     68 
     69     // Complex Pattern Selectors.
     70     bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
     71     bool SelectADDRdpii(SDValue Addr, SDValue &Base, SDValue &Offset);
     72     bool SelectADDRcpii(SDValue Addr, SDValue &Base, SDValue &Offset);
     73 
     74     virtual const char *getPassName() const {
     75       return "XCore DAG->DAG Pattern Instruction Selection";
     76     }
     77 
     78     // Include the pieces autogenerated from the target description.
     79   #include "XCoreGenDAGISel.inc"
     80   };
     81 }  // end anonymous namespace
     82 
     83 /// createXCoreISelDag - This pass converts a legalized DAG into a
     84 /// XCore-specific DAG, ready for instruction scheduling.
     85 ///
     86 FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM) {
     87   return new XCoreDAGToDAGISel(TM);
     88 }
     89 
     90 bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
     91                                        SDValue &Offset) {
     92   FrameIndexSDNode *FIN = 0;
     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 = 0;
    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::SelectADDRdpii(SDValue Addr, SDValue &Base,
    113                                        SDValue &Offset) {
    114   if (Addr.getOpcode() == XCoreISD::DPRelativeWrapper) {
    115     Base = Addr.getOperand(0);
    116     Offset = CurDAG->getTargetConstant(0, MVT::i32);
    117     return true;
    118   }
    119   if (Addr.getOpcode() == ISD::ADD) {
    120     ConstantSDNode *CN = 0;
    121     if ((Addr.getOperand(0).getOpcode() == XCoreISD::DPRelativeWrapper)
    122       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    123       && (CN->getSExtValue() % 4 == 0)) {
    124       // Constant word offset from a object in the data region
    125       Base = Addr.getOperand(0).getOperand(0);
    126       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    127       return true;
    128     }
    129   }
    130   return false;
    131 }
    132 
    133 bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
    134                                        SDValue &Offset) {
    135   if (Addr.getOpcode() == XCoreISD::CPRelativeWrapper) {
    136     Base = Addr.getOperand(0);
    137     Offset = CurDAG->getTargetConstant(0, MVT::i32);
    138     return true;
    139   }
    140   if (Addr.getOpcode() == ISD::ADD) {
    141     ConstantSDNode *CN = 0;
    142     if ((Addr.getOperand(0).getOpcode() == XCoreISD::CPRelativeWrapper)
    143       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    144       && (CN->getSExtValue() % 4 == 0)) {
    145       // Constant word offset from a object in the data region
    146       Base = Addr.getOperand(0).getOperand(0);
    147       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    148       return true;
    149     }
    150   }
    151   return false;
    152 }
    153 
    154 SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
    155   DebugLoc dl = N->getDebugLoc();
    156   switch (N->getOpcode()) {
    157   default: break;
    158   case ISD::Constant: {
    159     uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
    160     if (immMskBitp(N)) {
    161       // Transformation function: get the size of a mask
    162       // Look for the first non-zero bit
    163       SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
    164       return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
    165                                     MVT::i32, MskSize);
    166     }
    167     else if (!isUInt<16>(Val)) {
    168       SDValue CPIdx =
    169         CurDAG->getTargetConstantPool(ConstantInt::get(
    170                               Type::getInt32Ty(*CurDAG->getContext()), Val),
    171                                       TLI.getPointerTy());
    172       SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
    173                                             MVT::Other, CPIdx,
    174                                             CurDAG->getEntryNode());
    175       MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
    176       MemOp[0] = MF->getMachineMemOperand(
    177         MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
    178       cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
    179       return node;
    180     }
    181     break;
    182   }
    183   case XCoreISD::LADD: {
    184     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    185                         N->getOperand(2) };
    186     return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
    187                                   Ops, 3);
    188   }
    189   case XCoreISD::LSUB: {
    190     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    191                         N->getOperand(2) };
    192     return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
    193                                   Ops, 3);
    194   }
    195   case XCoreISD::MACCU: {
    196     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    197                       N->getOperand(2), N->getOperand(3) };
    198     return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
    199                                   Ops, 4);
    200   }
    201   case XCoreISD::MACCS: {
    202     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    203                       N->getOperand(2), N->getOperand(3) };
    204     return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
    205                                   Ops, 4);
    206   }
    207   case XCoreISD::LMUL: {
    208     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    209                       N->getOperand(2), N->getOperand(3) };
    210     return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
    211                                   Ops, 4);
    212   }
    213   case ISD::INTRINSIC_WO_CHAIN: {
    214     unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
    215     switch (IntNo) {
    216     case Intrinsic::xcore_crc8:
    217       SDValue Ops[] = { N->getOperand(1), N->getOperand(2), N->getOperand(3) };
    218       return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
    219                                     Ops, 3);
    220     }
    221     break;
    222   }
    223   case ISD::BRIND:
    224     if (SDNode *ResNode = SelectBRIND(N))
    225       return ResNode;
    226     break;
    227   // Other cases are autogenerated.
    228   }
    229   return SelectCode(N);
    230 }
    231 
    232 /// Given a chain return a new chain where any appearance of Old is replaced
    233 /// by New. There must be at most one instruction between Old and Chain and
    234 /// this instruction must be a TokenFactor. Returns an empty SDValue if
    235 /// these conditions don't hold.
    236 static SDValue
    237 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
    238 {
    239   if (Chain == Old)
    240     return New;
    241   if (Chain->getOpcode() != ISD::TokenFactor)
    242     return SDValue();
    243   SmallVector<SDValue, 8> Ops;
    244   bool found = false;
    245   for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    246     if (Chain->getOperand(i) == Old) {
    247       Ops.push_back(New);
    248       found = true;
    249     } else {
    250       Ops.push_back(Chain->getOperand(i));
    251     }
    252   }
    253   if (!found)
    254     return SDValue();
    255   return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
    256                          &Ops[0], Ops.size());
    257 }
    258 
    259 SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
    260   DebugLoc dl = N->getDebugLoc();
    261   // (brind (int_xcore_checkevent (addr)))
    262   SDValue Chain = N->getOperand(0);
    263   SDValue Addr = N->getOperand(1);
    264   if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    265     return 0;
    266   unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
    267   if (IntNo != Intrinsic::xcore_checkevent)
    268     return 0;
    269   SDValue nextAddr = Addr->getOperand(2);
    270   SDValue CheckEventChainOut(Addr.getNode(), 1);
    271   if (!CheckEventChainOut.use_empty()) {
    272     // If the chain out of the checkevent intrinsic is an operand of the
    273     // indirect branch or used in a TokenFactor which is the operand of the
    274     // indirect branch then build a new chain which uses the chain coming into
    275     // the checkevent intrinsic instead.
    276     SDValue CheckEventChainIn = Addr->getOperand(0);
    277     SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
    278                                       CheckEventChainIn);
    279     if (!NewChain.getNode())
    280       return 0;
    281     Chain = NewChain;
    282   }
    283   // Enable events on the thread using setsr 1 and then disable them immediately
    284   // after with clrsr 1. If any resources owned by the thread are ready an event
    285   // will be taken. If no resource is ready we branch to the address which was
    286   // the operand to the checkevent intrinsic.
    287   SDValue constOne = getI32Imm(1);
    288   SDValue Glue =
    289     SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
    290                                    constOne, Chain), 0);
    291   Glue =
    292     SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
    293                                    constOne, Glue), 0);
    294   if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
    295       nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    296     return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
    297                                 nextAddr->getOperand(0), Glue);
    298   }
    299   return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
    300 }
    301