xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARC/ARCISelDAGToDAG.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
1 //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines an instruction selector for the ARC target.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "ARC.h"
14 #include "ARCSelectionDAGInfo.h"
15 #include "ARCTargetMachine.h"
16 #include "llvm/CodeGen/MachineFrameInfo.h"
17 #include "llvm/CodeGen/MachineFunction.h"
18 #include "llvm/CodeGen/MachineInstrBuilder.h"
19 #include "llvm/CodeGen/MachineRegisterInfo.h"
20 #include "llvm/CodeGen/SelectionDAG.h"
21 #include "llvm/CodeGen/SelectionDAGISel.h"
22 #include "llvm/CodeGen/TargetLowering.h"
23 #include "llvm/IR/CallingConv.h"
24 #include "llvm/IR/Constants.h"
25 #include "llvm/IR/DerivedTypes.h"
26 #include "llvm/IR/Function.h"
27 #include "llvm/IR/Intrinsics.h"
28 #include "llvm/IR/LLVMContext.h"
29 #include "llvm/Support/Compiler.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/ErrorHandling.h"
32 #include "llvm/Support/raw_ostream.h"
33 
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "arc-isel"
37 #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection"
38 
39 /// ARCDAGToDAGISel - ARC specific code to select ARC machine
40 /// instructions for SelectionDAG operations.
41 namespace {
42 
43 class ARCDAGToDAGISel : public SelectionDAGISel {
44 public:
45   ARCDAGToDAGISel() = delete;
46 
47   ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
48       : SelectionDAGISel(TM, OptLevel) {}
49 
50   void Select(SDNode *N) override;
51 
52   // Complex Pattern Selectors.
53   bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
54   bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
55   bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
56   bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
57 
58 // Include the pieces autogenerated from the target description.
59 #include "ARCGenDAGISel.inc"
60 };
61 
62 class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
63 public:
64   static char ID;
65   explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel)
66       : SelectionDAGISelLegacy(
67             ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {}
68 };
69 
70 char ARCDAGToDAGISelLegacy::ID;
71 
72 } // end anonymous namespace
73 
74 INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
75 
76 /// This pass converts a legalized DAG into a ARC-specific DAG, ready for
77 /// instruction scheduling.
78 FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
79                                      CodeGenOptLevel OptLevel) {
80   return new ARCDAGToDAGISelLegacy(TM, OptLevel);
81 }
82 
83 bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
84                                         SDValue &Offset) {
85   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
86     Base = Addr.getOperand(0);
87     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
88     return true;
89   }
90   return false;
91 }
92 
93 bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
94                                        SDValue &Offset) {
95   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
96     return false;
97   }
98 
99   if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
100       !CurDAG->isBaseWithConstantOffset(Addr)) {
101     if (Addr.getOpcode() == ISD::FrameIndex) {
102       // Match frame index.
103       int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
104       Base = CurDAG->getTargetFrameIndex(
105           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
106     } else {
107       Base = Addr;
108     }
109     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
110     return true;
111   }
112 
113   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
114     int32_t RHSC = RHS->getSExtValue();
115     if (Addr.getOpcode() == ISD::SUB)
116       RHSC = -RHSC;
117 
118     // Do we need more than 9 bits to encode?
119     if (!isInt<9>(RHSC))
120       return false;
121     Base = Addr.getOperand(0);
122     if (Base.getOpcode() == ISD::FrameIndex) {
123       int FI = cast<FrameIndexSDNode>(Base)->getIndex();
124       Base = CurDAG->getTargetFrameIndex(
125           FI, TLI->getPointerTy(CurDAG->getDataLayout()));
126     }
127     Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
128     return true;
129   }
130   Base = Addr;
131   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
132   return true;
133 }
134 
135 bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
136                                         SDValue &Offset) {
137   if (SelectAddrModeS9(Addr, Base, Offset))
138     return false;
139   if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
140     return false;
141   }
142   if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
143     int32_t RHSC = RHS->getSExtValue();
144     if (Addr.getOpcode() == ISD::SUB)
145       RHSC = -RHSC;
146     Base = Addr.getOperand(0);
147     Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
148     return true;
149   }
150   return false;
151 }
152 
153 // Is this a legal frame index addressing expression.
154 bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
155                                          SDValue &Offset) {
156   FrameIndexSDNode *FIN = nullptr;
157   if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
158     Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
159     Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
160     return true;
161   }
162   if (Addr.getOpcode() == ISD::ADD) {
163     ConstantSDNode *CN = nullptr;
164     if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
165         (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
166         (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
167       // Constant positive word offset from frame index
168       Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
169       Offset =
170           CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
171       return true;
172     }
173   }
174   return false;
175 }
176 
177 void ARCDAGToDAGISel::Select(SDNode *N) {
178   switch (N->getOpcode()) {
179   case ISD::Constant: {
180     uint64_t CVal = N->getAsZExtVal();
181     ReplaceNode(N, CurDAG->getMachineNode(
182                        isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
183                        SDLoc(N), MVT::i32,
184                        CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
185     return;
186   }
187   }
188   SelectCode(N);
189 }
190