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" 1781ad6265SDimitry 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" 24bdd1243dSDimitry Andric #define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection" 25349cc55cSDimitry Andric 26349cc55cSDimitry Andric namespace { 27349cc55cSDimitry Andric class CSKYDAGToDAGISel : public SelectionDAGISel { 28349cc55cSDimitry Andric const CSKYSubtarget *Subtarget; 29349cc55cSDimitry Andric 30349cc55cSDimitry Andric public: 315f757f3fSDimitry Andric explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM, CodeGenOptLevel OptLevel) 32*0fca6ea1SDimitry Andric : SelectionDAGISel(TM, OptLevel) {} 33349cc55cSDimitry Andric 34349cc55cSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 35349cc55cSDimitry Andric // Reset the subtarget each time through. 36349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<CSKYSubtarget>(); 37349cc55cSDimitry Andric SelectionDAGISel::runOnMachineFunction(MF); 38349cc55cSDimitry Andric return true; 39349cc55cSDimitry Andric } 40349cc55cSDimitry Andric 41349cc55cSDimitry Andric void Select(SDNode *N) override; 420eae32dcSDimitry Andric bool selectAddCarry(SDNode *N); 430eae32dcSDimitry Andric bool selectSubCarry(SDNode *N); 4481ad6265SDimitry Andric bool selectBITCAST_TO_LOHI(SDNode *N); 4581ad6265SDimitry Andric bool selectInlineAsm(SDNode *N); 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1); 4881ad6265SDimitry Andric 495f757f3fSDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, 505f757f3fSDimitry Andric InlineAsm::ConstraintCode ConstraintID, 5181ad6265SDimitry Andric std::vector<SDValue> &OutOps) override; 52349cc55cSDimitry Andric 53349cc55cSDimitry Andric #include "CSKYGenDAGISel.inc" 54349cc55cSDimitry Andric }; 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric class CSKYDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 57*0fca6ea1SDimitry Andric public: 58*0fca6ea1SDimitry Andric static char ID; 59*0fca6ea1SDimitry Andric explicit CSKYDAGToDAGISelLegacy(CSKYTargetMachine &TM, 60*0fca6ea1SDimitry Andric CodeGenOptLevel OptLevel) 61*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy( 62*0fca6ea1SDimitry Andric ID, std::make_unique<CSKYDAGToDAGISel>(TM, OptLevel)) {} 63*0fca6ea1SDimitry Andric }; 64349cc55cSDimitry Andric } // namespace 65349cc55cSDimitry Andric 66*0fca6ea1SDimitry Andric char CSKYDAGToDAGISelLegacy::ID = 0; 67bdd1243dSDimitry Andric 68*0fca6ea1SDimitry Andric INITIALIZE_PASS(CSKYDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 69bdd1243dSDimitry Andric 70349cc55cSDimitry Andric void CSKYDAGToDAGISel::Select(SDNode *N) { 71349cc55cSDimitry Andric // If we have a custom node, we have already selected 72349cc55cSDimitry Andric if (N->isMachineOpcode()) { 73349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n"); 74349cc55cSDimitry Andric N->setNodeId(-1); 75349cc55cSDimitry Andric return; 76349cc55cSDimitry Andric } 77349cc55cSDimitry Andric 78349cc55cSDimitry Andric SDLoc Dl(N); 79349cc55cSDimitry Andric unsigned Opcode = N->getOpcode(); 80349cc55cSDimitry Andric bool IsSelected = false; 81349cc55cSDimitry Andric 82349cc55cSDimitry Andric switch (Opcode) { 83349cc55cSDimitry Andric default: 84349cc55cSDimitry Andric break; 8506c3fb27SDimitry Andric case ISD::UADDO_CARRY: 860eae32dcSDimitry Andric IsSelected = selectAddCarry(N); 870eae32dcSDimitry Andric break; 8806c3fb27SDimitry Andric case ISD::USUBO_CARRY: 890eae32dcSDimitry Andric IsSelected = selectSubCarry(N); 900eae32dcSDimitry Andric break; 9104eeddc0SDimitry Andric case ISD::GLOBAL_OFFSET_TABLE: { 9204eeddc0SDimitry Andric Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF); 9304eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode()); 9404eeddc0SDimitry Andric 9504eeddc0SDimitry Andric IsSelected = true; 9604eeddc0SDimitry Andric break; 9704eeddc0SDimitry Andric } 9804eeddc0SDimitry Andric case ISD::FrameIndex: { 9904eeddc0SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32); 10004eeddc0SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 10104eeddc0SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); 10204eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32 10304eeddc0SDimitry Andric : CSKY::ADDI16XZ, 10404eeddc0SDimitry Andric Dl, MVT::i32, TFI, Imm)); 10504eeddc0SDimitry Andric 10604eeddc0SDimitry Andric IsSelected = true; 10704eeddc0SDimitry Andric break; 10804eeddc0SDimitry Andric } 10981ad6265SDimitry Andric case CSKYISD::BITCAST_TO_LOHI: 11081ad6265SDimitry Andric IsSelected = selectBITCAST_TO_LOHI(N); 11181ad6265SDimitry Andric break; 11281ad6265SDimitry Andric case ISD::INLINEASM: 11381ad6265SDimitry Andric case ISD::INLINEASM_BR: 11481ad6265SDimitry Andric IsSelected = selectInlineAsm(N); 11581ad6265SDimitry Andric break; 116349cc55cSDimitry Andric } 117349cc55cSDimitry Andric 118349cc55cSDimitry Andric if (IsSelected) 119349cc55cSDimitry Andric return; 120349cc55cSDimitry Andric 121349cc55cSDimitry Andric // Select the default instruction. 122349cc55cSDimitry Andric SelectCode(N); 123349cc55cSDimitry Andric } 124349cc55cSDimitry Andric 12581ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) { 12681ad6265SDimitry Andric std::vector<SDValue> AsmNodeOperands; 1275f757f3fSDimitry Andric InlineAsm::Flag Flag; 12881ad6265SDimitry Andric bool Changed = false; 12981ad6265SDimitry Andric unsigned NumOps = N->getNumOperands(); 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint. 13281ad6265SDimitry Andric // However, some instructions (e.g. mula.s32) require GPR pair. 13381ad6265SDimitry Andric // Since there is no constraint to explicitly specify a 13481ad6265SDimitry Andric // reg pair, we use GPRPair reg class for "%r" for 64-bit data. 13581ad6265SDimitry Andric 13681ad6265SDimitry Andric SDLoc dl(N); 13781ad6265SDimitry Andric SDValue Glue = 13881ad6265SDimitry Andric N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0); 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric SmallVector<bool, 8> OpChanged; 14181ad6265SDimitry Andric // Glue node will be appended late. 14281ad6265SDimitry Andric for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; 14381ad6265SDimitry Andric ++i) { 14481ad6265SDimitry Andric SDValue op = N->getOperand(i); 14581ad6265SDimitry Andric AsmNodeOperands.push_back(op); 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric if (i < InlineAsm::Op_FirstOperand) 14881ad6265SDimitry Andric continue; 14981ad6265SDimitry Andric 1505f757f3fSDimitry Andric if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) 1515f757f3fSDimitry Andric Flag = InlineAsm::Flag(C->getZExtValue()); 1525f757f3fSDimitry Andric else 15381ad6265SDimitry Andric continue; 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric // Immediate operands to inline asm in the SelectionDAG are modeled with 1565f757f3fSDimitry Andric // two operands. The first is a constant of value InlineAsm::Kind::Imm, and 15781ad6265SDimitry Andric // the second is a constant with the value of the immediate. If we get here 1585f757f3fSDimitry Andric // and we have a Kind::Imm, skip the next operand, and continue. 1595f757f3fSDimitry Andric if (Flag.isImmKind()) { 16081ad6265SDimitry Andric SDValue op = N->getOperand(++i); 16181ad6265SDimitry Andric AsmNodeOperands.push_back(op); 16281ad6265SDimitry Andric continue; 16381ad6265SDimitry Andric } 16481ad6265SDimitry Andric 1655f757f3fSDimitry Andric const unsigned NumRegs = Flag.getNumOperandRegisters(); 16681ad6265SDimitry Andric if (NumRegs) 16781ad6265SDimitry Andric OpChanged.push_back(false); 16881ad6265SDimitry Andric 16981ad6265SDimitry Andric unsigned DefIdx = 0; 17081ad6265SDimitry Andric bool IsTiedToChangedOp = false; 17181ad6265SDimitry Andric // If it's a use that is tied with a previous def, it has no 17281ad6265SDimitry Andric // reg class constraint. 1735f757f3fSDimitry Andric if (Changed && Flag.isUseOperandTiedToDef(DefIdx)) 17481ad6265SDimitry Andric IsTiedToChangedOp = OpChanged[DefIdx]; 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric // Memory operands to inline asm in the SelectionDAG are modeled with two 1775f757f3fSDimitry Andric // operands: a constant of value InlineAsm::Kind::Mem followed by the input 1785f757f3fSDimitry Andric // operand. If we get here and we have a Kind::Mem, skip the next operand 1795f757f3fSDimitry Andric // (so it doesn't get misinterpreted), and continue. We do this here because 18081ad6265SDimitry Andric // it's important to update the OpChanged array correctly before moving on. 1815f757f3fSDimitry Andric if (Flag.isMemKind()) { 18281ad6265SDimitry Andric SDValue op = N->getOperand(++i); 18381ad6265SDimitry Andric AsmNodeOperands.push_back(op); 18481ad6265SDimitry Andric continue; 18581ad6265SDimitry Andric } 18681ad6265SDimitry Andric 1875f757f3fSDimitry Andric if (!Flag.isRegUseKind() && !Flag.isRegDefKind() && 1885f757f3fSDimitry Andric !Flag.isRegDefEarlyClobberKind()) 18981ad6265SDimitry Andric continue; 19081ad6265SDimitry Andric 19181ad6265SDimitry Andric unsigned RC; 1925f757f3fSDimitry Andric const bool HasRC = Flag.hasRegClassConstraint(RC); 19381ad6265SDimitry Andric if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) || 19481ad6265SDimitry Andric NumRegs != 2) 19581ad6265SDimitry Andric continue; 19681ad6265SDimitry Andric 19781ad6265SDimitry Andric assert((i + 2 < NumOps) && "Invalid number of operands in inline asm"); 19881ad6265SDimitry Andric SDValue V0 = N->getOperand(i + 1); 19981ad6265SDimitry Andric SDValue V1 = N->getOperand(i + 2); 20081ad6265SDimitry Andric unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg(); 20181ad6265SDimitry Andric unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg(); 20281ad6265SDimitry Andric SDValue PairedReg; 20381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 20481ad6265SDimitry Andric 2055f757f3fSDimitry Andric if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) { 20681ad6265SDimitry Andric // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to 20781ad6265SDimitry Andric // the original GPRs. 20881ad6265SDimitry Andric 20981ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass); 21081ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64); 21181ad6265SDimitry Andric SDValue Chain = SDValue(N, 0); 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric SDNode *GU = N->getGluedUser(); 21481ad6265SDimitry Andric SDValue RegCopy = 21581ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1)); 21681ad6265SDimitry Andric 21781ad6265SDimitry Andric // Extract values from a GPRPair reg and copy to the original GPR reg. 21881ad6265SDimitry Andric SDValue Sub0 = 21981ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy); 22081ad6265SDimitry Andric SDValue Sub1 = 22181ad6265SDimitry Andric CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy); 22281ad6265SDimitry Andric SDValue T0 = 22381ad6265SDimitry Andric CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1)); 22481ad6265SDimitry Andric SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1)); 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric // Update the original glue user. 22781ad6265SDimitry Andric std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1); 22881ad6265SDimitry Andric Ops.push_back(T1.getValue(1)); 22981ad6265SDimitry Andric CurDAG->UpdateNodeOperands(GU, Ops); 23081ad6265SDimitry Andric } else { 2315f757f3fSDimitry Andric // For Kind == InlineAsm::Kind::RegUse, we first copy two GPRs into a 23281ad6265SDimitry Andric // GPRPair and then pass the GPRPair to the inline asm. 23381ad6265SDimitry Andric SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain]; 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric // As REG_SEQ doesn't take RegisterSDNode, we copy them first. 23681ad6265SDimitry Andric SDValue T0 = 23781ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1)); 23881ad6265SDimitry Andric SDValue T1 = 23981ad6265SDimitry Andric CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1)); 24081ad6265SDimitry Andric SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0); 24181ad6265SDimitry Andric 24281ad6265SDimitry Andric // Copy REG_SEQ into a GPRPair-typed VR and replace the original two 24381ad6265SDimitry Andric // i32 VRs of inline asm with it. 24481ad6265SDimitry Andric Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass); 24581ad6265SDimitry Andric PairedReg = CurDAG->getRegister(GPVR, MVT::i64); 24681ad6265SDimitry Andric Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1)); 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric AsmNodeOperands[InlineAsm::Op_InputChain] = Chain; 24981ad6265SDimitry Andric Glue = Chain.getValue(1); 25081ad6265SDimitry Andric } 25181ad6265SDimitry Andric 25281ad6265SDimitry Andric Changed = true; 25381ad6265SDimitry Andric 25481ad6265SDimitry Andric if (PairedReg.getNode()) { 25581ad6265SDimitry Andric OpChanged[OpChanged.size() - 1] = true; 2565f757f3fSDimitry Andric // TODO: maybe a setter for getNumOperandRegisters? 2575f757f3fSDimitry Andric Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/); 25881ad6265SDimitry Andric if (IsTiedToChangedOp) 2595f757f3fSDimitry Andric Flag.setMatchingOp(DefIdx); 26081ad6265SDimitry Andric else 2615f757f3fSDimitry Andric Flag.setRegClass(CSKY::GPRPairRegClassID); 26281ad6265SDimitry Andric // Replace the current flag. 26381ad6265SDimitry Andric AsmNodeOperands[AsmNodeOperands.size() - 1] = 26481ad6265SDimitry Andric CurDAG->getTargetConstant(Flag, dl, MVT::i32); 26581ad6265SDimitry Andric // Add the new register node and skip the original two GPRs. 26681ad6265SDimitry Andric AsmNodeOperands.push_back(PairedReg); 26781ad6265SDimitry Andric // Skip the next two GPRs. 26881ad6265SDimitry Andric i += 2; 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric } 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric if (Glue.getNode()) 27381ad6265SDimitry Andric AsmNodeOperands.push_back(Glue); 27481ad6265SDimitry Andric if (!Changed) 27581ad6265SDimitry Andric return false; 27681ad6265SDimitry Andric 27781ad6265SDimitry Andric SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N), 27881ad6265SDimitry Andric CurDAG->getVTList(MVT::Other, MVT::Glue), 27981ad6265SDimitry Andric AsmNodeOperands); 28081ad6265SDimitry Andric New->setNodeId(-1); 28181ad6265SDimitry Andric ReplaceNode(N, New.getNode()); 28281ad6265SDimitry Andric return true; 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) { 28681ad6265SDimitry Andric SDLoc Dl(N); 28781ad6265SDimitry Andric auto VT = N->getValueType(0); 28881ad6265SDimitry Andric auto V = N->getOperand(0); 28981ad6265SDimitry Andric 29081ad6265SDimitry Andric if (!Subtarget->hasFPUv2DoubleFloat()) 29181ad6265SDimitry Andric return false; 29281ad6265SDimitry Andric 29381ad6265SDimitry Andric SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0); 29481ad6265SDimitry Andric SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0); 29581ad6265SDimitry Andric 29681ad6265SDimitry Andric ReplaceUses(SDValue(N, 0), V1); 29781ad6265SDimitry Andric ReplaceUses(SDValue(N, 1), V2); 29881ad6265SDimitry Andric CurDAG->RemoveDeadNode(N); 29981ad6265SDimitry Andric 30081ad6265SDimitry Andric return true; 30181ad6265SDimitry Andric } 30281ad6265SDimitry Andric 3030eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { 3040eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 3050eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 3060eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 3070eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 3080eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 3090eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 3100eae32dcSDimitry Andric 3110eae32dcSDimitry Andric SDLoc Dl(N); 3120eae32dcSDimitry Andric 3130eae32dcSDimitry Andric if (isNullConstant(Op2)) { 3140eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3150eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 3160eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3170eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 3180eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3190eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 3200eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3210eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 3220eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3230eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 3240eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3250eae32dcSDimitry Andric } else { 3260eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 3270eae32dcSDimitry Andric : CSKY::ADDC16, 3280eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, Op2}); 3290eae32dcSDimitry Andric } 3300eae32dcSDimitry Andric ReplaceNode(N, NewNode); 3310eae32dcSDimitry Andric return true; 3320eae32dcSDimitry Andric } 3330eae32dcSDimitry Andric 3340eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, 3350eae32dcSDimitry Andric SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { 3360eae32dcSDimitry Andric auto NewCarryReg = 3370eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, 3380eae32dcSDimitry Andric MVT::i32, OldCarry); 3390eae32dcSDimitry Andric auto NewCarry = 3400eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, 3410eae32dcSDimitry Andric Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), 3420eae32dcSDimitry Andric DAG->getTargetConstant(0, Dl, MVT::i32)); 3430eae32dcSDimitry Andric return SDValue(NewCarry, 0); 3440eae32dcSDimitry Andric } 3450eae32dcSDimitry Andric 3460eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { 3470eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 3480eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 3490eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 3500eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 3510eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 3520eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 3530eae32dcSDimitry Andric 3540eae32dcSDimitry Andric SDLoc Dl(N); 3550eae32dcSDimitry Andric 3560eae32dcSDimitry Andric if (isNullConstant(Op2)) { 3570eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3580eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 3590eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3600eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 3610eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3620eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 3630eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 3640eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 3650eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 3660eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 3670eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 3680eae32dcSDimitry Andric } else { 3690eae32dcSDimitry Andric auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); 3700eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 3710eae32dcSDimitry Andric : CSKY::SUBC16, 3720eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); 3730eae32dcSDimitry Andric } 3740eae32dcSDimitry Andric auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); 3750eae32dcSDimitry Andric 3760eae32dcSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); 3770eae32dcSDimitry Andric ReplaceUses(SDValue(N, 1), CarryOut); 3780eae32dcSDimitry Andric CurDAG->RemoveDeadNode(N); 3790eae32dcSDimitry Andric 3800eae32dcSDimitry Andric return true; 3810eae32dcSDimitry Andric } 3820eae32dcSDimitry Andric 38381ad6265SDimitry Andric SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) { 38481ad6265SDimitry Andric SDLoc dl(V0.getNode()); 38581ad6265SDimitry Andric SDValue RegClass = 38681ad6265SDimitry Andric CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32); 38781ad6265SDimitry Andric SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32); 38881ad6265SDimitry Andric SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32); 38981ad6265SDimitry Andric const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1}; 39081ad6265SDimitry Andric return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops); 39181ad6265SDimitry Andric } 39281ad6265SDimitry Andric 39381ad6265SDimitry Andric bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand( 3945f757f3fSDimitry Andric const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID, 3955f757f3fSDimitry Andric std::vector<SDValue> &OutOps) { 39681ad6265SDimitry Andric switch (ConstraintID) { 3975f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: 39881ad6265SDimitry Andric // We just support simple memory operands that have a single address 39981ad6265SDimitry Andric // operand and need no special handling. 40081ad6265SDimitry Andric OutOps.push_back(Op); 40181ad6265SDimitry Andric return false; 40281ad6265SDimitry Andric default: 40381ad6265SDimitry Andric break; 40481ad6265SDimitry Andric } 40581ad6265SDimitry Andric 40681ad6265SDimitry Andric return true; 40781ad6265SDimitry Andric } 40881ad6265SDimitry Andric 409bdd1243dSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM, 4105f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 411*0fca6ea1SDimitry Andric return new CSKYDAGToDAGISelLegacy(TM, OptLevel); 412349cc55cSDimitry Andric } 413