Coverage Report

Created: 2017-10-03 07:32

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