Bug Summary

File:llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
Warning:line 248, column 27
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name AVRISelDAGToDAG.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/build-llvm/lib/Target/AVR -I /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR -I /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/build-llvm/include -I /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/build-llvm/lib/Target/AVR -fdebug-prefix-map=/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998=. -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -o /tmp/scan-build-2020-09-28-092409-31635-1 -x c++ /build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp

/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp

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
24namespace llvm {
25
26/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
27class AVRDAGToDAGISel : public SelectionDAGISel {
28public:
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
49private:
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
59bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
60 Subtarget = &MF.getSubtarget<AVRSubtarget>();
61 return SelectionDAGISel::runOnMachineFunction(MF);
62}
63
64bool 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
121bool 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
168unsigned 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
202bool 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__))
1
Assuming 'ConstraintCode' is equal to Constraint_m
2
'?' condition is true
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
2.1
'RegNode' is null
2.1
'RegNode' is null
&&
3
Taking false branch
219 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
220 OutOps.push_back(Op);
221 return false;
222 }
223
224 if (Op->getOpcode() == ISD::FrameIndex) {
4
Assuming the condition is false
5
Taking false branch
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) {
6
Assuming the condition is true
240 SDValue CopyFromRegOp = Op->getOperand(0);
241 SDValue ImmOp = Op->getOperand(1);
7
Value assigned to 'ImmOp.Node'
242 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
8
Calling 'dyn_cast<llvm::ConstantSDNode, llvm::SDValue>'
26
Returning from 'dyn_cast<llvm::ConstantSDNode, llvm::SDValue>'
27
'ImmNode' initialized here
243
244 unsigned Reg;
245 bool CanHandleRegImmOpt = true;
246
247 CanHandleRegImmOpt &= ImmNode != 0;
28
Assuming 'ImmNode' is equal to null
248 CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64;
29
Called C++ object pointer is null
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
308template <> 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
323template <> 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
360template <> 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
416template <> 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
456template <> 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
471bool 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
516void 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
532bool 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
551FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
552 CodeGenOpt::Level OptLevel) {
553 return new AVRDAGToDAGISel(TM, OptLevel);
554}
555
556} // end of namespace llvm
557

/build/llvm-toolchain-snapshot-12~++20200927111121+5811d723998/llvm/include/llvm/Support/Casting.h

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
23namespace 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//
33template<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
40template<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.
55template <typename To, typename From, typename Enabler = void>
56struct 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.
63template <typename To, typename From>
64struct 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
68template <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
74template <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
80template <typename To, typename From>
81struct 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
88template <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
95template <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
102template <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
109template <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
116template<typename To, typename From, typename SimpleFrom>
117struct 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
127template<typename To, typename FromTy>
128struct 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//
141template <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
146template <typename First, typename Second, typename... Rest, typename Y>
147LLVM_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//
154template <typename... X, class Y>
155LLVM_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
165template<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.
169template<class To, class From> struct cast_retty_impl {
170 using ret_type = To &; // Normal case, return Ty&
171};
172template<class To, class From> struct cast_retty_impl<To, const From> {
173 using ret_type = const To &; // Normal case, return Ty&
174};
175
176template<class To, class From> struct cast_retty_impl<To, From*> {
177 using ret_type = To *; // Pointer arg case, return Ty*
178};
179
180template<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
184template<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
188template <class To, class From>
189struct cast_retty_impl<To, std::unique_ptr<From>> {
190private:
191 using PointerType = typename cast_retty_impl<To, From *>::ret_type;
192 using ResultType = std::remove_pointer_t<PointerType>;
193
194public:
195 using ret_type = std::unique_ptr<ResultType>;
196};
197
198template<class To, class From, class SimpleFrom>
199struct 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
206template<class To, class FromTy>
207struct 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
212template<class To, class From>
213struct 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//
221template<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,
17
Calling 'cast_convert_val::doit'
20
Returning from 'cast_convert_val::doit'
21
Returning pointer
225 typename simplify_type<SimpleFrom>::SimpleType>::doit(
226 simplify_type<From>::getSimplifiedValue(Val));
15
Assigning value
16
Passing value via 1st parameter 'Val'
227 }
228};
229
230template<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
18
'Res2' initialized here
234 = (typename cast_retty<To, FromTy>::ret_type)const_cast<FromTy&>(Val);
235 return Res2;
19
Returning pointer (loaded from 'Res2')
236 }
237};
238
239template <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//
251template <class X, class Y>
252inline std::enable_if_t<!is_simple_type<Y>::value,
253 typename cast_retty<X, const Y>::ret_type>
254cast(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
260template <class X, class Y>
261inline 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__))
;
12
Assuming 'Val' is a 'ConstantSDNode'
13
'?' condition is true
263 return cast_convert_val<X, Y,
14
Calling 'cast_convert_val::doit'
22
Returning from 'cast_convert_val::doit'
23
Returning pointer
264 typename simplify_type<Y>::SimpleType>::doit(Val);
265}
266
267template <class X, class Y>
268inline 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
274template <class X, class Y>
275inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
276cast(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//
287template <class X, class Y>
288LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<
289 !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>
290cast_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
297template <class X, class Y>
298LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<!is_simple_type<Y>::value,
299 typename cast_retty<X, Y>::ret_type>
300cast_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
307template <class X, class Y>
308LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y *>::ret_type
309cast_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
315template <class X, class Y>
316inline typename cast_retty<X, std::unique_ptr<Y>>::ret_type
317cast_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
331template <class X, class Y>
332LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<
333 !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>
334dyn_cast(const Y &Val) {
335 return isa<X>(Val) ? cast<X>(Val) : nullptr;
336}
337
338template <class X, class Y>
339LLVM_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;
9
Assuming 'Val' is a 'ConstantSDNode'
10
'?' condition is true
11
Calling 'cast<llvm::ConstantSDNode, llvm::SDValue>'
24
Returning from 'cast<llvm::ConstantSDNode, llvm::SDValue>'
25
Returning pointer
341}
342
343template <class X, class Y>
344LLVM_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//
351template <class X, class Y>
352LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<
353 !is_simple_type<Y>::value, typename cast_retty<X, const Y>::ret_type>
354dyn_cast_or_null(const Y &Val) {
355 return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
356}
357
358template <class X, class Y>
359LLVM_NODISCARD[[clang::warn_unused_result]] inline std::enable_if_t<!is_simple_type<Y>::value,
360 typename cast_retty<X, Y>::ret_type>
361dyn_cast_or_null(Y &Val) {
362 return (Val && isa<X>(Val)) ? cast<X>(Val) : nullptr;
363}
364
365template <class X, class Y>
366LLVM_NODISCARD[[clang::warn_unused_result]] inline typename cast_retty<X, Y *>::ret_type
367dyn_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.
376template <class X, class Y>
377LLVM_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
384template <class X, class Y>
385LLVM_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.
391template <class X, class Y>
392LLVM_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
399template <class X, class Y>
400LLVM_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