23#define DEBUG_TYPE "csky-isel"
24#define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"
46 bool selectBITCAST_TO_LOHI(
SDNode *
N);
47 bool selectInlineAsm(
SDNode *
N);
53 std::vector<SDValue> &OutOps)
override;
55#include "CSKYGenDAGISel.inc"
59char CSKYDAGToDAGISel::ID = 0;
65 if (
N->isMachineOpcode()) {
72 unsigned Opcode =
N->getOpcode();
73 bool IsSelected =
false;
79 IsSelected = selectAddCarry(
N);
82 IsSelected = selectSubCarry(
N);
85 Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);
86 ReplaceNode(
N, CurDAG->getRegister(GP,
N->getValueType(0)).getNode());
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));
103 IsSelected = selectBITCAST_TO_LOHI(
N);
107 IsSelected = selectInlineAsm(
N);
118bool CSKYDAGToDAGISel::selectInlineAsm(
SDNode *
N) {
119 std::vector<SDValue> AsmNodeOperands;
121 bool Changed =
false;
122 unsigned NumOps =
N->getNumOperands();
131 N->getGluedNode() ?
N->getOperand(NumOps - 1) :
SDValue(
nullptr, 0);
135 for (
unsigned i = 0, e =
N->getGluedNode() ? NumOps - 1 : NumOps; i < e;
138 AsmNodeOperands.push_back(
op);
143 if (
const auto *
C = dyn_cast<ConstantSDNode>(
N->getOperand(i)))
152 if (
Flag.isImmKind()) {
154 AsmNodeOperands.push_back(
op);
158 const unsigned NumRegs =
Flag.getNumOperandRegisters();
163 bool IsTiedToChangedOp =
false;
166 if (Changed &&
Flag.isUseOperandTiedToDef(DefIdx))
167 IsTiedToChangedOp = OpChanged[DefIdx];
174 if (
Flag.isMemKind()) {
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");
193 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
194 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
198 if (
Flag.isRegDefKind() ||
Flag.isRegDefEarlyClobberKind()) {
202 Register GPVR =
MRI.createVirtualRegister(&CSKY::GPRPairRegClass);
203 PairedReg = CurDAG->getRegister(GPVR, MVT::i64);
206 SDNode *GU =
N->getGluedUser();
208 CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.
getValue(1));
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));
221 Ops.push_back(
T1.getValue(1));
222 CurDAG->UpdateNodeOperands(GU, Ops);
230 CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.
getValue(1));
232 CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.
getValue(1));
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));
248 OpChanged[OpChanged.
size() - 1] =
true;
251 if (IsTiedToChangedOp)
252 Flag.setMatchingOp(DefIdx);
254 Flag.setRegClass(CSKY::GPRPairRegClassID);
256 AsmNodeOperands[AsmNodeOperands.size() - 1] =
257 CurDAG->getTargetConstant(Flag, dl, MVT::i32);
259 AsmNodeOperands.push_back(PairedReg);
266 AsmNodeOperands.push_back(Glue);
271 CurDAG->getVTList(MVT::Other, MVT::Glue),
274 ReplaceNode(
N,
New.getNode());
278bool 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);
291 CurDAG->RemoveDeadNode(
N);
296bool CSKYDAGToDAGISel::selectAddCarry(
SDNode *
N) {
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);
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)});
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);
339bool CSKYDAGToDAGISel::selectSubCarry(
SDNode *
N) {
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);
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)});
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)});
363 NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32
365 Dl, {Type0, Type1}, {Op0, Op1, CarryIn});
370 ReplaceUses(
SDValue(
N, 1), CarryOut);
371 CurDAG->RemoveDeadNode(
N);
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);
386bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(
388 std::vector<SDValue> &OutOps) {
389 switch (ConstraintID) {
390 case InlineAsm::ConstraintCode::m:
393 OutOps.push_back(
Op);
404 return new CSKYDAGToDAGISel(
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)
const char LLVMTargetMachineRef TM
#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,...
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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)