Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
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 SPARC target.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "SparcTargetMachine.h"
14
#include "llvm/CodeGen/MachineRegisterInfo.h"
15
#include "llvm/CodeGen/SelectionDAGISel.h"
16
#include "llvm/IR/Intrinsics.h"
17
#include "llvm/Support/Debug.h"
18
#include "llvm/Support/ErrorHandling.h"
19
#include "llvm/Support/raw_ostream.h"
20
using namespace llvm;
21
22
//===----------------------------------------------------------------------===//
23
// Instruction Selector Implementation
24
//===----------------------------------------------------------------------===//
25
26
//===--------------------------------------------------------------------===//
27
/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
28
/// instructions for SelectionDAG operations.
29
///
30
namespace {
31
class SparcDAGToDAGISel : public SelectionDAGISel {
32
  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
33
  /// make the right decision when generating code for different targets.
34
  const SparcSubtarget *Subtarget;
35
public:
36
198
  explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
37
38
694
  bool runOnMachineFunction(MachineFunction &MF) override {
39
694
    Subtarget = &MF.getSubtarget<SparcSubtarget>();
40
694
    return SelectionDAGISel::runOnMachineFunction(MF);
41
694
  }
42
43
  void Select(SDNode *N) override;
44
45
  // Complex Pattern Selectors.
46
  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
47
  bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
48
49
  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
50
  /// inline asm expressions.
51
  bool SelectInlineAsmMemoryOperand(const SDValue &Op,
52
                                    unsigned ConstraintID,
53
                                    std::vector<SDValue> &OutOps) override;
54
55
694
  StringRef getPassName() const override {
56
694
    return "SPARC DAG->DAG Pattern Instruction Selection";
57
694
  }
58
59
  // Include the pieces autogenerated from the target description.
60
#include "SparcGenDAGISel.inc"
61
62
private:
63
  SDNode* getGlobalBaseReg();
64
  bool tryInlineAsm(SDNode *N);
65
};
66
}  // end anonymous namespace
67
68
42
SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
69
42
  unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
70
42
  return CurDAG->getRegister(GlobalBaseReg,
71
42
                             TLI->getPointerTy(CurDAG->getDataLayout()))
72
42
      .getNode();
73
42
}
74
75
bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
76
5.97k
                                     SDValue &Base, SDValue &Offset) {
77
5.97k
  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
78
838
    Base = CurDAG->getTargetFrameIndex(
79
838
        FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
80
838
    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
81
838
    return true;
82
838
  }
83
5.13k
  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
84
5.13k
      
Addr.getOpcode() == ISD::TargetGlobalAddress4.96k
||
85
5.13k
      
Addr.getOpcode() == ISD::TargetGlobalTLSAddress4.78k
)
86
351
    return false;  // direct calls.
87
4.78k
88
4.78k
  if (Addr.getOpcode() == ISD::ADD) {
89
4.78k
    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
90
4.67k
      if (isInt<13>(CN->getSExtValue())) {
91
4.67k
        if (FrameIndexSDNode *FIN =
92
77
                dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
93
77
          // Constant offset from frame ref.
94
77
          Base = CurDAG->getTargetFrameIndex(
95
77
              FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));
96
4.59k
        } else {
97
4.59k
          Base = Addr.getOperand(0);
98
4.59k
        }
99
4.67k
        Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
100
4.67k
                                           MVT::i32);
101
4.67k
        return true;
102
4.67k
      }
103
108
    }
104
108
    if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
105
0
      Base = Addr.getOperand(1);
106
0
      Offset = Addr.getOperand(0).getOperand(0);
107
0
      return true;
108
0
    }
109
108
    if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
110
108
      Base = Addr.getOperand(0);
111
108
      Offset = Addr.getOperand(1).getOperand(0);
112
108
      return true;
113
108
    }
114
0
  }
115
0
  Base = Addr;
116
0
  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
117
0
  return true;
118
0
}
119
120
6.41k
bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
121
6.41k
  if (Addr.getOpcode() == ISD::FrameIndex) 
return false711
;
122
5.70k
  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
123
5.70k
      
Addr.getOpcode() == ISD::TargetGlobalAddress5.54k
||
124
5.70k
      
Addr.getOpcode() == ISD::TargetGlobalTLSAddress5.35k
)
125
351
    return false;  // direct calls.
126
5.35k
127
5.35k
  if (Addr.getOpcode() == ISD::ADD) {
128
4.83k
    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
129
4.67k
      if (isInt<13>(CN->getSExtValue()))
130
4.67k
        return false;  // Let the reg+imm pattern catch this!
131
158
    if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
132
158
        Addr.getOperand(1).getOpcode() == SPISD::Lo)
133
108
      return false;  // Let the reg+imm pattern catch this!
134
50
    R1 = Addr.getOperand(0);
135
50
    R2 = Addr.getOperand(1);
136
50
    return true;
137
50
  }
138
525
139
525
  R1 = Addr;
140
525
  R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));
141
525
  return true;
142
525
}
143
144
145
// Re-assemble i64 arguments split up in SelectionDAGBuilder's
146
// visitInlineAsm / GetRegistersForValue functions.
147
//
148
// Note: This function was copied from, and is essentially identical
149
// to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that
150
// such hacking-up is necessary; a rethink of how inline asm operands
151
// are handled may be in order to make doing this more sane.
152
//
153
// TODO: fix inline asm support so I can simply tell it that 'i64'
154
// inputs to asm need to be allocated to the IntPair register type,
155
// and have that work. Then, delete this function.
156
108
bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){
157
108
  std::vector<SDValue> AsmNodeOperands;
158
108
  unsigned Flag, Kind;
159
108
  bool Changed = false;
160
108
  unsigned NumOps = N->getNumOperands();
161
108
162
108
  // Normally, i64 data is bounded to two arbitrary GPRs for "%r"
163
108
  // constraint.  However, some instructions (e.g. ldd/std) require
164
108
  // (even/even+1) GPRs.
165
108
166
108
  // So, here, we check for this case, and mutate the inlineasm to use
167
108
  // a single IntPair register instead, which guarantees such even/odd
168
108
  // placement.
169
108
170
108
  SDLoc dl(N);
171
108
  SDValue Glue = N->getGluedNode() ? 
N->getOperand(NumOps-1)63
172
108
                                   : 
SDValue(nullptr,0)45
;
173
108
174
108
  SmallVector<bool, 8> OpChanged;
175
108
  // Glue node will be appended late.
176
2.85k
  for(unsigned i = 0, e = N->getGluedNode() ? 
NumOps - 163
:
NumOps45
; i < e;
++i2.75k
) {
177
2.75k
    SDValue op = N->getOperand(i);
178
2.75k
    AsmNodeOperands.push_back(op);
179
2.75k
180
2.75k
    if (i < InlineAsm::Op_FirstOperand)
181
432
      continue;
182
2.31k
183
2.31k
    if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
184
1.17k
      Flag = C->getZExtValue();
185
1.17k
      Kind = InlineAsm::getKind(Flag);
186
1.17k
    }
187
1.14k
    else
188
1.14k
      continue;
189
1.17k
190
1.17k
    // Immediate operands to inline asm in the SelectionDAG are modeled with
191
1.17k
    // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
192
1.17k
    // the second is a constant with the value of the immediate. If we get here
193
1.17k
    // and we have a Kind_Imm, skip the next operand, and continue.
194
1.17k
    if (Kind == InlineAsm::Kind_Imm) {
195
18
      SDValue op = N->getOperand(++i);
196
18
      AsmNodeOperands.push_back(op);
197
18
      continue;
198
18
    }
199
1.15k
200
1.15k
    unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
201
1.15k
    if (NumRegs)
202
1.15k
      OpChanged.push_back(false);
203
1.15k
204
1.15k
    unsigned DefIdx = 0;
205
1.15k
    bool IsTiedToChangedOp = false;
206
1.15k
    // If it's a use that is tied with a previous def, it has no
207
1.15k
    // reg class constraint.
208
1.15k
    if (Changed && 
InlineAsm::isUseOperandTiedToDef(Flag, DefIdx)32
)
209
2
      IsTiedToChangedOp = OpChanged[DefIdx];
210
1.15k
211
1.15k
    if (Kind != InlineAsm::Kind_RegUse && 
Kind != InlineAsm::Kind_RegDef1.05k
212
1.15k
        && 
Kind != InlineAsm::Kind_RegDefEarlyClobber994
)
213
994
      continue;
214
159
215
159
    unsigned RC;
216
159
    bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
217
159
    if ((!IsTiedToChangedOp && 
(157
!HasRC157
||
RC != SP::IntRegsRegClassID136
))
218
159
        || 
NumRegs != 292
)
219
152
      continue;
220
7
221
7
    assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
222
7
    SDValue V0 = N->getOperand(i+1);
223
7
    SDValue V1 = N->getOperand(i+2);
224
7
    unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
225
7
    unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
226
7
    SDValue PairedReg;
227
7
    MachineRegisterInfo &MRI = MF->getRegInfo();
228
7
229
7
    if (Kind == InlineAsm::Kind_RegDef ||
230
7
        
Kind == InlineAsm::Kind_RegDefEarlyClobber5
) {
231
2
      // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
232
2
      // the original GPRs.
233
2
234
2
      unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
235
2
      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
236
2
      SDValue Chain = SDValue(N,0);
237
2
238
2
      SDNode *GU = N->getGluedUser();
239
2
      SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,
240
2
                                               Chain.getValue(1));
241
2
242
2
      // Extract values from a GPRPair reg and copy to the original GPR reg.
243
2
      SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,
244
2
                                                    RegCopy);
245
2
      SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,
246
2
                                                    RegCopy);
247
2
      SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
248
2
                                        RegCopy.getValue(1));
249
2
      SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
250
2
251
2
      // Update the original glue user.
252
2
      std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
253
2
      Ops.push_back(T1.getValue(1));
254
2
      CurDAG->UpdateNodeOperands(GU, Ops);
255
2
    }
256
5
    else {
257
5
      // For Kind  == InlineAsm::Kind_RegUse, we first copy two GPRs into a
258
5
      // GPRPair and then pass the GPRPair to the inline asm.
259
5
      SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
260
5
261
5
      // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
262
5
      SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
263
5
                                          Chain.getValue(1));
264
5
      SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
265
5
                                          T0.getValue(1));
266
5
      SDValue Pair = SDValue(
267
5
          CurDAG->getMachineNode(
268
5
              TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,
269
5
              {
270
5
                  CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,
271
5
                                            MVT::i32),
272
5
                  T0,
273
5
                  CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),
274
5
                  T1,
275
5
                  CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),
276
5
              }),
277
5
          0);
278
5
279
5
      // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
280
5
      // i32 VRs of inline asm with it.
281
5
      unsigned GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);
282
5
      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);
283
5
      Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
284
5
285
5
      AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
286
5
      Glue = Chain.getValue(1);
287
5
    }
288
7
289
7
    Changed = true;
290
7
291
7
    if(PairedReg.getNode()) {
292
7
      OpChanged[OpChanged.size() -1 ] = true;
293
7
      Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
294
7
      if (IsTiedToChangedOp)
295
2
        Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
296
5
      else
297
5
        Flag = InlineAsm::getFlagWordForRegClass(Flag, SP::IntPairRegClassID);
298
7
      // Replace the current flag.
299
7
      AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
300
7
          Flag, dl, MVT::i32);
301
7
      // Add the new register node and skip the original two GPRs.
302
7
      AsmNodeOperands.push_back(PairedReg);
303
7
      // Skip the next two GPRs.
304
7
      i += 2;
305
7
    }
306
7
  }
307
108
308
108
  if (Glue.getNode())
309
63
    AsmNodeOperands.push_back(Glue);
310
108
  if (!Changed)
311
103
    return false;
312
5
313
5
  SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));
314
5
315
5
  SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
316
5
      CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
317
5
  New->setNodeId(-1);
318
5
  ReplaceNode(N, New.getNode());
319
5
  return true;
320
5
}
321
322
26.5k
void SparcDAGToDAGISel::Select(SDNode *N) {
323
26.5k
  SDLoc dl(N);
324
26.5k
  if (N->isMachineOpcode()) {
325
4.56k
    N->setNodeId(-1);
326
4.56k
    return;   // Already selected.
327
4.56k
  }
328
21.9k
329
21.9k
  switch (N->getOpcode()) {
330
21.9k
  
default: break21.8k
;
331
21.9k
  case ISD::INLINEASM:
332
108
  case ISD::INLINEASM_BR: {
333
108
    if (tryInlineAsm(N))
334
5
      return;
335
103
    break;
336
103
  }
337
103
  case SPISD::GLOBAL_BASE_REG:
338
42
    ReplaceNode(N, getGlobalBaseReg());
339
42
    return;
340
103
341
103
  case ISD::SDIV:
342
13
  case ISD::UDIV: {
343
13
    // sdivx / udivx handle 64-bit divides.
344
13
    if (N->getValueType(0) == MVT::i64)
345
7
      break;
346
6
    // FIXME: should use a custom expander to expose the SRA to the dag.
347
6
    SDValue DivLHS = N->getOperand(0);
348
6
    SDValue DivRHS = N->getOperand(1);
349
6
350
6
    // Set the Y register to the high-part.
351
6
    SDValue TopPart;
352
6
    if (N->getOpcode() == ISD::SDIV) {
353
1
      TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
354
1
                                   CurDAG->getTargetConstant(31, dl, MVT::i32)),
355
1
                        0);
356
5
    } else {
357
5
      TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
358
5
    }
359
6
    TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,
360
6
                                   SDValue())
361
6
                  .getValue(1);
362
6
363
6
    // FIXME: Handle div by immediate.
364
6
    unsigned Opcode = N->getOpcode() == ISD::SDIV ? 
SP::SDIVrr1
:
SP::UDIVrr5
;
365
6
    CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);
366
6
    return;
367
6
  }
368
21.9k
  }
369
21.9k
370
21.9k
  SelectCode(N);
371
21.9k
}
372
373
374
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
375
/// inline asm expressions.
376
bool
377
SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
378
                                                unsigned ConstraintID,
379
20
                                                std::vector<SDValue> &OutOps) {
380
20
  SDValue Op0, Op1;
381
20
  switch (ConstraintID) {
382
20
  
default: return true0
;
383
20
  case InlineAsm::Constraint_i:
384
20
  case InlineAsm::Constraint_o:
385
20
  case InlineAsm::Constraint_m: // memory
386
20
   if (!SelectADDRrr(Op, Op0, Op1))
387
13
     SelectADDRri(Op, Op0, Op1);
388
20
   break;
389
20
  }
390
20
391
20
  OutOps.push_back(Op0);
392
20
  OutOps.push_back(Op1);
393
20
  return false;
394
20
}
395
396
/// createSparcISelDag - This pass converts a legalized DAG into a
397
/// SPARC-specific DAG, ready for instruction scheduling.
398
///
399
198
FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
400
198
  return new SparcDAGToDAGISel(TM);
401
198
}