//===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines an instruction selector for the CSKY target. // //===----------------------------------------------------------------------===// #include "CSKY.h" #include "CSKYSubtarget.h" #include "CSKYTargetMachine.h" #include "MCTargetDesc/CSKYMCTargetDesc.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" using namespace llvm; #define DEBUG_TYPE "csky-isel" namespace { class CSKYDAGToDAGISel : public SelectionDAGISel { const CSKYSubtarget *Subtarget; public: explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM) : SelectionDAGISel(TM) {} StringRef getPassName() const override { return "CSKY DAG->DAG Pattern Instruction Selection"; } bool runOnMachineFunction(MachineFunction &MF) override { // Reset the subtarget each time through. Subtarget = &MF.getSubtarget(); SelectionDAGISel::runOnMachineFunction(MF); return true; } void Select(SDNode *N) override; bool selectAddCarry(SDNode *N); bool selectSubCarry(SDNode *N); #include "CSKYGenDAGISel.inc" }; } // namespace void CSKYDAGToDAGISel::Select(SDNode *N) { // If we have a custom node, we have already selected if (N->isMachineOpcode()) { LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n"); N->setNodeId(-1); return; } SDLoc Dl(N); unsigned Opcode = N->getOpcode(); bool IsSelected = false; switch (Opcode) { default: break; case ISD::ADDCARRY: IsSelected = selectAddCarry(N); break; case ISD::SUBCARRY: IsSelected = selectSubCarry(N); break; case ISD::GLOBAL_OFFSET_TABLE: { Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF); ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode()); IsSelected = true; break; } case ISD::FrameIndex: { SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32); int FI = cast(N)->getIndex(); SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32 : CSKY::ADDI16XZ, Dl, MVT::i32, TFI, Imm)); IsSelected = true; break; } } if (IsSelected) return; // Select the default instruction. SelectCode(N); } bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) { MachineSDNode *NewNode = nullptr; auto Type0 = N->getValueType(0); auto Type1 = N->getValueType(1); auto Op0 = N->getOperand(0); auto Op1 = N->getOperand(1); auto Op2 = N->getOperand(2); SDLoc Dl(N); if (isNullConstant(Op2)) { auto *CA = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); NewNode = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, {Op0, Op1, SDValue(CA, 0)}); } else if (isOneConstant(Op2)) { auto *CA = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); NewNode = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, {Op0, Op1, SDValue(CA, 0)}); } else { NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1}, {Op0, Op1, Op2}); } ReplaceNode(N, NewNode); return true; } static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget, SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) { auto NewCarryReg = DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl, MVT::i32, OldCarry); auto NewCarry = DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16, Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0), DAG->getTargetConstant(0, Dl, MVT::i32)); return SDValue(NewCarry, 0); } bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) { MachineSDNode *NewNode = nullptr; auto Type0 = N->getValueType(0); auto Type1 = N->getValueType(1); auto Op0 = N->getOperand(0); auto Op1 = N->getOperand(1); auto Op2 = N->getOperand(2); SDLoc Dl(N); if (isNullConstant(Op2)) { auto *CA = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1); NewNode = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, {Op0, Op1, SDValue(CA, 0)}); } else if (isOneConstant(Op2)) { auto *CA = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1); NewNode = CurDAG->getMachineNode( Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, {Op0, Op1, SDValue(CA, 0)}); } else { auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2); NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1}, {Op0, Op1, CarryIn}); } auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1)); ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0)); ReplaceUses(SDValue(N, 1), CarryOut); CurDAG->RemoveDeadNode(N); return true; } FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM) { return new CSKYDAGToDAGISel(TM); }