Coverage Report

Created: 2019-07-24 05:18

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