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" 17349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 18349cc55cSDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 19349cc55cSDimitry Andric 20349cc55cSDimitry Andric using namespace llvm; 21349cc55cSDimitry Andric 22349cc55cSDimitry Andric #define DEBUG_TYPE "csky-isel" 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric namespace { 25349cc55cSDimitry Andric class CSKYDAGToDAGISel : public SelectionDAGISel { 26349cc55cSDimitry Andric const CSKYSubtarget *Subtarget; 27349cc55cSDimitry Andric 28349cc55cSDimitry Andric public: 29349cc55cSDimitry Andric explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {} 30349cc55cSDimitry Andric 31349cc55cSDimitry Andric StringRef getPassName() const override { 32349cc55cSDimitry Andric return "CSKY DAG->DAG Pattern Instruction Selection"; 33349cc55cSDimitry Andric } 34349cc55cSDimitry Andric 35349cc55cSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 36349cc55cSDimitry Andric // Reset the subtarget each time through. 37349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<CSKYSubtarget>(); 38349cc55cSDimitry Andric SelectionDAGISel::runOnMachineFunction(MF); 39349cc55cSDimitry Andric return true; 40349cc55cSDimitry Andric } 41349cc55cSDimitry Andric 42349cc55cSDimitry Andric void Select(SDNode *N) override; 430eae32dcSDimitry Andric bool selectAddCarry(SDNode *N); 440eae32dcSDimitry Andric bool selectSubCarry(SDNode *N); 45349cc55cSDimitry Andric 46349cc55cSDimitry Andric #include "CSKYGenDAGISel.inc" 47349cc55cSDimitry Andric }; 48349cc55cSDimitry Andric } // namespace 49349cc55cSDimitry Andric 50349cc55cSDimitry Andric void CSKYDAGToDAGISel::Select(SDNode *N) { 51349cc55cSDimitry Andric // If we have a custom node, we have already selected 52349cc55cSDimitry Andric if (N->isMachineOpcode()) { 53349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n"); 54349cc55cSDimitry Andric N->setNodeId(-1); 55349cc55cSDimitry Andric return; 56349cc55cSDimitry Andric } 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric SDLoc Dl(N); 59349cc55cSDimitry Andric unsigned Opcode = N->getOpcode(); 60349cc55cSDimitry Andric bool IsSelected = false; 61349cc55cSDimitry Andric 62349cc55cSDimitry Andric switch (Opcode) { 63349cc55cSDimitry Andric default: 64349cc55cSDimitry Andric break; 650eae32dcSDimitry Andric case ISD::ADDCARRY: 660eae32dcSDimitry Andric IsSelected = selectAddCarry(N); 670eae32dcSDimitry Andric break; 680eae32dcSDimitry Andric case ISD::SUBCARRY: 690eae32dcSDimitry Andric IsSelected = selectSubCarry(N); 700eae32dcSDimitry Andric break; 71*04eeddc0SDimitry Andric case ISD::GLOBAL_OFFSET_TABLE: { 72*04eeddc0SDimitry Andric Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF); 73*04eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode()); 74*04eeddc0SDimitry Andric 75*04eeddc0SDimitry Andric IsSelected = true; 76*04eeddc0SDimitry Andric break; 77*04eeddc0SDimitry Andric } 78*04eeddc0SDimitry Andric case ISD::FrameIndex: { 79*04eeddc0SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32); 80*04eeddc0SDimitry Andric int FI = cast<FrameIndexSDNode>(N)->getIndex(); 81*04eeddc0SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); 82*04eeddc0SDimitry Andric ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32 83*04eeddc0SDimitry Andric : CSKY::ADDI16XZ, 84*04eeddc0SDimitry Andric Dl, MVT::i32, TFI, Imm)); 85*04eeddc0SDimitry Andric 86*04eeddc0SDimitry Andric IsSelected = true; 87*04eeddc0SDimitry Andric break; 88*04eeddc0SDimitry Andric } 89349cc55cSDimitry Andric } 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric if (IsSelected) 92349cc55cSDimitry Andric return; 93349cc55cSDimitry Andric 94349cc55cSDimitry Andric // Select the default instruction. 95349cc55cSDimitry Andric SelectCode(N); 96349cc55cSDimitry Andric } 97349cc55cSDimitry Andric 980eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { 990eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 1000eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 1010eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 1020eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 1030eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 1040eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 1050eae32dcSDimitry Andric 1060eae32dcSDimitry Andric SDLoc Dl(N); 1070eae32dcSDimitry Andric 1080eae32dcSDimitry Andric if (isNullConstant(Op2)) { 1090eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 1100eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 1110eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 1120eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 1130eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 1140eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 1150eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 1160eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 1170eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 1180eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 1190eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 1200eae32dcSDimitry Andric } else { 1210eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 1220eae32dcSDimitry Andric : CSKY::ADDC16, 1230eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, Op2}); 1240eae32dcSDimitry Andric } 1250eae32dcSDimitry Andric ReplaceNode(N, NewNode); 1260eae32dcSDimitry Andric return true; 1270eae32dcSDimitry Andric } 1280eae32dcSDimitry Andric 1290eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, 1300eae32dcSDimitry Andric SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { 1310eae32dcSDimitry Andric auto NewCarryReg = 1320eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, 1330eae32dcSDimitry Andric MVT::i32, OldCarry); 1340eae32dcSDimitry Andric auto NewCarry = 1350eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, 1360eae32dcSDimitry Andric Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), 1370eae32dcSDimitry Andric DAG->getTargetConstant(0, Dl, MVT::i32)); 1380eae32dcSDimitry Andric return SDValue(NewCarry, 0); 1390eae32dcSDimitry Andric } 1400eae32dcSDimitry Andric 1410eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { 1420eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 1430eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 1440eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 1450eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 1460eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 1470eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 1480eae32dcSDimitry Andric 1490eae32dcSDimitry Andric SDLoc Dl(N); 1500eae32dcSDimitry Andric 1510eae32dcSDimitry Andric if (isNullConstant(Op2)) { 1520eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 1530eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 1540eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 1550eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 1560eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 1570eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 1580eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 1590eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 1600eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 1610eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 1620eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 1630eae32dcSDimitry Andric } else { 1640eae32dcSDimitry Andric auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); 1650eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 1660eae32dcSDimitry Andric : CSKY::SUBC16, 1670eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); 1680eae32dcSDimitry Andric } 1690eae32dcSDimitry Andric auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); 1700eae32dcSDimitry Andric 1710eae32dcSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); 1720eae32dcSDimitry Andric ReplaceUses(SDValue(N, 1), CarryOut); 1730eae32dcSDimitry Andric CurDAG->RemoveDeadNode(N); 1740eae32dcSDimitry Andric 1750eae32dcSDimitry Andric return true; 1760eae32dcSDimitry Andric } 1770eae32dcSDimitry Andric 178349cc55cSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { 179349cc55cSDimitry Andric return new CSKYDAGToDAGISel(TM); 180349cc55cSDimitry Andric } 181