xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYISelDAGToDAG.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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