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, CodeGenOpt::Level OptLevel)
     45       : SelectionDAGISel(TM, OptLevel),
     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                                        CodeGenOpt::Level OptLevel) {
     88   return new XCoreDAGToDAGISel(TM, OptLevel);
     89 }
     90 
     91 bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
     92                                        SDValue &Offset) {
     93   FrameIndexSDNode *FIN = 0;
     94   if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
     95     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
     96     Offset = CurDAG->getTargetConstant(0, MVT::i32);
     97     return true;
     98   }
     99   if (Addr.getOpcode() == ISD::ADD) {
    100     ConstantSDNode *CN = 0;
    101     if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
    102       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    103       && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
    104       // Constant positive word offset from frame index
    105       Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
    106       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    107       return true;
    108     }
    109   }
    110   return false;
    111 }
    112 
    113 bool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Addr, SDValue &Base,
    114                                        SDValue &Offset) {
    115   if (Addr.getOpcode() == XCoreISD::DPRelativeWrapper) {
    116     Base = Addr.getOperand(0);
    117     Offset = CurDAG->getTargetConstant(0, MVT::i32);
    118     return true;
    119   }
    120   if (Addr.getOpcode() == ISD::ADD) {
    121     ConstantSDNode *CN = 0;
    122     if ((Addr.getOperand(0).getOpcode() == XCoreISD::DPRelativeWrapper)
    123       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    124       && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
    125       // Constant word offset from a object in the data region
    126       Base = Addr.getOperand(0).getOperand(0);
    127       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    128       return true;
    129     }
    130   }
    131   return false;
    132 }
    133 
    134 bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
    135                                        SDValue &Offset) {
    136   if (Addr.getOpcode() == XCoreISD::CPRelativeWrapper) {
    137     Base = Addr.getOperand(0);
    138     Offset = CurDAG->getTargetConstant(0, MVT::i32);
    139     return true;
    140   }
    141   if (Addr.getOpcode() == ISD::ADD) {
    142     ConstantSDNode *CN = 0;
    143     if ((Addr.getOperand(0).getOpcode() == XCoreISD::CPRelativeWrapper)
    144       && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
    145       && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
    146       // Constant word offset from a object in the data region
    147       Base = Addr.getOperand(0).getOperand(0);
    148       Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
    149       return true;
    150     }
    151   }
    152   return false;
    153 }
    154 
    155 SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
    156   DebugLoc dl = N->getDebugLoc();
    157   switch (N->getOpcode()) {
    158   default: break;
    159   case ISD::Constant: {
    160     uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
    161     if (immMskBitp(N)) {
    162       // Transformation function: get the size of a mask
    163       // Look for the first non-zero bit
    164       SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
    165       return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
    166                                     MVT::i32, MskSize);
    167     }
    168     else if (!isUInt<16>(Val)) {
    169       SDValue CPIdx =
    170         CurDAG->getTargetConstantPool(ConstantInt::get(
    171                               Type::getInt32Ty(*CurDAG->getContext()), Val),
    172                                       TLI.getPointerTy());
    173       SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
    174                                             MVT::Other, CPIdx,
    175                                             CurDAG->getEntryNode());
    176       MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
    177       MemOp[0] = MF->getMachineMemOperand(
    178         MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
    179       cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
    180       return node;
    181     }
    182     break;
    183   }
    184   case XCoreISD::LADD: {
    185     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    186                         N->getOperand(2) };
    187     return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
    188                                   Ops, 3);
    189   }
    190   case XCoreISD::LSUB: {
    191     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    192                         N->getOperand(2) };
    193     return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
    194                                   Ops, 3);
    195   }
    196   case XCoreISD::MACCU: {
    197     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    198                       N->getOperand(2), N->getOperand(3) };
    199     return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
    200                                   Ops, 4);
    201   }
    202   case XCoreISD::MACCS: {
    203     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    204                       N->getOperand(2), N->getOperand(3) };
    205     return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
    206                                   Ops, 4);
    207   }
    208   case XCoreISD::LMUL: {
    209     SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
    210                       N->getOperand(2), N->getOperand(3) };
    211     return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
    212                                   Ops, 4);
    213   }
    214   case ISD::INTRINSIC_WO_CHAIN: {
    215     unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
    216     switch (IntNo) {
    217     case Intrinsic::xcore_crc8:
    218       SDValue Ops[] = { N->getOperand(1), N->getOperand(2), N->getOperand(3) };
    219       return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
    220                                     Ops, 3);
    221     }
    222     break;
    223   }
    224   case ISD::BRIND:
    225     if (SDNode *ResNode = SelectBRIND(N))
    226       return ResNode;
    227     break;
    228   // Other cases are autogenerated.
    229   }
    230   return SelectCode(N);
    231 }
    232 
    233 /// Given a chain return a new chain where any appearance of Old is replaced
    234 /// by New. There must be at most one instruction between Old and Chain and
    235 /// this instruction must be a TokenFactor. Returns an empty SDValue if
    236 /// these conditions don't hold.
    237 static SDValue
    238 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
    239 {
    240   if (Chain == Old)
    241     return New;
    242   if (Chain->getOpcode() != ISD::TokenFactor)
    243     return SDValue();
    244   SmallVector<SDValue, 8> Ops;
    245   bool found = false;
    246   for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    247     if (Chain->getOperand(i) == Old) {
    248       Ops.push_back(New);
    249       found = true;
    250     } else {
    251       Ops.push_back(Chain->getOperand(i));
    252     }
    253   }
    254   if (!found)
    255     return SDValue();
    256   return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
    257                          &Ops[0], Ops.size());
    258 }
    259 
    260 SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
    261   DebugLoc dl = N->getDebugLoc();
    262   // (brind (int_xcore_checkevent (addr)))
    263   SDValue Chain = N->getOperand(0);
    264   SDValue Addr = N->getOperand(1);
    265   if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    266     return 0;
    267   unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
    268   if (IntNo != Intrinsic::xcore_checkevent)
    269     return 0;
    270   SDValue nextAddr = Addr->getOperand(2);
    271   SDValue CheckEventChainOut(Addr.getNode(), 1);
    272   if (!CheckEventChainOut.use_empty()) {
    273     // If the chain out of the checkevent intrinsic is an operand of the
    274     // indirect branch or used in a TokenFactor which is the operand of the
    275     // indirect branch then build a new chain which uses the chain coming into
    276     // the checkevent intrinsic instead.
    277     SDValue CheckEventChainIn = Addr->getOperand(0);
    278     SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
    279                                       CheckEventChainIn);
    280     if (!NewChain.getNode())
    281       return 0;
    282     Chain = NewChain;
    283   }
    284   // Enable events on the thread using setsr 1 and then disable them immediately
    285   // after with clrsr 1. If any resources owned by the thread are ready an event
    286   // will be taken. If no resource is ready we branch to the address which was
    287   // the operand to the checkevent intrinsic.
    288   SDValue constOne = getI32Imm(1);
    289   SDValue Glue =
    290     SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
    291                                    constOne, Chain), 0);
    292   Glue =
    293     SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
    294                                    constOne, Glue), 0);
    295   if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
    296       nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    297     return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
    298                                 nextAddr->getOperand(0), Glue);
    299   }
    300   return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
    301 }
    302