1349cc55cSDimitry Andric //===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric // 9349cc55cSDimitry Andric // This file defines an instruction selector for the CSKY target. 10349cc55cSDimitry Andric // 11349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 12349cc55cSDimitry Andric 13349cc55cSDimitry Andric #include "CSKY.h" 14349cc55cSDimitry Andric #include "CSKYSubtarget.h" 15349cc55cSDimitry Andric #include "CSKYTargetMachine.h" 16349cc55cSDimitry Andric #include "MCTargetDesc/CSKYMCTargetDesc.h" 17*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 18349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 19349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 20349cc55cSDimitry Andric 21349cc55cSDimitry Andric using namespace llvm; 22349cc55cSDimitry Andric 23349cc55cSDimitry Andric #define DEBUG_TYPE "csky-isel" 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric namespace { 26349cc55cSDimitry Andric class CSKYDAGToDAGISel : public SelectionDAGISel { 27349cc55cSDimitry Andric const CSKYSubtarget *Subtarget; 28349cc55cSDimitry Andric 29349cc55cSDimitry Andric public: 30349cc55cSDimitry Andric explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {} 31349cc55cSDimitry Andric 32349cc55cSDimitry Andric StringRef getPassName() const override { 33349cc55cSDimitry Andric return "CSKY DAG->DAG Pattern Instruction Selection"; 34349cc55cSDimitry Andric } 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 37349cc55cSDimitry Andric // Reset the subtarget each time through. 38349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<CSKYSubtarget>(); 39349cc55cSDimitry Andric SelectionDAGISel::runOnMachineFunction(MF); 40349cc55cSDimitry Andric return true; 41349cc55cSDimitry Andric } 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric void Select(SDNode *N) override; 440eae32dcSDimitry Andric bool selectAddCarry(SDNode *N); 450eae32dcSDimitry Andric bool selectSubCarry(SDNode *N); 46*81ad6265SDimitry Andric bool selectBITCAST_TO_LOHI(SDNode *N); 47*81ad6265SDimitry Andric bool selectInlineAsm(SDNode *N); 48*81ad6265SDimitry Andric 49*81ad6265SDimitry Andric SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1); 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 52*81ad6265SDimitry Andric std::vector<SDValue> &OutOps) override; 53349cc55cSDimitry Andric 54349cc55cSDimitry Andric #include "CSKYGenDAGISel.inc" 55349cc55cSDimitry Andric }; 56349cc55cSDimitry Andric } // namespace 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric void CSKYDAGToDAGISel::Select(SDNode *N) { 59349cc55cSDimitry Andric // If we have a custom node, we have already selected 60349cc55cSDimitry Andric if (N->isMachineOpcode()) { 61349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n"); 62349cc55cSDimitry Andric N->setNodeId(-1); 63349cc55cSDimitry Andric return; 64349cc55cSDimitry Andric } 65349cc55cSDimitry Andric 66349cc55cSDimitry Andric SDLoc Dl(N); 67349cc55cSDimitry Andric unsigned Opcode = N->getOpcode(); 68349cc55cSDimitry Andric bool IsSelected = false; 69349cc55cSDimitry Andric 70349cc55cSDimitry Andric switch (Opcode) { 71349cc55cSDimitry Andric default: 72349cc55cSDimitry Andric break; 730eae32dcSDimitry Andric case ISD::ADDCARRY: 740eae32dcSDimitry Andric IsSelected = selectAddCarry(N); 750eae32dcSDimitry Andric break; 760eae32dcSDimitry Andric case ISD::SUBCARRY: 770eae32dcSDimitry Andric IsSelected = selectSubCarry(N); 780eae32dcSDimitry Andric break; 7904eeddc0SDimitry Andric case ISD::GLOBAL_OFFSET_TABLE: { 8004eeddc0SDimitry Andric Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF); 8104eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode()); 8204eeddc0SDimitry Andric 8304eeddc0SDimitry Andric IsSelected = true; 8404eeddc0SDimitry Andric break; 8504eeddc0SDimitry Andric } 8604eeddc0SDimitry Andric case ISD::FrameIndex: { 8704eeddc0SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32); 8804eeddc0SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 8904eeddc0SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); 9004eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32 9104eeddc0SDimitry Andric : CSKY::ADDI16XZ, 9204eeddc0SDimitry Andric Dl, MVT::i32, TFI, Imm)); 9304eeddc0SDimitry Andric 9404eeddc0SDimitry Andric IsSelected = true; 9504eeddc0SDimitry Andric break; 9604eeddc0SDimitry Andric } 97*81ad6265SDimitry Andric case CSKYISD::BITCAST_TO_LOHI: 98*81ad6265SDimitry Andric IsSelected = selectBITCAST_TO_LOHI(N); 99*81ad6265SDimitry Andric break; 100*81ad6265SDimitry Andric case ISD::INLINEASM: 101*81ad6265SDimitry Andric case ISD::INLINEASM_BR: 102*81ad6265SDimitry Andric IsSelected = selectInlineAsm(N); 103*81ad6265SDimitry Andric break; 104349cc55cSDimitry Andric } 105349cc55cSDimitry Andric 106349cc55cSDimitry Andric if (IsSelected) 107349cc55cSDimitry Andric return; 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric // Select the default instruction. 110349cc55cSDimitry Andric SelectCode(N); 111349cc55cSDimitry Andric } 112349cc55cSDimitry Andric 113*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) { 114*81ad6265SDimitry Andric std::vector<SDValue> AsmNodeOperands; 115*81ad6265SDimitry Andric unsigned Flag, Kind; 116*81ad6265SDimitry Andric bool Changed = false; 117*81ad6265SDimitry Andric unsigned NumOps = N->getNumOperands(); 118*81ad6265SDimitry Andric 119*81ad6265SDimitry Andric // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint. 120*81ad6265SDimitry Andric // However, some instructions (e.g. mula.s32) require GPR pair. 121*81ad6265SDimitry Andric // Since there is no constraint to explicitly specify a 122*81ad6265SDimitry Andric // reg pair, we use GPRPair reg class for "%r" for 64-bit data. 123*81ad6265SDimitry Andric 124*81ad6265SDimitry Andric SDLoc dl(N); 125*81ad6265SDimitry Andric SDValue Glue = 126*81ad6265SDimitry Andric N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0); 127*81ad6265SDimitry Andric 128*81ad6265SDimitry Andric SmallVector<bool, 8> OpChanged; 129*81ad6265SDimitry Andric // Glue node will be appended late. 130*81ad6265SDimitry Andric for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; 131*81ad6265SDimitry Andric ++i) { 132*81ad6265SDimitry Andric SDValue op = N->getOperand(i); 133*81ad6265SDimitry Andric AsmNodeOperands.push_back(op); 134*81ad6265SDimitry Andric 135*81ad6265SDimitry Andric if (i < InlineAsm::Op_FirstOperand) 136*81ad6265SDimitry Andric continue; 137*81ad6265SDimitry Andric 138*81ad6265SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) { 139*81ad6265SDimitry Andric Flag = C->getZExtValue(); 140*81ad6265SDimitry Andric Kind = InlineAsm::getKind(Flag); 141*81ad6265SDimitry Andric } else 142*81ad6265SDimitry Andric continue; 143*81ad6265SDimitry Andric 144*81ad6265SDimitry Andric // Immediate operands to inline asm in the SelectionDAG are modeled with 145*81ad6265SDimitry Andric // two operands. The first is a constant of value InlineAsm::Kind_Imm, and 146*81ad6265SDimitry Andric // the second is a constant with the value of the immediate. If we get here 147*81ad6265SDimitry Andric // and we have a Kind_Imm, skip the next operand, and continue. 148*81ad6265SDimitry Andric if (Kind == InlineAsm::Kind_Imm) { 149*81ad6265SDimitry Andric SDValue op = N->getOperand(++i); 150*81ad6265SDimitry Andric AsmNodeOperands.push_back(op); 151*81ad6265SDimitry Andric continue; 152*81ad6265SDimitry Andric } 153*81ad6265SDimitry Andric 154*81ad6265SDimitry Andric unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag); 155*81ad6265SDimitry Andric if (NumRegs) 156*81ad6265SDimitry Andric OpChanged.push_back(false); 157*81ad6265SDimitry Andric 158*81ad6265SDimitry Andric unsigned DefIdx = 0; 159*81ad6265SDimitry Andric bool IsTiedToChangedOp = false; 160*81ad6265SDimitry Andric // If it's a use that is tied with a previous def, it has no 161*81ad6265SDimitry Andric // reg class constraint. 162*81ad6265SDimitry Andric if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx)) 163*81ad6265SDimitry Andric IsTiedToChangedOp = OpChanged[DefIdx]; 164*81ad6265SDimitry Andric 165*81ad6265SDimitry Andric // Memory operands to inline asm in the SelectionDAG are modeled with two 166*81ad6265SDimitry Andric // operands: a constant of value InlineAsm::Kind_Mem followed by the input 167*81ad6265SDimitry Andric // operand. If we get here and we have a Kind_Mem, skip the next operand (so 168*81ad6265SDimitry Andric // it doesn't get misinterpreted), and continue. We do this here because 169*81ad6265SDimitry Andric // it's important to update the OpChanged array correctly before moving on. 170*81ad6265SDimitry Andric if (Kind == InlineAsm::Kind_Mem) { 171*81ad6265SDimitry Andric SDValue op = N->getOperand(++i); 172*81ad6265SDimitry Andric AsmNodeOperands.push_back(op); 173*81ad6265SDimitry Andric continue; 174*81ad6265SDimitry Andric } 175*81ad6265SDimitry Andric 176*81ad6265SDimitry Andric if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef && 177*81ad6265SDimitry Andric Kind != InlineAsm::Kind_RegDefEarlyClobber) 178*81ad6265SDimitry Andric continue; 179*81ad6265SDimitry Andric 180*81ad6265SDimitry Andric unsigned RC; 181*81ad6265SDimitry Andric bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC); 182*81ad6265SDimitry Andric if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) || 183*81ad6265SDimitry Andric NumRegs != 2) 184*81ad6265SDimitry Andric continue; 185*81ad6265SDimitry Andric 186*81ad6265SDimitry Andric assert((i + 2 < NumOps) && "Invalid number of operands in inline asm"); 187*81ad6265SDimitry Andric SDValue V0 = N->getOperand(i + 1); 188*81ad6265SDimitry Andric SDValue V1 = N->getOperand(i + 2); 189*81ad6265SDimitry Andric unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg(); 190*81ad6265SDimitry Andric unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg(); 191*81ad6265SDimitry Andric SDValue PairedReg; 192*81ad6265SDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 193*81ad6265SDimitry Andric 194*81ad6265SDimitry Andric if (Kind == InlineAsm::Kind_RegDef || 195*81ad6265SDimitry Andric Kind == InlineAsm::Kind_RegDefEarlyClobber) { 196*81ad6265SDimitry Andric // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to 197*81ad6265SDimitry Andric // the original GPRs. 198*81ad6265SDimitry Andric 199*81ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass); 200*81ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64); 201*81ad6265SDimitry Andric SDValue Chain = SDValue(N, 0); 202*81ad6265SDimitry Andric 203*81ad6265SDimitry Andric SDNode *GU = N->getGluedUser(); 204*81ad6265SDimitry Andric SDValue RegCopy = 205*81ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1)); 206*81ad6265SDimitry Andric 207*81ad6265SDimitry Andric // Extract values from a GPRPair reg and copy to the original GPR reg. 208*81ad6265SDimitry Andric SDValue Sub0 = 209*81ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy); 210*81ad6265SDimitry Andric SDValue Sub1 = 211*81ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy); 212*81ad6265SDimitry Andric SDValue T0 = 213*81ad6265SDimitry Andric CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1)); 214*81ad6265SDimitry Andric SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1)); 215*81ad6265SDimitry Andric 216*81ad6265SDimitry Andric // Update the original glue user. 217*81ad6265SDimitry Andric std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1); 218*81ad6265SDimitry Andric Ops.push_back(T1.getValue(1)); 219*81ad6265SDimitry Andric CurDAG->UpdateNodeOperands(GU, Ops); 220*81ad6265SDimitry Andric } else { 221*81ad6265SDimitry Andric // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a 222*81ad6265SDimitry Andric // GPRPair and then pass the GPRPair to the inline asm. 223*81ad6265SDimitry Andric SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain]; 224*81ad6265SDimitry Andric 225*81ad6265SDimitry Andric // As REG_SEQ doesn't take RegisterSDNode, we copy them first. 226*81ad6265SDimitry Andric SDValue T0 = 227*81ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1)); 228*81ad6265SDimitry Andric SDValue T1 = 229*81ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1)); 230*81ad6265SDimitry Andric SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0); 231*81ad6265SDimitry Andric 232*81ad6265SDimitry Andric // Copy REG_SEQ into a GPRPair-typed VR and replace the original two 233*81ad6265SDimitry Andric // i32 VRs of inline asm with it. 234*81ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass); 235*81ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64); 236*81ad6265SDimitry Andric Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1)); 237*81ad6265SDimitry Andric 238*81ad6265SDimitry Andric AsmNodeOperands[InlineAsm::Op_InputChain] = Chain; 239*81ad6265SDimitry Andric Glue = Chain.getValue(1); 240*81ad6265SDimitry Andric } 241*81ad6265SDimitry Andric 242*81ad6265SDimitry Andric Changed = true; 243*81ad6265SDimitry Andric 244*81ad6265SDimitry Andric if (PairedReg.getNode()) { 245*81ad6265SDimitry Andric OpChanged[OpChanged.size() - 1] = true; 246*81ad6265SDimitry Andric Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/); 247*81ad6265SDimitry Andric if (IsTiedToChangedOp) 248*81ad6265SDimitry Andric Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx); 249*81ad6265SDimitry Andric else 250*81ad6265SDimitry Andric Flag = InlineAsm::getFlagWordForRegClass(Flag, CSKY::GPRPairRegClassID); 251*81ad6265SDimitry Andric // Replace the current flag. 252*81ad6265SDimitry Andric AsmNodeOperands[AsmNodeOperands.size() - 1] = 253*81ad6265SDimitry Andric CurDAG->getTargetConstant(Flag, dl, MVT::i32); 254*81ad6265SDimitry Andric // Add the new register node and skip the original two GPRs. 255*81ad6265SDimitry Andric AsmNodeOperands.push_back(PairedReg); 256*81ad6265SDimitry Andric // Skip the next two GPRs. 257*81ad6265SDimitry Andric i += 2; 258*81ad6265SDimitry Andric } 259*81ad6265SDimitry Andric } 260*81ad6265SDimitry Andric 261*81ad6265SDimitry Andric if (Glue.getNode()) 262*81ad6265SDimitry Andric AsmNodeOperands.push_back(Glue); 263*81ad6265SDimitry Andric if (!Changed) 264*81ad6265SDimitry Andric return false; 265*81ad6265SDimitry Andric 266*81ad6265SDimitry Andric SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N), 267*81ad6265SDimitry Andric CurDAG->getVTList(MVT::Other, MVT::Glue), 268*81ad6265SDimitry Andric AsmNodeOperands); 269*81ad6265SDimitry Andric New->setNodeId(-1); 270*81ad6265SDimitry Andric ReplaceNode(N, New.getNode()); 271*81ad6265SDimitry Andric return true; 272*81ad6265SDimitry Andric } 273*81ad6265SDimitry Andric 274*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) { 275*81ad6265SDimitry Andric SDLoc Dl(N); 276*81ad6265SDimitry Andric auto VT = N->getValueType(0); 277*81ad6265SDimitry Andric auto V = N->getOperand(0); 278*81ad6265SDimitry Andric 279*81ad6265SDimitry Andric if (!Subtarget->hasFPUv2DoubleFloat()) 280*81ad6265SDimitry Andric return false; 281*81ad6265SDimitry Andric 282*81ad6265SDimitry Andric SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0); 283*81ad6265SDimitry Andric SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0); 284*81ad6265SDimitry Andric 285*81ad6265SDimitry Andric ReplaceUses(SDValue(N, 0), V1); 286*81ad6265SDimitry Andric ReplaceUses(SDValue(N, 1), V2); 287*81ad6265SDimitry Andric CurDAG->RemoveDeadNode(N); 288*81ad6265SDimitry Andric 289*81ad6265SDimitry Andric return true; 290*81ad6265SDimitry Andric } 291*81ad6265SDimitry Andric 2920eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { 2930eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 2940eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 2950eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 2960eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 2970eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 2980eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 2990eae32dcSDimitry Andric 3000eae32dcSDimitry Andric SDLoc Dl(N); 3010eae32dcSDimitry Andric 3020eae32dcSDimitry Andric if (isNullConstant(Op2)) { 3030eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3040eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 3050eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3060eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 3070eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3080eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 3090eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3100eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 3110eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3120eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 3130eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3140eae32dcSDimitry Andric } else { 3150eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 3160eae32dcSDimitry Andric : CSKY::ADDC16, 3170eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, Op2}); 3180eae32dcSDimitry Andric } 3190eae32dcSDimitry Andric ReplaceNode(N, NewNode); 3200eae32dcSDimitry Andric return true; 3210eae32dcSDimitry Andric } 3220eae32dcSDimitry Andric 3230eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, 3240eae32dcSDimitry Andric SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { 3250eae32dcSDimitry Andric auto NewCarryReg = 3260eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, 3270eae32dcSDimitry Andric MVT::i32, OldCarry); 3280eae32dcSDimitry Andric auto NewCarry = 3290eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, 3300eae32dcSDimitry Andric Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), 3310eae32dcSDimitry Andric DAG->getTargetConstant(0, Dl, MVT::i32)); 3320eae32dcSDimitry Andric return SDValue(NewCarry, 0); 3330eae32dcSDimitry Andric } 3340eae32dcSDimitry Andric 3350eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { 3360eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 3370eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 3380eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 3390eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 3400eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 3410eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 3420eae32dcSDimitry Andric 3430eae32dcSDimitry Andric SDLoc Dl(N); 3440eae32dcSDimitry Andric 3450eae32dcSDimitry Andric if (isNullConstant(Op2)) { 3460eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3470eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 3480eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3490eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 3500eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3510eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 3520eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3530eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 3540eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3550eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 3560eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3570eae32dcSDimitry Andric } else { 3580eae32dcSDimitry Andric auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); 3590eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 3600eae32dcSDimitry Andric : CSKY::SUBC16, 3610eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); 3620eae32dcSDimitry Andric } 3630eae32dcSDimitry Andric auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); 3640eae32dcSDimitry Andric 3650eae32dcSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); 3660eae32dcSDimitry Andric ReplaceUses(SDValue(N, 1), CarryOut); 3670eae32dcSDimitry Andric CurDAG->RemoveDeadNode(N); 3680eae32dcSDimitry Andric 3690eae32dcSDimitry Andric return true; 3700eae32dcSDimitry Andric } 3710eae32dcSDimitry Andric 372*81ad6265SDimitry Andric SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) { 373*81ad6265SDimitry Andric SDLoc dl(V0.getNode()); 374*81ad6265SDimitry Andric SDValue RegClass = 375*81ad6265SDimitry Andric CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32); 376*81ad6265SDimitry Andric SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32); 377*81ad6265SDimitry Andric SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32); 378*81ad6265SDimitry Andric const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1}; 379*81ad6265SDimitry Andric return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops); 380*81ad6265SDimitry Andric } 381*81ad6265SDimitry Andric 382*81ad6265SDimitry Andric bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand( 383*81ad6265SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 384*81ad6265SDimitry Andric switch (ConstraintID) { 385*81ad6265SDimitry Andric case InlineAsm::Constraint_m: 386*81ad6265SDimitry Andric // We just support simple memory operands that have a single address 387*81ad6265SDimitry Andric // operand and need no special handling. 388*81ad6265SDimitry Andric OutOps.push_back(Op); 389*81ad6265SDimitry Andric return false; 390*81ad6265SDimitry Andric default: 391*81ad6265SDimitry Andric break; 392*81ad6265SDimitry Andric } 393*81ad6265SDimitry Andric 394*81ad6265SDimitry Andric return true; 395*81ad6265SDimitry Andric } 396*81ad6265SDimitry Andric 397349cc55cSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { 398349cc55cSDimitry Andric return new CSKYDAGToDAGISel(TM); 399349cc55cSDimitry Andric } 400