1 //===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines an instruction selector for the CSKY target.
11 //===----------------------------------------------------------------------===//
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"
23 #define DEBUG_TYPE "csky-isel"
24 #define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"
27 class CSKYDAGToDAGISel
: public SelectionDAGISel
{
28 const CSKYSubtarget
*Subtarget
;
33 explicit CSKYDAGToDAGISel(CSKYTargetMachine
&TM
, CodeGenOptLevel OptLevel
)
34 : SelectionDAGISel(ID
, TM
, OptLevel
) {}
36 bool runOnMachineFunction(MachineFunction
&MF
) override
{
37 // Reset the subtarget each time through.
38 Subtarget
= &MF
.getSubtarget
<CSKYSubtarget
>();
39 SelectionDAGISel::runOnMachineFunction(MF
);
43 void Select(SDNode
*N
) override
;
44 bool selectAddCarry(SDNode
*N
);
45 bool selectSubCarry(SDNode
*N
);
46 bool selectBITCAST_TO_LOHI(SDNode
*N
);
47 bool selectInlineAsm(SDNode
*N
);
49 SDNode
*createGPRPairNode(EVT VT
, SDValue V0
, SDValue V1
);
51 bool SelectInlineAsmMemoryOperand(const SDValue
&Op
,
52 InlineAsm::ConstraintCode ConstraintID
,
53 std::vector
<SDValue
> &OutOps
) override
;
55 #include "CSKYGenDAGISel.inc"
59 char CSKYDAGToDAGISel::ID
= 0;
61 INITIALIZE_PASS(CSKYDAGToDAGISel
, DEBUG_TYPE
, PASS_NAME
, false, false)
63 void CSKYDAGToDAGISel::Select(SDNode
*N
) {
64 // If we have a custom node, we have already selected
65 if (N
->isMachineOpcode()) {
66 LLVM_DEBUG(dbgs() << "== "; N
->dump(CurDAG
); dbgs() << "\n");
72 unsigned Opcode
= N
->getOpcode();
73 bool IsSelected
= false;
78 case ISD::UADDO_CARRY
:
79 IsSelected
= selectAddCarry(N
);
81 case ISD::USUBO_CARRY
:
82 IsSelected
= selectSubCarry(N
);
84 case ISD::GLOBAL_OFFSET_TABLE
: {
85 Register GP
= Subtarget
->getInstrInfo()->getGlobalBaseReg(*MF
);
86 ReplaceNode(N
, CurDAG
->getRegister(GP
, N
->getValueType(0)).getNode());
91 case ISD::FrameIndex
: {
92 SDValue Imm
= CurDAG
->getTargetConstant(0, Dl
, MVT::i32
);
93 int FI
= cast
<FrameIndexSDNode
>(N
)->getIndex();
94 SDValue TFI
= CurDAG
->getTargetFrameIndex(FI
, MVT::i32
);
95 ReplaceNode(N
, CurDAG
->getMachineNode(Subtarget
->hasE2() ? CSKY::ADDI32
97 Dl
, MVT::i32
, TFI
, Imm
));
102 case CSKYISD::BITCAST_TO_LOHI
:
103 IsSelected
= selectBITCAST_TO_LOHI(N
);
106 case ISD::INLINEASM_BR
:
107 IsSelected
= selectInlineAsm(N
);
114 // Select the default instruction.
118 bool CSKYDAGToDAGISel::selectInlineAsm(SDNode
*N
) {
119 std::vector
<SDValue
> AsmNodeOperands
;
120 InlineAsm::Flag Flag
;
121 bool Changed
= false;
122 unsigned NumOps
= N
->getNumOperands();
124 // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
125 // However, some instructions (e.g. mula.s32) require GPR pair.
126 // Since there is no constraint to explicitly specify a
127 // reg pair, we use GPRPair reg class for "%r" for 64-bit data.
131 N
->getGluedNode() ? N
->getOperand(NumOps
- 1) : SDValue(nullptr, 0);
133 SmallVector
<bool, 8> OpChanged
;
134 // Glue node will be appended late.
135 for (unsigned i
= 0, e
= N
->getGluedNode() ? NumOps
- 1 : NumOps
; i
< e
;
137 SDValue op
= N
->getOperand(i
);
138 AsmNodeOperands
.push_back(op
);
140 if (i
< InlineAsm::Op_FirstOperand
)
143 if (const auto *C
= dyn_cast
<ConstantSDNode
>(N
->getOperand(i
)))
144 Flag
= InlineAsm::Flag(C
->getZExtValue());
148 // Immediate operands to inline asm in the SelectionDAG are modeled with
149 // two operands. The first is a constant of value InlineAsm::Kind::Imm, and
150 // the second is a constant with the value of the immediate. If we get here
151 // and we have a Kind::Imm, skip the next operand, and continue.
152 if (Flag
.isImmKind()) {
153 SDValue op
= N
->getOperand(++i
);
154 AsmNodeOperands
.push_back(op
);
158 const unsigned NumRegs
= Flag
.getNumOperandRegisters();
160 OpChanged
.push_back(false);
163 bool IsTiedToChangedOp
= false;
164 // If it's a use that is tied with a previous def, it has no
165 // reg class constraint.
166 if (Changed
&& Flag
.isUseOperandTiedToDef(DefIdx
))
167 IsTiedToChangedOp
= OpChanged
[DefIdx
];
169 // Memory operands to inline asm in the SelectionDAG are modeled with two
170 // operands: a constant of value InlineAsm::Kind::Mem followed by the input
171 // operand. If we get here and we have a Kind::Mem, skip the next operand
172 // (so it doesn't get misinterpreted), and continue. We do this here because
173 // it's important to update the OpChanged array correctly before moving on.
174 if (Flag
.isMemKind()) {
175 SDValue op
= N
->getOperand(++i
);
176 AsmNodeOperands
.push_back(op
);
180 if (!Flag
.isRegUseKind() && !Flag
.isRegDefKind() &&
181 !Flag
.isRegDefEarlyClobberKind())
185 const bool HasRC
= Flag
.hasRegClassConstraint(RC
);
186 if ((!IsTiedToChangedOp
&& (!HasRC
|| RC
!= CSKY::GPRRegClassID
)) ||
190 assert((i
+ 2 < NumOps
) && "Invalid number of operands in inline asm");
191 SDValue V0
= N
->getOperand(i
+ 1);
192 SDValue V1
= N
->getOperand(i
+ 2);
193 unsigned Reg0
= cast
<RegisterSDNode
>(V0
)->getReg();
194 unsigned Reg1
= cast
<RegisterSDNode
>(V1
)->getReg();
196 MachineRegisterInfo
&MRI
= MF
->getRegInfo();
198 if (Flag
.isRegDefKind() || Flag
.isRegDefEarlyClobberKind()) {
199 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
200 // the original GPRs.
202 Register GPVR
= MRI
.createVirtualRegister(&CSKY::GPRPairRegClass
);
203 PairedReg
= CurDAG
->getRegister(GPVR
, MVT::i64
);
204 SDValue Chain
= SDValue(N
, 0);
206 SDNode
*GU
= N
->getGluedUser();
208 CurDAG
->getCopyFromReg(Chain
, dl
, GPVR
, MVT::i64
, Chain
.getValue(1));
210 // Extract values from a GPRPair reg and copy to the original GPR reg.
212 CurDAG
->getTargetExtractSubreg(CSKY::sub32_0
, dl
, MVT::i32
, RegCopy
);
214 CurDAG
->getTargetExtractSubreg(CSKY::sub32_32
, dl
, MVT::i32
, RegCopy
);
216 CurDAG
->getCopyToReg(Sub0
, dl
, Reg0
, Sub0
, RegCopy
.getValue(1));
217 SDValue T1
= CurDAG
->getCopyToReg(Sub1
, dl
, Reg1
, Sub1
, T0
.getValue(1));
219 // Update the original glue user.
220 std::vector
<SDValue
> Ops(GU
->op_begin(), GU
->op_end() - 1);
221 Ops
.push_back(T1
.getValue(1));
222 CurDAG
->UpdateNodeOperands(GU
, Ops
);
224 // For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a
225 // GPRPair and then pass the GPRPair to the inline asm.
226 SDValue Chain
= AsmNodeOperands
[InlineAsm::Op_InputChain
];
228 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
230 CurDAG
->getCopyFromReg(Chain
, dl
, Reg0
, MVT::i32
, Chain
.getValue(1));
232 CurDAG
->getCopyFromReg(Chain
, dl
, Reg1
, MVT::i32
, T0
.getValue(1));
233 SDValue Pair
= SDValue(createGPRPairNode(MVT::i64
, T0
, T1
), 0);
235 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
236 // i32 VRs of inline asm with it.
237 Register GPVR
= MRI
.createVirtualRegister(&CSKY::GPRPairRegClass
);
238 PairedReg
= CurDAG
->getRegister(GPVR
, MVT::i64
);
239 Chain
= CurDAG
->getCopyToReg(T1
, dl
, GPVR
, Pair
, T1
.getValue(1));
241 AsmNodeOperands
[InlineAsm::Op_InputChain
] = Chain
;
242 Glue
= Chain
.getValue(1);
247 if (PairedReg
.getNode()) {
248 OpChanged
[OpChanged
.size() - 1] = true;
249 // TODO: maybe a setter for getNumOperandRegisters?
250 Flag
= InlineAsm::Flag(Flag
.getKind(), 1 /* RegNum*/);
251 if (IsTiedToChangedOp
)
252 Flag
.setMatchingOp(DefIdx
);
254 Flag
.setRegClass(CSKY::GPRPairRegClassID
);
255 // Replace the current flag.
256 AsmNodeOperands
[AsmNodeOperands
.size() - 1] =
257 CurDAG
->getTargetConstant(Flag
, dl
, MVT::i32
);
258 // Add the new register node and skip the original two GPRs.
259 AsmNodeOperands
.push_back(PairedReg
);
260 // Skip the next two GPRs.
266 AsmNodeOperands
.push_back(Glue
);
270 SDValue New
= CurDAG
->getNode(N
->getOpcode(), SDLoc(N
),
271 CurDAG
->getVTList(MVT::Other
, MVT::Glue
),
274 ReplaceNode(N
, New
.getNode());
278 bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode
*N
) {
280 auto VT
= N
->getValueType(0);
281 auto V
= N
->getOperand(0);
283 if (!Subtarget
->hasFPUv2DoubleFloat())
286 SDValue V1
= SDValue(CurDAG
->getMachineNode(CSKY::FMFVRL_D
, Dl
, VT
, V
), 0);
287 SDValue V2
= SDValue(CurDAG
->getMachineNode(CSKY::FMFVRH_D
, Dl
, VT
, V
), 0);
289 ReplaceUses(SDValue(N
, 0), V1
);
290 ReplaceUses(SDValue(N
, 1), V2
);
291 CurDAG
->RemoveDeadNode(N
);
296 bool CSKYDAGToDAGISel::selectAddCarry(SDNode
*N
) {
297 MachineSDNode
*NewNode
= nullptr;
298 auto Type0
= N
->getValueType(0);
299 auto Type1
= N
->getValueType(1);
300 auto Op0
= N
->getOperand(0);
301 auto Op1
= N
->getOperand(1);
302 auto Op2
= N
->getOperand(2);
306 if (isNullConstant(Op2
)) {
307 auto *CA
= CurDAG
->getMachineNode(
308 Subtarget
->has2E3() ? CSKY::CLRC32
: CSKY::CLRC16
, Dl
, Type1
);
309 NewNode
= CurDAG
->getMachineNode(
310 Subtarget
->has2E3() ? CSKY::ADDC32
: CSKY::ADDC16
, Dl
, {Type0
, Type1
},
311 {Op0
, Op1
, SDValue(CA
, 0)});
312 } else if (isOneConstant(Op2
)) {
313 auto *CA
= CurDAG
->getMachineNode(
314 Subtarget
->has2E3() ? CSKY::SETC32
: CSKY::SETC16
, Dl
, Type1
);
315 NewNode
= CurDAG
->getMachineNode(
316 Subtarget
->has2E3() ? CSKY::ADDC32
: CSKY::ADDC16
, Dl
, {Type0
, Type1
},
317 {Op0
, Op1
, SDValue(CA
, 0)});
319 NewNode
= CurDAG
->getMachineNode(Subtarget
->has2E3() ? CSKY::ADDC32
321 Dl
, {Type0
, Type1
}, {Op0
, Op1
, Op2
});
323 ReplaceNode(N
, NewNode
);
327 static SDValue
InvertCarryFlag(const CSKYSubtarget
*Subtarget
,
328 SelectionDAG
*DAG
, SDLoc Dl
, SDValue OldCarry
) {
330 DAG
->getMachineNode(Subtarget
->has2E3() ? CSKY::MVCV32
: CSKY::MVCV16
, Dl
,
333 DAG
->getMachineNode(Subtarget
->hasE2() ? CSKY::BTSTI32
: CSKY::BTSTI16
,
334 Dl
, OldCarry
.getValueType(), SDValue(NewCarryReg
, 0),
335 DAG
->getTargetConstant(0, Dl
, MVT::i32
));
336 return SDValue(NewCarry
, 0);
339 bool CSKYDAGToDAGISel::selectSubCarry(SDNode
*N
) {
340 MachineSDNode
*NewNode
= nullptr;
341 auto Type0
= N
->getValueType(0);
342 auto Type1
= N
->getValueType(1);
343 auto Op0
= N
->getOperand(0);
344 auto Op1
= N
->getOperand(1);
345 auto Op2
= N
->getOperand(2);
349 if (isNullConstant(Op2
)) {
350 auto *CA
= CurDAG
->getMachineNode(
351 Subtarget
->has2E3() ? CSKY::SETC32
: CSKY::SETC16
, Dl
, Type1
);
352 NewNode
= CurDAG
->getMachineNode(
353 Subtarget
->has2E3() ? CSKY::SUBC32
: CSKY::SUBC16
, Dl
, {Type0
, Type1
},
354 {Op0
, Op1
, SDValue(CA
, 0)});
355 } else if (isOneConstant(Op2
)) {
356 auto *CA
= CurDAG
->getMachineNode(
357 Subtarget
->has2E3() ? CSKY::CLRC32
: CSKY::CLRC16
, Dl
, Type1
);
358 NewNode
= CurDAG
->getMachineNode(
359 Subtarget
->has2E3() ? CSKY::SUBC32
: CSKY::SUBC16
, Dl
, {Type0
, Type1
},
360 {Op0
, Op1
, SDValue(CA
, 0)});
362 auto CarryIn
= InvertCarryFlag(Subtarget
, CurDAG
, Dl
, Op2
);
363 NewNode
= CurDAG
->getMachineNode(Subtarget
->has2E3() ? CSKY::SUBC32
365 Dl
, {Type0
, Type1
}, {Op0
, Op1
, CarryIn
});
367 auto CarryOut
= InvertCarryFlag(Subtarget
, CurDAG
, Dl
, SDValue(NewNode
, 1));
369 ReplaceUses(SDValue(N
, 0), SDValue(NewNode
, 0));
370 ReplaceUses(SDValue(N
, 1), CarryOut
);
371 CurDAG
->RemoveDeadNode(N
);
376 SDNode
*CSKYDAGToDAGISel::createGPRPairNode(EVT VT
, SDValue V0
, SDValue V1
) {
377 SDLoc
dl(V0
.getNode());
379 CurDAG
->getTargetConstant(CSKY::GPRPairRegClassID
, dl
, MVT::i32
);
380 SDValue SubReg0
= CurDAG
->getTargetConstant(CSKY::sub32_0
, dl
, MVT::i32
);
381 SDValue SubReg1
= CurDAG
->getTargetConstant(CSKY::sub32_32
, dl
, MVT::i32
);
382 const SDValue Ops
[] = {RegClass
, V0
, SubReg0
, V1
, SubReg1
};
383 return CurDAG
->getMachineNode(TargetOpcode::REG_SEQUENCE
, dl
, VT
, Ops
);
386 bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
387 const SDValue
&Op
, const InlineAsm::ConstraintCode ConstraintID
,
388 std::vector
<SDValue
> &OutOps
) {
389 switch (ConstraintID
) {
390 case InlineAsm::ConstraintCode::m
:
391 // We just support simple memory operands that have a single address
392 // operand and need no special handling.
393 OutOps
.push_back(Op
);
402 FunctionPass
*llvm::createCSKYISelDag(CSKYTargetMachine
&TM
,
403 CodeGenOptLevel OptLevel
) {
404 return new CSKYDAGToDAGISel(TM
, OptLevel
);