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 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 XCoreISD::CRC8: {
    215     SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
    216     return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
    217                                   Ops, 3);
    218   }
    219   case ISD::BRIND:
    220     if (SDNode *ResNode = SelectBRIND(N))
    221       return ResNode;
    222     break;
    223   // Other cases are autogenerated.
    224   }
    225   return SelectCode(N);
    226 }
    227 
    228 /// Given a chain return a new chain where any appearance of Old is replaced
    229 /// by New. There must be at most one instruction between Old and Chain and
    230 /// this instruction must be a TokenFactor. Returns an empty SDValue if
    231 /// these conditions don't hold.
    232 static SDValue
    233 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
    234 {
    235   if (Chain == Old)
    236     return New;
    237   if (Chain->getOpcode() != ISD::TokenFactor)
    238     return SDValue();
    239   SmallVector<SDValue, 8> Ops;
    240   bool found = false;
    241   for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
    242     if (Chain->getOperand(i) == Old) {
    243       Ops.push_back(New);
    244       found = true;
    245     } else {
    246       Ops.push_back(Chain->getOperand(i));
    247     }
    248   }
    249   if (!found)
    250     return SDValue();
    251   return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
    252                          &Ops[0], Ops.size());
    253 }
    254 
    255 SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
    256   DebugLoc dl = N->getDebugLoc();
    257   // (brind (int_xcore_checkevent (addr)))
    258   SDValue Chain = N->getOperand(0);
    259   SDValue Addr = N->getOperand(1);
    260   if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
    261     return 0;
    262   unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
    263   if (IntNo != Intrinsic::xcore_checkevent)
    264     return 0;
    265   SDValue nextAddr = Addr->getOperand(2);
    266   SDValue CheckEventChainOut(Addr.getNode(), 1);
    267   if (!CheckEventChainOut.use_empty()) {
    268     // If the chain out of the checkevent intrinsic is an operand of the
    269     // indirect branch or used in a TokenFactor which is the operand of the
    270     // indirect branch then build a new chain which uses the chain coming into
    271     // the checkevent intrinsic instead.
    272     SDValue CheckEventChainIn = Addr->getOperand(0);
    273     SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
    274                                       CheckEventChainIn);
    275     if (!NewChain.getNode())
    276       return 0;
    277     Chain = NewChain;
    278   }
    279   // Enable events on the thread using setsr 1 and then disable them immediately
    280   // after with clrsr 1. If any resources owned by the thread are ready an event
    281   // will be taken. If no resource is ready we branch to the address which was
    282   // the operand to the checkevent intrinsic.
    283   SDValue constOne = getI32Imm(1);
    284   SDValue Glue =
    285     SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
    286                                    constOne, Chain), 0);
    287   Glue =
    288     SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
    289                                    constOne, Glue), 0);
    290   if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
    291       nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
    292     return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
    293                                 nextAddr->getOperand(0), Glue);
    294   }
    295   return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
    296 }
    297