Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp
35294 views
1
//===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//
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 CSKY target.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "CSKY.h"
14
#include "CSKYSubtarget.h"
15
#include "CSKYTargetMachine.h"
16
#include "MCTargetDesc/CSKYMCTargetDesc.h"
17
#include "llvm/CodeGen/MachineFrameInfo.h"
18
#include "llvm/CodeGen/SelectionDAG.h"
19
#include "llvm/CodeGen/SelectionDAGISel.h"
20
21
using namespace llvm;
22
23
#define DEBUG_TYPE "csky-isel"
24
#define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"
25
26
namespace {
27
class CSKYDAGToDAGISel : public SelectionDAGISel {
28
const CSKYSubtarget *Subtarget;
29
30
public:
31
explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM, CodeGenOptLevel OptLevel)
32
: SelectionDAGISel(TM, OptLevel) {}
33
34
bool runOnMachineFunction(MachineFunction &MF) override {
35
// Reset the subtarget each time through.
36
Subtarget = &MF.getSubtarget<CSKYSubtarget>();
37
SelectionDAGISel::runOnMachineFunction(MF);
38
return true;
39
}
40
41
void Select(SDNode *N) override;
42
bool selectAddCarry(SDNode *N);
43
bool selectSubCarry(SDNode *N);
44
bool selectBITCAST_TO_LOHI(SDNode *N);
45
bool selectInlineAsm(SDNode *N);
46
47
SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
48
49
bool SelectInlineAsmMemoryOperand(const SDValue &Op,
50
InlineAsm::ConstraintCode ConstraintID,
51
std::vector<SDValue> &OutOps) override;
52
53
#include "CSKYGenDAGISel.inc"
54
};
55
56
class CSKYDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
57
public:
58
static char ID;
59
explicit CSKYDAGToDAGISelLegacy(CSKYTargetMachine &TM,
60
CodeGenOptLevel OptLevel)
61
: SelectionDAGISelLegacy(
62
ID, std::make_unique<CSKYDAGToDAGISel>(TM, OptLevel)) {}
63
};
64
} // namespace
65
66
char CSKYDAGToDAGISelLegacy::ID = 0;
67
68
INITIALIZE_PASS(CSKYDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
69
70
void CSKYDAGToDAGISel::Select(SDNode *N) {
71
// If we have a custom node, we have already selected
72
if (N->isMachineOpcode()) {
73
LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");
74
N->setNodeId(-1);
75
return;
76
}
77
78
SDLoc Dl(N);
79
unsigned Opcode = N->getOpcode();
80
bool IsSelected = false;
81
82
switch (Opcode) {
83
default:
84
break;
85
case ISD::UADDO_CARRY:
86
IsSelected = selectAddCarry(N);
87
break;
88
case ISD::USUBO_CARRY:
89
IsSelected = selectSubCarry(N);
90
break;
91
case ISD::GLOBAL_OFFSET_TABLE: {
92
Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
93
ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());
94
95
IsSelected = true;
96
break;
97
}
98
case ISD::FrameIndex: {
99
SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);
100
int FI = cast<FrameIndexSDNode>(N)->getIndex();
101
SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);
102
ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32
103
: CSKY::ADDI16XZ,
104
Dl, MVT::i32, TFI, Imm));
105
106
IsSelected = true;
107
break;
108
}
109
case CSKYISD::BITCAST_TO_LOHI:
110
IsSelected = selectBITCAST_TO_LOHI(N);
111
break;
112
case ISD::INLINEASM:
113
case ISD::INLINEASM_BR:
114
IsSelected = selectInlineAsm(N);
115
break;
116
}
117
118
if (IsSelected)
119
return;
120
121
// Select the default instruction.
122
SelectCode(N);
123
}
124
125
bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) {
126
std::vector<SDValue> AsmNodeOperands;
127
InlineAsm::Flag Flag;
128
bool Changed = false;
129
unsigned NumOps = N->getNumOperands();
130
131
// Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
132
// However, some instructions (e.g. mula.s32) require GPR pair.
133
// Since there is no constraint to explicitly specify a
134
// reg pair, we use GPRPair reg class for "%r" for 64-bit data.
135
136
SDLoc dl(N);
137
SDValue Glue =
138
N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0);
139
140
SmallVector<bool, 8> OpChanged;
141
// Glue node will be appended late.
142
for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
143
++i) {
144
SDValue op = N->getOperand(i);
145
AsmNodeOperands.push_back(op);
146
147
if (i < InlineAsm::Op_FirstOperand)
148
continue;
149
150
if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))
151
Flag = InlineAsm::Flag(C->getZExtValue());
152
else
153
continue;
154
155
// Immediate operands to inline asm in the SelectionDAG are modeled with
156
// two operands. The first is a constant of value InlineAsm::Kind::Imm, and
157
// the second is a constant with the value of the immediate. If we get here
158
// and we have a Kind::Imm, skip the next operand, and continue.
159
if (Flag.isImmKind()) {
160
SDValue op = N->getOperand(++i);
161
AsmNodeOperands.push_back(op);
162
continue;
163
}
164
165
const unsigned NumRegs = Flag.getNumOperandRegisters();
166
if (NumRegs)
167
OpChanged.push_back(false);
168
169
unsigned DefIdx = 0;
170
bool IsTiedToChangedOp = false;
171
// If it's a use that is tied with a previous def, it has no
172
// reg class constraint.
173
if (Changed && Flag.isUseOperandTiedToDef(DefIdx))
174
IsTiedToChangedOp = OpChanged[DefIdx];
175
176
// Memory operands to inline asm in the SelectionDAG are modeled with two
177
// operands: a constant of value InlineAsm::Kind::Mem followed by the input
178
// operand. If we get here and we have a Kind::Mem, skip the next operand
179
// (so it doesn't get misinterpreted), and continue. We do this here because
180
// it's important to update the OpChanged array correctly before moving on.
181
if (Flag.isMemKind()) {
182
SDValue op = N->getOperand(++i);
183
AsmNodeOperands.push_back(op);
184
continue;
185
}
186
187
if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&
188
!Flag.isRegDefEarlyClobberKind())
189
continue;
190
191
unsigned RC;
192
const bool HasRC = Flag.hasRegClassConstraint(RC);
193
if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
194
NumRegs != 2)
195
continue;
196
197
assert((i + 2 < NumOps) && "Invalid number of operands in inline asm");
198
SDValue V0 = N->getOperand(i + 1);
199
SDValue V1 = N->getOperand(i + 2);
200
unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
201
unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
202
SDValue PairedReg;
203
MachineRegisterInfo &MRI = MF->getRegInfo();
204
205
if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {
206
// Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
207
// the original GPRs.
208
209
Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
210
PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
211
SDValue Chain = SDValue(N, 0);
212
213
SDNode *GU = N->getGluedUser();
214
SDValue RegCopy =
215
CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1));
216
217
// Extract values from a GPRPair reg and copy to the original GPR reg.
218
SDValue Sub0 =
219
CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);
220
SDValue Sub1 =
221
CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);
222
SDValue T0 =
223
CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1));
224
SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
225
226
// Update the original glue user.
227
std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1);
228
Ops.push_back(T1.getValue(1));
229
CurDAG->UpdateNodeOperands(GU, Ops);
230
} else {
231
// For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a
232
// GPRPair and then pass the GPRPair to the inline asm.
233
SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
234
235
// As REG_SEQ doesn't take RegisterSDNode, we copy them first.
236
SDValue T0 =
237
CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1));
238
SDValue T1 =
239
CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1));
240
SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0);
241
242
// Copy REG_SEQ into a GPRPair-typed VR and replace the original two
243
// i32 VRs of inline asm with it.
244
Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
245
PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
246
Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
247
248
AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
249
Glue = Chain.getValue(1);
250
}
251
252
Changed = true;
253
254
if (PairedReg.getNode()) {
255
OpChanged[OpChanged.size() - 1] = true;
256
// TODO: maybe a setter for getNumOperandRegisters?
257
Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);
258
if (IsTiedToChangedOp)
259
Flag.setMatchingOp(DefIdx);
260
else
261
Flag.setRegClass(CSKY::GPRPairRegClassID);
262
// Replace the current flag.
263
AsmNodeOperands[AsmNodeOperands.size() - 1] =
264
CurDAG->getTargetConstant(Flag, dl, MVT::i32);
265
// Add the new register node and skip the original two GPRs.
266
AsmNodeOperands.push_back(PairedReg);
267
// Skip the next two GPRs.
268
i += 2;
269
}
270
}
271
272
if (Glue.getNode())
273
AsmNodeOperands.push_back(Glue);
274
if (!Changed)
275
return false;
276
277
SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
278
CurDAG->getVTList(MVT::Other, MVT::Glue),
279
AsmNodeOperands);
280
New->setNodeId(-1);
281
ReplaceNode(N, New.getNode());
282
return true;
283
}
284
285
bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) {
286
SDLoc Dl(N);
287
auto VT = N->getValueType(0);
288
auto V = N->getOperand(0);
289
290
if (!Subtarget->hasFPUv2DoubleFloat())
291
return false;
292
293
SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0);
294
SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0);
295
296
ReplaceUses(SDValue(N, 0), V1);
297
ReplaceUses(SDValue(N, 1), V2);
298
CurDAG->RemoveDeadNode(N);
299
300
return true;
301
}
302
303
bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {
304
MachineSDNode *NewNode = nullptr;
305
auto Type0 = N->getValueType(0);
306
auto Type1 = N->getValueType(1);
307
auto Op0 = N->getOperand(0);
308
auto Op1 = N->getOperand(1);
309
auto Op2 = N->getOperand(2);
310
311
SDLoc Dl(N);
312
313
if (isNullConstant(Op2)) {
314
auto *CA = CurDAG->getMachineNode(
315
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
316
NewNode = CurDAG->getMachineNode(
317
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
318
{Op0, Op1, SDValue(CA, 0)});
319
} else if (isOneConstant(Op2)) {
320
auto *CA = CurDAG->getMachineNode(
321
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
322
NewNode = CurDAG->getMachineNode(
323
Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},
324
{Op0, Op1, SDValue(CA, 0)});
325
} else {
326
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
327
: CSKY::ADDC16,
328
Dl, {Type0, Type1}, {Op0, Op1, Op2});
329
}
330
ReplaceNode(N, NewNode);
331
return true;
332
}
333
334
static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,
335
SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {
336
auto NewCarryReg =
337
DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,
338
MVT::i32, OldCarry);
339
auto NewCarry =
340
DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,
341
Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),
342
DAG->getTargetConstant(0, Dl, MVT::i32));
343
return SDValue(NewCarry, 0);
344
}
345
346
bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {
347
MachineSDNode *NewNode = nullptr;
348
auto Type0 = N->getValueType(0);
349
auto Type1 = N->getValueType(1);
350
auto Op0 = N->getOperand(0);
351
auto Op1 = N->getOperand(1);
352
auto Op2 = N->getOperand(2);
353
354
SDLoc Dl(N);
355
356
if (isNullConstant(Op2)) {
357
auto *CA = CurDAG->getMachineNode(
358
Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);
359
NewNode = CurDAG->getMachineNode(
360
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
361
{Op0, Op1, SDValue(CA, 0)});
362
} else if (isOneConstant(Op2)) {
363
auto *CA = CurDAG->getMachineNode(
364
Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);
365
NewNode = CurDAG->getMachineNode(
366
Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},
367
{Op0, Op1, SDValue(CA, 0)});
368
} else {
369
auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);
370
NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
371
: CSKY::SUBC16,
372
Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
373
}
374
auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));
375
376
ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));
377
ReplaceUses(SDValue(N, 1), CarryOut);
378
CurDAG->RemoveDeadNode(N);
379
380
return true;
381
}
382
383
SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
384
SDLoc dl(V0.getNode());
385
SDValue RegClass =
386
CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32);
387
SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32);
388
SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32);
389
const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};
390
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
391
}
392
393
bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
394
const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID,
395
std::vector<SDValue> &OutOps) {
396
switch (ConstraintID) {
397
case InlineAsm::ConstraintCode::m:
398
// We just support simple memory operands that have a single address
399
// operand and need no special handling.
400
OutOps.push_back(Op);
401
return false;
402
default:
403
break;
404
}
405
406
return true;
407
}
408
409
FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM,
410
CodeGenOptLevel OptLevel) {
411
return new CSKYDAGToDAGISelLegacy(TM, OptLevel);
412
}
413
414