23#define DEBUG_TYPE "csky-isel"
24#define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"
44 bool selectBITCAST_TO_LOHI(
SDNode *
N);
45 bool selectInlineAsm(
SDNode *
N);
51 std::vector<SDValue> &OutOps)
override;
53#include "CSKYGenDAGISel.inc"
62 ID, std::make_unique<CSKYDAGToDAGISel>(TM, OptLevel)) {}
66char CSKYDAGToDAGISelLegacy::ID = 0;
72 if (
N->isMachineOpcode()) {
79 unsigned Opcode =
N->getOpcode();
80 bool IsSelected =
false;
86 IsSelected = selectAddCarry(
N);
89 IsSelected = selectSubCarry(
N);
92 Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
93 ReplaceNode(
N, CurDAG->getRegister(GP,
N->getValueType(0)).getNode());
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
104 Dl, MVT::i32, TFI, Imm));
110 IsSelected = selectBITCAST_TO_LOHI(
N);
114 IsSelected = selectInlineAsm(
N);
125bool CSKYDAGToDAGISel::selectInlineAsm(
SDNode *
N) {
126 std::vector<SDValue> AsmNodeOperands;
128 bool Changed =
false;
129 unsigned NumOps =
N->getNumOperands();
138 N->getGluedNode() ?
N->getOperand(NumOps - 1) :
SDValue(
nullptr, 0);
142 for (
unsigned i = 0, e =
N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
145 AsmNodeOperands.push_back(
op);
150 if (
const auto *
C = dyn_cast<ConstantSDNode>(
N->getOperand(i)))
159 if (
Flag.isImmKind()) {
161 AsmNodeOperands.push_back(
op);
165 const unsigned NumRegs =
Flag.getNumOperandRegisters();
170 bool IsTiedToChangedOp =
false;
173 if (Changed &&
Flag.isUseOperandTiedToDef(DefIdx))
174 IsTiedToChangedOp = OpChanged[DefIdx];
181 if (
Flag.isMemKind()) {
183 AsmNodeOperands.push_back(
op);
187 if (!
Flag.isRegUseKind() && !
Flag.isRegDefKind() &&
188 !
Flag.isRegDefEarlyClobberKind())
192 const bool HasRC =
Flag.hasRegClassConstraint(RC);
193 if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||
197 assert((i + 2 < NumOps) &&
"Invalid number of operands in inline asm");
200 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
201 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
205 if (
Flag.isRegDefKind() ||
Flag.isRegDefEarlyClobberKind()) {
209 Register GPVR =
MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
210 PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
213 SDNode *GU =
N->getGluedUser();
215 CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.
getValue(1));
219 CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);
221 CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);
223 CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.
getValue(1));
228 Ops.push_back(
T1.getValue(1));
229 CurDAG->UpdateNodeOperands(GU, Ops);
237 CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.
getValue(1));
239 CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.
getValue(1));
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));
255 OpChanged[OpChanged.
size() - 1] =
true;
258 if (IsTiedToChangedOp)
259 Flag.setMatchingOp(DefIdx);
261 Flag.setRegClass(CSKY::GPRPairRegClassID);
263 AsmNodeOperands[AsmNodeOperands.size() - 1] =
264 CurDAG->getTargetConstant(Flag, dl, MVT::i32);
266 AsmNodeOperands.push_back(PairedReg);
273 AsmNodeOperands.push_back(Glue);
278 CurDAG->getVTList(MVT::Other, MVT::Glue),
281 ReplaceNode(
N,
New.getNode());
285bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(
SDNode *
N) {
287 auto VT =
N->getValueType(0);
288 auto V =
N->getOperand(0);
290 if (!Subtarget->hasFPUv2DoubleFloat())
293 SDValue V1 =
SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0);
298 CurDAG->RemoveDeadNode(
N);
303bool CSKYDAGToDAGISel::selectAddCarry(
SDNode *
N) {
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);
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)});
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)});
326 NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32
328 Dl, {Type0, Type1}, {Op0, Op1, Op2});
330 ReplaceNode(
N, NewNode);
346bool CSKYDAGToDAGISel::selectSubCarry(
SDNode *
N) {
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);
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)});
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)});
370 NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
372 Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
377 ReplaceUses(
SDValue(
N, 1), CarryOut);
378 CurDAG->RemoveDeadNode(
N);
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);
393bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
395 std::vector<SDValue> &OutOps) {
396 switch (ConstraintID) {
397 case InlineAsm::ConstraintCode::m:
400 OutOps.push_back(
Op);
411 return new CSKYDAGToDAGISelLegacy(TM, OptLevel);
unsigned const MachineRegisterInfo * MRI
static SDValue createGPRPairNode(SelectionDAG &DAG, SDValue V)
amdgpu AMDGPU Register Bank Select
static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This class represents an Operation in the Expression.
FunctionPass class - This class is used to implement most global optimizations.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
An SDNode that represents everything that will be needed to construct a MachineInstr.
Wrapper class representing virtual and physical registers.
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
op_iterator op_end() const
op_iterator op_begin() const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, std::vector< SDValue > &OutOps)
SelectInlineAsmMemoryOperand - Select the specified address as a target addressing mode,...
virtual bool runOnMachineFunction(MachineFunction &mf)
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ GLOBAL_OFFSET_TABLE
The address of the GOT.
@ UADDO_CARRY
Carry-using nodes for multiple precision addition and subtraction.
@ INLINEASM_BR
INLINEASM_BR - Branching version of inline asm. Used by asm-goto.
@ INLINEASM
INLINEASM - Represents an inline asm block.
Flag
These should be considered private to the implementation of the MCInstrDesc class.
This is an optimization pass for GlobalISel generic memory operations.
bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
CodeGenOptLevel
Code generation optimization level.
bool isOneConstant(SDValue V)
Returns true if V is a constant integer one.
FunctionPass * createCSKYISelDag(CSKYTargetMachine &TM, CodeGenOptLevel OptLevel)