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