File: | llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp |
Warning: | line 248, column 27 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===// | ||||
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 AVR target. | ||||
10 | // | ||||
11 | //===----------------------------------------------------------------------===// | ||||
12 | |||||
13 | #include "AVR.h" | ||||
14 | #include "AVRTargetMachine.h" | ||||
15 | #include "MCTargetDesc/AVRMCTargetDesc.h" | ||||
16 | |||||
17 | #include "llvm/CodeGen/MachineRegisterInfo.h" | ||||
18 | #include "llvm/CodeGen/SelectionDAGISel.h" | ||||
19 | #include "llvm/Support/Debug.h" | ||||
20 | #include "llvm/Support/raw_ostream.h" | ||||
21 | |||||
22 | #define DEBUG_TYPE"avr-isel" "avr-isel" | ||||
23 | |||||
24 | namespace llvm { | ||||
25 | |||||
26 | /// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form). | ||||
27 | class AVRDAGToDAGISel : public SelectionDAGISel { | ||||
28 | public: | ||||
29 | AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel) | ||||
30 | : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {} | ||||
31 | |||||
32 | StringRef getPassName() const override { | ||||
33 | return "AVR DAG->DAG Instruction Selection"; | ||||
34 | } | ||||
35 | |||||
36 | bool runOnMachineFunction(MachineFunction &MF) override; | ||||
37 | |||||
38 | bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp); | ||||
39 | |||||
40 | bool selectIndexedLoad(SDNode *N); | ||||
41 | unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT); | ||||
42 | |||||
43 | bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode, | ||||
44 | std::vector<SDValue> &OutOps) override; | ||||
45 | |||||
46 | // Include the pieces autogenerated from the target description. | ||||
47 | #include "AVRGenDAGISel.inc" | ||||
48 | |||||
49 | private: | ||||
50 | void Select(SDNode *N) override; | ||||
51 | bool trySelect(SDNode *N); | ||||
52 | |||||
53 | template <unsigned NodeType> bool select(SDNode *N); | ||||
54 | bool selectMultiplication(SDNode *N); | ||||
55 | |||||
56 | const AVRSubtarget *Subtarget; | ||||
57 | }; | ||||
58 | |||||
59 | bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { | ||||
60 | Subtarget = &MF.getSubtarget<AVRSubtarget>(); | ||||
61 | return SelectionDAGISel::runOnMachineFunction(MF); | ||||
62 | } | ||||
63 | |||||
64 | bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base, | ||||
65 | SDValue &Disp) { | ||||
66 | SDLoc dl(Op); | ||||
67 | auto DL = CurDAG->getDataLayout(); | ||||
68 | MVT PtrVT = getTargetLowering()->getPointerTy(DL); | ||||
69 | |||||
70 | // if the address is a frame index get the TargetFrameIndex. | ||||
71 | if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) { | ||||
72 | Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT); | ||||
73 | Disp = CurDAG->getTargetConstant(0, dl, MVT::i8); | ||||
74 | |||||
75 | return true; | ||||
76 | } | ||||
77 | |||||
78 | // Match simple Reg + uimm6 operands. | ||||
79 | if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && | ||||
80 | !CurDAG->isBaseWithConstantOffset(N)) { | ||||
81 | return false; | ||||
82 | } | ||||
83 | |||||
84 | if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | ||||
85 | int RHSC = (int)RHS->getZExtValue(); | ||||
86 | |||||
87 | // Convert negative offsets into positives ones. | ||||
88 | if (N.getOpcode() == ISD::SUB) { | ||||
89 | RHSC = -RHSC; | ||||
90 | } | ||||
91 | |||||
92 | // <#Frame index + const> | ||||
93 | // Allow folding offsets bigger than 63 so the frame pointer can be used | ||||
94 | // directly instead of copying it around by adjusting and restoring it for | ||||
95 | // each access. | ||||
96 | if (N.getOperand(0).getOpcode() == ISD::FrameIndex) { | ||||
97 | int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex(); | ||||
98 | |||||
99 | Base = CurDAG->getTargetFrameIndex(FI, PtrVT); | ||||
100 | Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16); | ||||
101 | |||||
102 | return true; | ||||
103 | } | ||||
104 | |||||
105 | // The value type of the memory instruction determines what is the maximum | ||||
106 | // offset allowed. | ||||
107 | MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT(); | ||||
108 | |||||
109 | // We only accept offsets that fit in 6 bits (unsigned). | ||||
110 | if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) { | ||||
111 | Base = N.getOperand(0); | ||||
112 | Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8); | ||||
113 | |||||
114 | return true; | ||||
115 | } | ||||
116 | } | ||||
117 | |||||
118 | return false; | ||||
119 | } | ||||
120 | |||||
121 | bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) { | ||||
122 | const LoadSDNode *LD = cast<LoadSDNode>(N); | ||||
123 | ISD::MemIndexedMode AM = LD->getAddressingMode(); | ||||
124 | MVT VT = LD->getMemoryVT().getSimpleVT(); | ||||
125 | auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout()); | ||||
126 | |||||
127 | // We only care if this load uses a POSTINC or PREDEC mode. | ||||
128 | if ((LD->getExtensionType() != ISD::NON_EXTLOAD) || | ||||
129 | (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) { | ||||
130 | |||||
131 | return false; | ||||
132 | } | ||||
133 | |||||
134 | unsigned Opcode = 0; | ||||
135 | bool isPre = (AM == ISD::PRE_DEC); | ||||
136 | int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue(); | ||||
137 | |||||
138 | switch (VT.SimpleTy) { | ||||
139 | case MVT::i8: { | ||||
140 | if ((!isPre && Offs != 1) || (isPre && Offs != -1)) { | ||||
141 | return false; | ||||
142 | } | ||||
143 | |||||
144 | Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi; | ||||
145 | break; | ||||
146 | } | ||||
147 | case MVT::i16: { | ||||
148 | if ((!isPre && Offs != 2) || (isPre && Offs != -2)) { | ||||
149 | return false; | ||||
150 | } | ||||
151 | |||||
152 | Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi; | ||||
153 | break; | ||||
154 | } | ||||
155 | default: | ||||
156 | return false; | ||||
157 | } | ||||
158 | |||||
159 | SDNode *ResNode = CurDAG->getMachineNode(Opcode, SDLoc(N), VT, | ||||
160 | PtrVT, MVT::Other, | ||||
161 | LD->getBasePtr(), LD->getChain()); | ||||
162 | ReplaceUses(N, ResNode); | ||||
163 | CurDAG->RemoveDeadNode(N); | ||||
164 | |||||
165 | return true; | ||||
166 | } | ||||
167 | |||||
168 | unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, | ||||
169 | MVT VT) { | ||||
170 | ISD::MemIndexedMode AM = LD->getAddressingMode(); | ||||
171 | |||||
172 | // Progmem indexed loads only work in POSTINC mode. | ||||
173 | if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) { | ||||
174 | return 0; | ||||
175 | } | ||||
176 | |||||
177 | unsigned Opcode = 0; | ||||
178 | int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue(); | ||||
179 | |||||
180 | switch (VT.SimpleTy) { | ||||
181 | case MVT::i8: { | ||||
182 | if (Offs != 1) { | ||||
183 | return 0; | ||||
184 | } | ||||
185 | Opcode = AVR::LPMRdZPi; | ||||
186 | break; | ||||
187 | } | ||||
188 | case MVT::i16: { | ||||
189 | if (Offs != 2) { | ||||
190 | return 0; | ||||
191 | } | ||||
192 | Opcode = AVR::LPMWRdZPi; | ||||
193 | break; | ||||
194 | } | ||||
195 | default: | ||||
196 | return 0; | ||||
197 | } | ||||
198 | |||||
199 | return Opcode; | ||||
200 | } | ||||
201 | |||||
202 | bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, | ||||
203 | unsigned ConstraintCode, | ||||
204 | std::vector<SDValue> &OutOps) { | ||||
205 | assert((ConstraintCode == InlineAsm::Constraint_m ||(((ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && "Unexpected asm memory constraint" ) ? static_cast<void> (0) : __assert_fail ("(ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && \"Unexpected asm memory constraint\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 207, __PRETTY_FUNCTION__)) | ||||
| |||||
206 | ConstraintCode == InlineAsm::Constraint_Q) &&(((ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && "Unexpected asm memory constraint" ) ? static_cast<void> (0) : __assert_fail ("(ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && \"Unexpected asm memory constraint\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 207, __PRETTY_FUNCTION__)) | ||||
207 | "Unexpected asm memory constraint")(((ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && "Unexpected asm memory constraint" ) ? static_cast<void> (0) : __assert_fail ("(ConstraintCode == InlineAsm::Constraint_m || ConstraintCode == InlineAsm::Constraint_Q) && \"Unexpected asm memory constraint\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 207, __PRETTY_FUNCTION__)); | ||||
208 | |||||
209 | MachineRegisterInfo &RI = MF->getRegInfo(); | ||||
210 | const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); | ||||
211 | const TargetLowering &TL = *STI.getTargetLowering(); | ||||
212 | SDLoc dl(Op); | ||||
213 | auto DL = CurDAG->getDataLayout(); | ||||
214 | |||||
215 | const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op); | ||||
216 | |||||
217 | // If address operand is of PTRDISPREGS class, all is OK, then. | ||||
218 | if (RegNode
| ||||
219 | RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) { | ||||
220 | OutOps.push_back(Op); | ||||
221 | return false; | ||||
222 | } | ||||
223 | |||||
224 | if (Op->getOpcode() == ISD::FrameIndex) { | ||||
225 | SDValue Base, Disp; | ||||
226 | |||||
227 | if (SelectAddr(Op.getNode(), Op, Base, Disp)) { | ||||
228 | OutOps.push_back(Base); | ||||
229 | OutOps.push_back(Disp); | ||||
230 | |||||
231 | return false; | ||||
232 | } | ||||
233 | |||||
234 | return true; | ||||
235 | } | ||||
236 | |||||
237 | // If Op is add 'register, immediate' and | ||||
238 | // register is either virtual register or register of PTRDISPREGSRegClass | ||||
239 | if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) { | ||||
240 | SDValue CopyFromRegOp = Op->getOperand(0); | ||||
241 | SDValue ImmOp = Op->getOperand(1); | ||||
242 | ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp); | ||||
243 | |||||
244 | unsigned Reg; | ||||
245 | bool CanHandleRegImmOpt = true; | ||||
246 | |||||
247 | CanHandleRegImmOpt &= ImmNode != 0; | ||||
248 | CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64; | ||||
| |||||
249 | |||||
250 | if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) { | ||||
251 | RegisterSDNode *RegNode = | ||||
252 | cast<RegisterSDNode>(CopyFromRegOp->getOperand(1)); | ||||
253 | Reg = RegNode->getReg(); | ||||
254 | CanHandleRegImmOpt &= (Register::isVirtualRegister(Reg) || | ||||
255 | AVR::PTRDISPREGSRegClass.contains(Reg)); | ||||
256 | } else { | ||||
257 | CanHandleRegImmOpt = false; | ||||
258 | } | ||||
259 | |||||
260 | // If we detect proper case - correct virtual register class | ||||
261 | // if needed and go to another inlineasm operand. | ||||
262 | if (CanHandleRegImmOpt) { | ||||
263 | SDValue Base, Disp; | ||||
264 | |||||
265 | if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) { | ||||
266 | SDLoc dl(CopyFromRegOp); | ||||
267 | |||||
268 | Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); | ||||
269 | |||||
270 | SDValue CopyToReg = | ||||
271 | CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp); | ||||
272 | |||||
273 | SDValue NewCopyFromRegOp = | ||||
274 | CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); | ||||
275 | |||||
276 | Base = NewCopyFromRegOp; | ||||
277 | } else { | ||||
278 | Base = CopyFromRegOp; | ||||
279 | } | ||||
280 | |||||
281 | if (ImmNode->getValueType(0) != MVT::i8) { | ||||
282 | Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8); | ||||
283 | } else { | ||||
284 | Disp = ImmOp; | ||||
285 | } | ||||
286 | |||||
287 | OutOps.push_back(Base); | ||||
288 | OutOps.push_back(Disp); | ||||
289 | |||||
290 | return false; | ||||
291 | } | ||||
292 | } | ||||
293 | |||||
294 | // More generic case. | ||||
295 | // Create chain that puts Op into pointer register | ||||
296 | // and return that register. | ||||
297 | Register VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); | ||||
298 | |||||
299 | SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op); | ||||
300 | SDValue CopyFromReg = | ||||
301 | CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); | ||||
302 | |||||
303 | OutOps.push_back(CopyFromReg); | ||||
304 | |||||
305 | return false; | ||||
306 | } | ||||
307 | |||||
308 | template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) { | ||||
309 | auto DL = CurDAG->getDataLayout(); | ||||
310 | |||||
311 | // Convert the frameindex into a temp instruction that will hold the | ||||
312 | // effective address of the final stack slot. | ||||
313 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | ||||
314 | SDValue TFI = | ||||
315 | CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL)); | ||||
316 | |||||
317 | CurDAG->SelectNodeTo(N, AVR::FRMIDX, | ||||
318 | getTargetLowering()->getPointerTy(DL), TFI, | ||||
319 | CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16)); | ||||
320 | return true; | ||||
321 | } | ||||
322 | |||||
323 | template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) { | ||||
324 | // Use the STD{W}SPQRr pseudo instruction when passing arguments through | ||||
325 | // the stack on function calls for further expansion during the PEI phase. | ||||
326 | const StoreSDNode *ST = cast<StoreSDNode>(N); | ||||
327 | SDValue BasePtr = ST->getBasePtr(); | ||||
328 | |||||
329 | // Early exit when the base pointer is a frame index node or a constant. | ||||
330 | if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) || | ||||
331 | BasePtr.isUndef()) { | ||||
332 | return false; | ||||
333 | } | ||||
334 | |||||
335 | const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0)); | ||||
336 | // Only stores where SP is the base pointer are valid. | ||||
337 | if (!RN || (RN->getReg() != AVR::SP)) { | ||||
338 | return false; | ||||
339 | } | ||||
340 | |||||
341 | int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue(); | ||||
342 | SDValue Chain = ST->getChain(); | ||||
343 | EVT VT = ST->getValue().getValueType(); | ||||
344 | SDLoc DL(N); | ||||
345 | SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16); | ||||
346 | SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain}; | ||||
347 | unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr; | ||||
348 | |||||
349 | SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops); | ||||
350 | |||||
351 | // Transfer memory operands. | ||||
352 | CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {ST->getMemOperand()}); | ||||
353 | |||||
354 | ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); | ||||
355 | CurDAG->RemoveDeadNode(N); | ||||
356 | |||||
357 | return true; | ||||
358 | } | ||||
359 | |||||
360 | template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) { | ||||
361 | const LoadSDNode *LD = cast<LoadSDNode>(N); | ||||
362 | if (!AVR::isProgramMemoryAccess(LD)) { | ||||
363 | // Check if the opcode can be converted into an indexed load. | ||||
364 | return selectIndexedLoad(N); | ||||
365 | } | ||||
366 | |||||
367 | assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu")((Subtarget->hasLPM() && "cannot load from program memory on this mcu" ) ? static_cast<void> (0) : __assert_fail ("Subtarget->hasLPM() && \"cannot load from program memory on this mcu\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 367, __PRETTY_FUNCTION__)); | ||||
368 | |||||
369 | // This is a flash memory load, move the pointer into R31R30 and emit | ||||
370 | // the lpm instruction. | ||||
371 | MVT VT = LD->getMemoryVT().getSimpleVT(); | ||||
372 | SDValue Chain = LD->getChain(); | ||||
373 | SDValue Ptr = LD->getBasePtr(); | ||||
374 | SDNode *ResNode; | ||||
375 | SDLoc DL(N); | ||||
376 | |||||
377 | Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue()); | ||||
378 | Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16, | ||||
379 | Chain.getValue(1)); | ||||
380 | |||||
381 | SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16); | ||||
382 | |||||
383 | // Check if the opcode can be converted into an indexed load. | ||||
384 | if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) { | ||||
385 | // It is legal to fold the load into an indexed load. | ||||
386 | ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr, | ||||
387 | RegZ); | ||||
388 | ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); | ||||
389 | } else { | ||||
390 | // Selecting an indexed load is not legal, fallback to a normal load. | ||||
391 | switch (VT.SimpleTy) { | ||||
392 | case MVT::i8: | ||||
393 | ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other, | ||||
394 | Ptr, RegZ); | ||||
395 | break; | ||||
396 | case MVT::i16: | ||||
397 | ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, | ||||
398 | MVT::Other, Ptr, RegZ); | ||||
399 | ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); | ||||
400 | break; | ||||
401 | default: | ||||
402 | llvm_unreachable("Unsupported VT!")::llvm::llvm_unreachable_internal("Unsupported VT!", "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 402); | ||||
403 | } | ||||
404 | } | ||||
405 | |||||
406 | // Transfer memory operands. | ||||
407 | CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {LD->getMemOperand()}); | ||||
408 | |||||
409 | ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); | ||||
410 | ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); | ||||
411 | CurDAG->RemoveDeadNode(N); | ||||
412 | |||||
413 | return true; | ||||
414 | } | ||||
415 | |||||
416 | template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) { | ||||
417 | SDValue InFlag; | ||||
418 | SDValue Chain = N->getOperand(0); | ||||
419 | SDValue Callee = N->getOperand(1); | ||||
420 | unsigned LastOpNum = N->getNumOperands() - 1; | ||||
421 | |||||
422 | // Direct calls are autogenerated. | ||||
423 | unsigned Op = Callee.getOpcode(); | ||||
424 | if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) { | ||||
425 | return false; | ||||
426 | } | ||||
427 | |||||
428 | // Skip the incoming flag if present | ||||
429 | if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) { | ||||
430 | --LastOpNum; | ||||
431 | } | ||||
432 | |||||
433 | SDLoc DL(N); | ||||
434 | Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag); | ||||
435 | SmallVector<SDValue, 8> Ops; | ||||
436 | Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16)); | ||||
437 | |||||
438 | // Map all operands into the new node. | ||||
439 | for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) { | ||||
440 | Ops.push_back(N->getOperand(i)); | ||||
441 | } | ||||
442 | |||||
443 | Ops.push_back(Chain); | ||||
444 | Ops.push_back(Chain.getValue(1)); | ||||
445 | |||||
446 | SDNode *ResNode = | ||||
447 | CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops); | ||||
448 | |||||
449 | ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); | ||||
450 | ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); | ||||
451 | CurDAG->RemoveDeadNode(N); | ||||
452 | |||||
453 | return true; | ||||
454 | } | ||||
455 | |||||
456 | template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) { | ||||
457 | SDValue Chain = N->getOperand(0); | ||||
458 | SDValue JmpAddr = N->getOperand(1); | ||||
459 | |||||
460 | SDLoc DL(N); | ||||
461 | // Move the destination address of the indirect branch into R31R30. | ||||
462 | Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr); | ||||
463 | SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain); | ||||
464 | |||||
465 | ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); | ||||
466 | CurDAG->RemoveDeadNode(N); | ||||
467 | |||||
468 | return true; | ||||
469 | } | ||||
470 | |||||
471 | bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) { | ||||
472 | SDLoc DL(N); | ||||
473 | MVT Type = N->getSimpleValueType(0); | ||||
474 | |||||
475 | assert(Type == MVT::i8 && "unexpected value type")((Type == MVT::i8 && "unexpected value type") ? static_cast <void> (0) : __assert_fail ("Type == MVT::i8 && \"unexpected value type\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp" , 475, __PRETTY_FUNCTION__)); | ||||
476 | |||||
477 | bool isSigned = N->getOpcode() == ISD::SMUL_LOHI; | ||||
478 | unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr; | ||||
479 | |||||
480 | SDValue Lhs = N->getOperand(0); | ||||
481 | SDValue Rhs = N->getOperand(1); | ||||
482 | SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs); | ||||
483 | SDValue InChain = CurDAG->getEntryNode(); | ||||
484 | SDValue InGlue = SDValue(Mul, 0); | ||||
485 | |||||
486 | // Copy the low half of the result, if it is needed. | ||||
487 | if (N->hasAnyUseOfValue(0)) { | ||||
488 | SDValue CopyFromLo = | ||||
489 | CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue); | ||||
490 | |||||
491 | ReplaceUses(SDValue(N, 0), CopyFromLo); | ||||
492 | |||||
493 | InChain = CopyFromLo.getValue(1); | ||||
494 | InGlue = CopyFromLo.getValue(2); | ||||
495 | } | ||||
496 | |||||
497 | // Copy the high half of the result, if it is needed. | ||||
498 | if (N->hasAnyUseOfValue(1)) { | ||||
499 | SDValue CopyFromHi = | ||||
500 | CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue); | ||||
501 | |||||
502 | ReplaceUses(SDValue(N, 1), CopyFromHi); | ||||
503 | |||||
504 | InChain = CopyFromHi.getValue(1); | ||||
505 | InGlue = CopyFromHi.getValue(2); | ||||
506 | } | ||||
507 | |||||
508 | CurDAG->RemoveDeadNode(N); | ||||
509 | |||||
510 | // We need to clear R1. This is currently done (dirtily) | ||||
511 | // using a custom inserter. | ||||
512 | |||||
513 | return true; | ||||
514 | } | ||||
515 | |||||
516 | void AVRDAGToDAGISel::Select(SDNode *N) { | ||||
517 | // If we have a custom node, we already have selected! | ||||
518 | if (N->isMachineOpcode()) { | ||||
519 | LLVM_DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("avr-isel")) { errs() << "== "; N->dump(CurDAG); errs () << "\n"; } } while (false); | ||||
520 | N->setNodeId(-1); | ||||
521 | return; | ||||
522 | } | ||||
523 | |||||
524 | // See if subclasses can handle this node. | ||||
525 | if (trySelect(N)) | ||||
526 | return; | ||||
527 | |||||
528 | // Select the default instruction | ||||
529 | SelectCode(N); | ||||
530 | } | ||||
531 | |||||
532 | bool AVRDAGToDAGISel::trySelect(SDNode *N) { | ||||
533 | unsigned Opcode = N->getOpcode(); | ||||
534 | SDLoc DL(N); | ||||
535 | |||||
536 | switch (Opcode) { | ||||
537 | // Nodes we fully handle. | ||||
538 | case ISD::FrameIndex: return select<ISD::FrameIndex>(N); | ||||
539 | case ISD::BRIND: return select<ISD::BRIND>(N); | ||||
540 | case ISD::UMUL_LOHI: | ||||
541 | case ISD::SMUL_LOHI: return selectMultiplication(N); | ||||
542 | |||||
543 | // Nodes we handle partially. Other cases are autogenerated | ||||
544 | case ISD::STORE: return select<ISD::STORE>(N); | ||||
545 | case ISD::LOAD: return select<ISD::LOAD>(N); | ||||
546 | case AVRISD::CALL: return select<AVRISD::CALL>(N); | ||||
547 | default: return false; | ||||
548 | } | ||||
549 | } | ||||
550 | |||||
551 | FunctionPass *createAVRISelDag(AVRTargetMachine &TM, | ||||
552 | CodeGenOpt::Level OptLevel) { | ||||
553 | return new AVRDAGToDAGISel(TM, OptLevel); | ||||
554 | } | ||||
555 | |||||
556 | } // end of namespace llvm | ||||
557 |
1 | //===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- 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 the isa<X>(), cast<X>(), dyn_cast<X>(), cast_or_null<X>(), |
10 | // and dyn_cast_or_null<X>() templates. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_SUPPORT_CASTING_H |
15 | #define LLVM_SUPPORT_CASTING_H |
16 | |
17 | #include "llvm/Support/Compiler.h" |
18 | #include "llvm/Support/type_traits.h" |
19 | #include <cassert> |
20 | #include <memory> |
21 | #include <type_traits> |
22 | |
23 | namespace llvm { |
24 | |
25 | //===----------------------------------------------------------------------===// |
26 | // isa<x> Support Templates |
27 | //===----------------------------------------------------------------------===// |
28 | |
29 | // Define a template that can be specialized by smart pointers to reflect the |
30 | // fact that they are automatically dereferenced, and are not involved with the |
31 | // template selection process... the default implementation is a noop. |
32 | // |
33 | template<typename From> struct simplify_type { |
34 | using SimpleType = From; // The real type this represents... |
35 | |
36 | // An accessor to get the real value... |
37 | static SimpleType &getSimplifiedValue(From &Val) { return Val; } |
38 | }; |
39 | |
40 | template<typename From> struct simplify_type<const From> { |
41 | using NonConstSimpleType = typename simplify_type<From>::SimpleType; |
42 | using SimpleType = |
43 | typename add_const_past_pointer<NonConstSimpleType>::type; |
44 | using RetType = |
45 | typename add_lvalue_reference_if_not_pointer<SimpleType>::type; |
46 | |
47 | static RetType getSimplifiedValue(const From& Val) { |
48 | return simplify_type<From>::getSimplifiedValue(const_cast<From&>(Val)); |
49 | } |
50 | }; |
51 | |
52 | // The core of the implementation of isa<X> is here; To and From should be |
53 | // the names of classes. This template can be specialized to customize the |
54 | // implementation of isa<> without rewriting it from scratch. |
55 | template <typename To, typename From, typename Enabler = void> |
56 | struct isa_impl { |
57 | static inline bool doit(const From &Val) { |
58 | return To::classof(&Val); |
59 | } |
60 | }; |
61 | |
62 | /// Always allow upcasts, and perform no dynamic check for them. |
63 | template <typename To, typename From> |
64 | struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> { |
65 | static inline bool doit(const From &) { return true; } |
66 | }; |
67 | |
68 | template <typename To, typename From> struct isa_impl_cl { |
69 | static inline bool doit(const From &Val) { |
70 | return isa_impl<To, From>::doit(Val); |
71 | } |
72 | }; |
73 | |
74 | template <typename To, typename From> struct isa_impl_cl<To, const From> { |
75 | static inline bool doit(const From &Val) { |
76 | return isa_impl<To, From>::doit(Val); |
77 | } |
78 | }; |
79 | |
80 | template <typename To, typename From> |
81 | struct isa_impl_cl<To, const std::unique_ptr<From>> { |
82 | static inline bool doit(const std::unique_ptr<From> &Val) { |
83 | assert(Val && "isa<> used on a null pointer")((Val && "isa<> used on a null pointer") ? static_cast <void> (0) : __assert_fail ("Val && \"isa<> used on a null pointer\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 83, __PRETTY_FUNCTION__)); |
84 | return isa_impl_cl<To, From>::doit(*Val); |
85 | } |
86 | }; |
87 | |
88 | template <typename To, typename From> struct isa_impl_cl<To, From*> { |
89 | static inline bool doit(const From *Val) { |
90 | assert(Val && "isa<> used on a null pointer")((Val && "isa<> used on a null pointer") ? static_cast <void> (0) : __assert_fail ("Val && \"isa<> used on a null pointer\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 90, __PRETTY_FUNCTION__)); |
91 | return isa_impl<To, From>::doit(*Val); |
92 | } |
93 | }; |
94 | |
95 | template <typename To, typename From> struct isa_impl_cl<To, From*const> { |
96 | static inline bool doit(const From *Val) { |
97 | assert(Val && "isa<> used on a null pointer")((Val && "isa<> used on a null pointer") ? static_cast <void> (0) : __assert_fail ("Val && \"isa<> used on a null pointer\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 97, __PRETTY_FUNCTION__)); |
98 | return isa_impl<To, From>::doit(*Val); |
99 | } |
100 | }; |
101 | |
102 | template <typename To, typename From> struct isa_impl_cl<To, const From*> { |
103 | static inline bool doit(const From *Val) { |
104 | assert(Val && "isa<> used on a null pointer")((Val && "isa<> used on a null pointer") ? static_cast <void> (0) : __assert_fail ("Val && \"isa<> used on a null pointer\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 104, __PRETTY_FUNCTION__)); |
105 | return isa_impl<To, From>::doit(*Val); |
106 | } |
107 | }; |
108 | |
109 | template <typename To, typename From> struct isa_impl_cl<To, const From*const> { |
110 | static inline bool doit(const From *Val) { |
111 | assert(Val && "isa<> used on a null pointer")((Val && "isa<> used on a null pointer") ? static_cast <void> (0) : __assert_fail ("Val && \"isa<> used on a null pointer\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 111, __PRETTY_FUNCTION__)); |
112 | return isa_impl<To, From>::doit(*Val); |
113 | } |
114 | }; |
115 | |
116 | template<typename To, typename From, typename SimpleFrom> |
117 | struct isa_impl_wrap { |
118 | // When From != SimplifiedType, we can simplify the type some more by using |
119 | // the simplify_type template. |
120 | static bool doit(const From &Val) { |
121 | return isa_impl_wrap<To, SimpleFrom, |
122 | typename simplify_type<SimpleFrom>::SimpleType>::doit( |
123 | simplify_type<const From>::getSimplifiedValue(Val)); |
124 | } |
125 | }; |
126 | |
127 | template<typename To, typename FromTy> |
128 | struct isa_impl_wrap<To, FromTy, FromTy> { |
129 | // When From == SimpleType, we are as simple as we are going to get. |
130 | static bool doit(const FromTy &Val) { |
131 | return isa_impl_cl<To,FromTy>::doit(Val); |
132 | } |
133 | }; |
134 | |
135 | // isa<X> - Return true if the parameter to the template is an instance of one |
136 | // of the template type arguments. Used like this: |
137 | // |
138 | // if (isa<Type>(myVal)) { ... } |
139 | // if (isa<Type0, Type1, Type2>(myVal)) { ... } |
140 | // |
141 | template <class X, class Y> LLVM_NODISCARD[[clang::warn_unused_result]] inline bool isa(const Y &Val) { |
142 | return isa_impl_wrap<X, const Y, |
143 | typename simplify_type<const Y>::SimpleType>::doit(Val); |
144 | } |
145 | |
146 | template <typename First, typename Second, typename... Rest, typename Y> |
147 | LLVM_NODISCARD[[clang::warn_unused_result]] inline bool isa(const Y &Val) { |
148 | return isa<First>(Val) || isa<Second, Rest...>(Val); |
149 | } |
150 | |
151 | // isa_and_nonnull<X> - Functionally identical to isa, except that a null value |
152 | // is accepted. |
153 | // |
154 | template <typename... X, class Y> |
155 | LLVM_NODISCARD[[clang::warn_unused_result]] inline bool isa_and_nonnull(const Y &Val) { |
156 | if (!Val) |
157 | return false; |
158 | return isa<X...>(Val); |
159 | } |
160 | |
161 | //===----------------------------------------------------------------------===// |
162 | // cast<x> Support Templates |
163 | //===----------------------------------------------------------------------===// |
164 | |
165 | template<class To, class From> struct cast_retty; |
166 | |
167 | // Calculate what type the 'cast' function should return, based on a requested |
168 | // type of To and a source type of From. |
169 | template<class To, class From> struct cast_retty_impl { |
170 | using ret_type = To &; // Normal case, return Ty& |
171 | }; |
172 | template<class To, class From> struct cast_retty_impl<To, const From> { |
173 | using ret_type = const To &; // Normal case, return Ty& |
174 | }; |
175 | |
176 | template<class To, class From> struct cast_retty_impl<To, From*> { |
177 | using ret_type = To *; // Pointer arg case, return Ty* |
178 | }; |
179 | |
180 | template<class To, class From> struct cast_retty_impl<To, const From*> { |
181 | using ret_type = const To *; // Constant pointer arg case, return const Ty* |
182 | }; |
183 | |
184 | template<class To, class From> struct cast_retty_impl<To, const From*const> { |
185 | using ret_type = const To *; // Constant pointer arg case, return const Ty* |
186 | }; |
187 | |
188 | template <class To, class From> |
189 | struct cast_retty_impl<To, std::unique_ptr<From>> { |
190 | private: |
191 | using PointerType = typename cast_retty_impl<To, From *>::ret_type; |
192 | using ResultType = std::remove_pointer_t<PointerType>; |
193 | |
194 | public: |
195 | using ret_type = std::unique_ptr<ResultType>; |
196 | }; |
197 | |
198 | template<class To, class From, class SimpleFrom> |
199 | struct cast_retty_wrap { |
200 | // When the simplified type and the from type are not the same, use the type |
201 | // simplifier to reduce the type, then reuse cast_retty_impl to get the |
202 | // resultant type. |
203 | using ret_type = typename cast_retty<To, SimpleFrom>::ret_type; |
204 | }; |
205 | |
206 | template<class To, class FromTy> |
207 | struct cast_retty_wrap<To, FromTy, FromTy> { |
208 | // When the simplified type is equal to the from type, use it directly. |
209 | using ret_type = typename cast_retty_impl<To,FromTy>::ret_type; |
210 | }; |
211 | |
212 | template<class To, class From> |
213 | struct cast_retty { |
214 | using ret_type = typename cast_retty_wrap< |
215 | To, From, typename simplify_type<From>::SimpleType>::ret_type; |
216 | }; |
217 | |
218 | // Ensure the non-simple values are converted using the simplify_type template |
219 | // that may be specialized by smart pointers... |
220 | // |
221 | template<class To, class From, class SimpleFrom> struct cast_convert_val { |
222 | // This is not a simple type, use the template to simplify it... |
223 | static typename cast_retty<To, From>::ret_type doit(From &Val) { |
224 | return cast_convert_val<To, SimpleFrom, |
225 | typename simplify_type<SimpleFrom>::SimpleType>::doit( |
226 | simplify_type<From>::getSimplifiedValue(Val)); |
227 | } |
228 | }; |
229 | |
230 | template<class To, class FromTy> struct cast_convert_val<To,FromTy,FromTy> { |
231 | // This _is_ a simple type, just cast it. |
232 | static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) { |
233 | typename cast_retty<To, FromTy>::ret_type Res2 |
234 | = (typename cast_retty<To, FromTy>::ret_type)const_cast<FromTy&>(Val); |
235 | return Res2; |
236 | } |
237 | }; |
238 | |
239 | template <class X> struct is_simple_type { |
240 | static const bool value = |
241 | std::is_same<X, typename simplify_type<X>::SimpleType>::value; |
242 | }; |
243 | |
244 | // cast<X> - Return the argument parameter cast to the specified type. This |
245 | // casting operator asserts that the type is correct, so it does not return null |
246 | // on failure. It does not allow a null argument (use cast_or_null for that). |
247 | // It is typically used like this: |
248 | // |
249 | // cast<Instruction>(myVal)->getParent() |
250 | // |
251 | template <class X, class Y> |
252 | inline std::enable_if_t<!is_simple_type<Y>::value, |
253 | typename cast_retty<X, const Y>::ret_type> |
254 | cast(const Y &Val) { |
255 | assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 255, __PRETTY_FUNCTION__)); |
256 | return cast_convert_val< |
257 | X, const Y, typename simplify_type<const Y>::SimpleType>::doit(Val); |
258 | } |
259 | |
260 | template <class X, class Y> |
261 | inline typename cast_retty<X, Y>::ret_type cast(Y &Val) { |
262 | assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 262, __PRETTY_FUNCTION__)); |
263 | return cast_convert_val<X, Y, |
264 | typename simplify_type<Y>::SimpleType>::doit(Val); |
265 | } |
266 | |
267 | template <class X, class Y> |
268 | inline typename cast_retty<X, Y *>::ret_type cast(Y *Val) { |
269 | assert(isa<X>(Val) && "cast<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 269, __PRETTY_FUNCTION__)); |
270 | return cast_convert_val<X, Y*, |
271 | typename simplify_type<Y*>::SimpleType>::doit(Val); |
272 | } |
273 | |
274 | template <class X, class Y> |
275 | inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type |
276 | cast(std::unique_ptr<Y> &&Val) { |
277 | assert(isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!")((isa<X>(Val.get()) && "cast<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val.get()) && \"cast<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 277, __PRETTY_FUNCTION__)); |
278 | using ret_type = typename cast_retty<X, std::unique_ptr<Y>>::ret_type; |
279 | return ret_type( |
280 | cast_convert_val<X, Y *, typename simplify_type<Y *>::SimpleType>::doit( |
281 | Val.release())); |
282 | } |
283 | |
284 | // cast_or_null<X> - Functionally identical to cast, except that a null value is |
285 | // accepted. |
286 | // |
287 | template <class X, class Y> |
288 | LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t< |
289 | !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> |
290 | cast_or_null(const Y &Val) { |
291 | if (!Val) |
292 | return nullptr; |
293 | assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 293, __PRETTY_FUNCTION__)); |
294 | return cast<X>(Val); |
295 | } |
296 | |
297 | template <class X, class Y> |
298 | LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<!is_simple_type<Y>::value, |
299 | typename cast_retty<X, Y>::ret_type> |
300 | cast_or_null(Y &Val) { |
301 | if (!Val) |
302 | return nullptr; |
303 | assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 303, __PRETTY_FUNCTION__)); |
304 | return cast<X>(Val); |
305 | } |
306 | |
307 | template <class X, class Y> |
308 | LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y *>::ret_type |
309 | cast_or_null(Y *Val) { |
310 | if (!Val) return nullptr; |
311 | assert(isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!")((isa<X>(Val) && "cast_or_null<Ty>() argument of incompatible type!" ) ? static_cast<void> (0) : __assert_fail ("isa<X>(Val) && \"cast_or_null<Ty>() argument of incompatible type!\"" , "/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h" , 311, __PRETTY_FUNCTION__)); |
312 | return cast<X>(Val); |
313 | } |
314 | |
315 | template <class X, class Y> |
316 | inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type |
317 | cast_or_null(std::unique_ptr<Y> &&Val) { |
318 | if (!Val) |
319 | return nullptr; |
320 | return cast<X>(std::move(Val)); |
321 | } |
322 | |
323 | // dyn_cast<X> - Return the argument parameter cast to the specified type. This |
324 | // casting operator returns null if the argument is of the wrong type, so it can |
325 | // be used to test for a type as well as cast if successful. This should be |
326 | // used in the context of an if statement like this: |
327 | // |
328 | // if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... } |
329 | // |
330 | |
331 | template <class X, class Y> |
332 | LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t< |
333 | !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> |
334 | dyn_cast(const Y &Val) { |
335 | return isa<X>(Val) ? cast<X>(Val) : nullptr; |
336 | } |
337 | |
338 | template <class X, class Y> |
339 | LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y>::ret_type dyn_cast(Y &Val) { |
340 | return isa<X>(Val) ? cast<X>(Val) : nullptr; |
341 | } |
342 | |
343 | template <class X, class Y> |
344 | LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y *>::ret_type dyn_cast(Y *Val) { |
345 | return isa<X>(Val) ? cast<X>(Val) : nullptr; |
346 | } |
347 | |
348 | // dyn_cast_or_null<X> - Functionally identical to dyn_cast, except that a null |
349 | // value is accepted. |
350 | // |
351 | template <class X, class Y> |
352 | LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t< |
353 | !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type> |
354 | dyn_cast_or_null(const Y &Val) { |
355 | return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; |
356 | } |
357 | |
358 | template <class X, class Y> |
359 | LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<!is_simple_type<Y>::value, |
360 | typename cast_retty<X, Y>::ret_type> |
361 | dyn_cast_or_null(Y &Val) { |
362 | return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; |
363 | } |
364 | |
365 | template <class X, class Y> |
366 | LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y *>::ret_type |
367 | dyn_cast_or_null(Y *Val) { |
368 | return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr; |
369 | } |
370 | |
371 | // unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>, |
372 | // taking ownership of the input pointer iff isa<X>(Val) is true. If the |
373 | // cast is successful, From refers to nullptr on exit and the casted value |
374 | // is returned. If the cast is unsuccessful, the function returns nullptr |
375 | // and From is unchanged. |
376 | template <class X, class Y> |
377 | LLVM_NODISCARD[[clang::warn_unused_result]] inline auto unique_dyn_cast(std::unique_ptr<Y> &Val) |
378 | -> decltype(cast<X>(Val)) { |
379 | if (!isa<X>(Val)) |
380 | return nullptr; |
381 | return cast<X>(std::move(Val)); |
382 | } |
383 | |
384 | template <class X, class Y> |
385 | LLVM_NODISCARD[[clang::warn_unused_result]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) { |
386 | return unique_dyn_cast<X, Y>(Val); |
387 | } |
388 | |
389 | // dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast, except that |
390 | // a null value is accepted. |
391 | template <class X, class Y> |
392 | LLVM_NODISCARD[[clang::warn_unused_result]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) |
393 | -> decltype(cast<X>(Val)) { |
394 | if (!Val) |
395 | return nullptr; |
396 | return unique_dyn_cast<X, Y>(Val); |
397 | } |
398 | |
399 | template <class X, class Y> |
400 | LLVM_NODISCARD[[clang::warn_unused_result]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) { |
401 | return unique_dyn_cast_or_null<X, Y>(Val); |
402 | } |
403 | |
404 | } // end namespace llvm |
405 | |
406 | #endif // LLVM_SUPPORT_CASTING_H |