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