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 | static char ID; |
45 | |
46 | ARCDAGToDAGISel() = delete; |
47 | |
48 | ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) |
49 | : SelectionDAGISel(ID, TM, OptLevel) {} |
50 | |
51 | void Select(SDNode *N) override; |
52 | |
53 | // Complex Pattern Selectors. |
54 | bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); |
55 | bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); |
56 | bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); |
57 | bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); |
58 | |
59 | // Include the pieces autogenerated from the target description. |
60 | #include "ARCGenDAGISel.inc" |
61 | }; |
62 | |
63 | char ARCDAGToDAGISel::ID; |
64 | |
65 | } // end anonymous namespace |
66 | |
67 | INITIALIZE_PASS(ARCDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) |
68 | |
69 | /// This pass converts a legalized DAG into a ARC-specific DAG, ready for |
70 | /// instruction scheduling. |
71 | FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, |
72 | CodeGenOptLevel OptLevel) { |
73 | return new ARCDAGToDAGISel(TM, OptLevel); |
74 | } |
75 | |
76 | bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, |
77 | SDValue &Offset) { |
78 | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { |
79 | Base = Addr.getOperand(i: 0); |
80 | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); |
81 | return true; |
82 | } |
83 | return false; |
84 | } |
85 | |
86 | bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, |
87 | SDValue &Offset) { |
88 | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { |
89 | return false; |
90 | } |
91 | |
92 | if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && |
93 | !CurDAG->isBaseWithConstantOffset(Op: Addr)) { |
94 | if (Addr.getOpcode() == ISD::FrameIndex) { |
95 | // Match frame index. |
96 | int FI = cast<FrameIndexSDNode>(Val&: Addr)->getIndex(); |
97 | Base = CurDAG->getTargetFrameIndex( |
98 | FI, VT: TLI->getPointerTy(DL: CurDAG->getDataLayout())); |
99 | } else { |
100 | Base = Addr; |
101 | } |
102 | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); |
103 | return true; |
104 | } |
105 | |
106 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))) { |
107 | int32_t RHSC = RHS->getSExtValue(); |
108 | if (Addr.getOpcode() == ISD::SUB) |
109 | RHSC = -RHSC; |
110 | |
111 | // Do we need more than 9 bits to encode? |
112 | if (!isInt<9>(x: RHSC)) |
113 | return false; |
114 | Base = Addr.getOperand(i: 0); |
115 | if (Base.getOpcode() == ISD::FrameIndex) { |
116 | int FI = cast<FrameIndexSDNode>(Val&: Base)->getIndex(); |
117 | Base = CurDAG->getTargetFrameIndex( |
118 | FI, VT: TLI->getPointerTy(DL: CurDAG->getDataLayout())); |
119 | } |
120 | Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); |
121 | return true; |
122 | } |
123 | Base = Addr; |
124 | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); |
125 | return true; |
126 | } |
127 | |
128 | bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, |
129 | SDValue &Offset) { |
130 | if (SelectAddrModeS9(Addr, Base, Offset)) |
131 | return false; |
132 | if (Addr.getOpcode() == ARCISD::GAWRAPPER) { |
133 | return false; |
134 | } |
135 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))) { |
136 | int32_t RHSC = RHS->getSExtValue(); |
137 | if (Addr.getOpcode() == ISD::SUB) |
138 | RHSC = -RHSC; |
139 | Base = Addr.getOperand(i: 0); |
140 | Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); |
141 | return true; |
142 | } |
143 | return false; |
144 | } |
145 | |
146 | // Is this a legal frame index addressing expression. |
147 | bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, |
148 | SDValue &Offset) { |
149 | FrameIndexSDNode *FIN = nullptr; |
150 | if ((FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr))) { |
151 | Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), MVT::VT: i32); |
152 | Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); |
153 | return true; |
154 | } |
155 | if (Addr.getOpcode() == ISD::ADD) { |
156 | ConstantSDNode *CN = nullptr; |
157 | if ((FIN = dyn_cast<FrameIndexSDNode>(Val: Addr.getOperand(i: 0))) && |
158 | (CN = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1))) && |
159 | (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { |
160 | // Constant positive word offset from frame index |
161 | Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), MVT::VT: i32); |
162 | Offset = |
163 | CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); |
164 | return true; |
165 | } |
166 | } |
167 | return false; |
168 | } |
169 | |
170 | void ARCDAGToDAGISel::Select(SDNode *N) { |
171 | switch (N->getOpcode()) { |
172 | case ISD::Constant: { |
173 | uint64_t CVal = N->getAsZExtVal(); |
174 | ReplaceNode(N, CurDAG->getMachineNode( |
175 | isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, |
176 | SDLoc(N), MVT::i32, |
177 | CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); |
178 | return; |
179 | } |
180 | } |
181 | SelectCode(N); |
182 | } |
183 | |