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; 43*0eae32dcSDimitry Andric bool selectAddCarry(SDNode *N); 44*0eae32dcSDimitry 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; 65*0eae32dcSDimitry Andric case ISD::ADDCARRY: 66*0eae32dcSDimitry Andric IsSelected = selectAddCarry(N); 67*0eae32dcSDimitry Andric break; 68*0eae32dcSDimitry Andric case ISD::SUBCARRY: 69*0eae32dcSDimitry Andric IsSelected = selectSubCarry(N); 70*0eae32dcSDimitry Andric break; 71349cc55cSDimitry Andric } 72349cc55cSDimitry Andric 73349cc55cSDimitry Andric if (IsSelected) 74349cc55cSDimitry Andric return; 75349cc55cSDimitry Andric 76349cc55cSDimitry Andric // Select the default instruction. 77349cc55cSDimitry Andric SelectCode(N); 78349cc55cSDimitry Andric } 79349cc55cSDimitry Andric 80*0eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { 81*0eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 82*0eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 83*0eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 84*0eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 85*0eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 86*0eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 87*0eae32dcSDimitry Andric 88*0eae32dcSDimitry Andric SDLoc Dl(N); 89*0eae32dcSDimitry Andric 90*0eae32dcSDimitry Andric if (isNullConstant(Op2)) { 91*0eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 92*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 93*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 94*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 95*0eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 96*0eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 97*0eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 98*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 99*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 100*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, 101*0eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 102*0eae32dcSDimitry Andric } else { 103*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 104*0eae32dcSDimitry Andric : CSKY::ADDC16, 105*0eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, Op2}); 106*0eae32dcSDimitry Andric } 107*0eae32dcSDimitry Andric ReplaceNode(N, NewNode); 108*0eae32dcSDimitry Andric return true; 109*0eae32dcSDimitry Andric } 110*0eae32dcSDimitry Andric 111*0eae32dcSDimitry Andric static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, 112*0eae32dcSDimitry Andric SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { 113*0eae32dcSDimitry Andric auto NewCarryReg = 114*0eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, 115*0eae32dcSDimitry Andric MVT::i32, OldCarry); 116*0eae32dcSDimitry Andric auto NewCarry = 117*0eae32dcSDimitry Andric DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, 118*0eae32dcSDimitry Andric Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), 119*0eae32dcSDimitry Andric DAG->getTargetConstant(0, Dl, MVT::i32)); 120*0eae32dcSDimitry Andric return SDValue(NewCarry, 0); 121*0eae32dcSDimitry Andric } 122*0eae32dcSDimitry Andric 123*0eae32dcSDimitry Andric bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { 124*0eae32dcSDimitry Andric MachineSDNode *NewNode = nullptr; 125*0eae32dcSDimitry Andric auto Type0 = N->getValueType(0); 126*0eae32dcSDimitry Andric auto Type1 = N->getValueType(1); 127*0eae32dcSDimitry Andric auto Op0 = N->getOperand(0); 128*0eae32dcSDimitry Andric auto Op1 = N->getOperand(1); 129*0eae32dcSDimitry Andric auto Op2 = N->getOperand(2); 130*0eae32dcSDimitry Andric 131*0eae32dcSDimitry Andric SDLoc Dl(N); 132*0eae32dcSDimitry Andric 133*0eae32dcSDimitry Andric if (isNullConstant(Op2)) { 134*0eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 135*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); 136*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 137*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 138*0eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 139*0eae32dcSDimitry Andric } else if (isOneConstant(Op2)) { 140*0eae32dcSDimitry Andric auto *CA = CurDAG->getMachineNode( 141*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); 142*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode( 143*0eae32dcSDimitry Andric Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, 144*0eae32dcSDimitry Andric {Op0, Op1, SDValue(CA, 0)}); 145*0eae32dcSDimitry Andric } else { 146*0eae32dcSDimitry Andric auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); 147*0eae32dcSDimitry Andric NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 148*0eae32dcSDimitry Andric : CSKY::SUBC16, 149*0eae32dcSDimitry Andric Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); 150*0eae32dcSDimitry Andric } 151*0eae32dcSDimitry Andric auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); 152*0eae32dcSDimitry Andric 153*0eae32dcSDimitry Andric ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); 154*0eae32dcSDimitry Andric ReplaceUses(SDValue(N, 1), CarryOut); 155*0eae32dcSDimitry Andric CurDAG->RemoveDeadNode(N); 156*0eae32dcSDimitry Andric 157*0eae32dcSDimitry Andric return true; 158*0eae32dcSDimitry Andric } 159*0eae32dcSDimitry Andric 160349cc55cSDimitry Andric FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { 161349cc55cSDimitry Andric return new CSKYDAGToDAGISel(TM); 162349cc55cSDimitry Andric } 163