1 | //===- StatepointLowering.h - SDAGBuilder's statepoint code ---*- 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 includes support code use by SelectionDAGBuilder when lowering a |
10 | // statepoint sequence in SelectionDAG IR. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H |
15 | #define LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H |
16 | |
17 | #include "llvm/ADT/DenseMap.h" |
18 | #include "llvm/ADT/SmallBitVector.h" |
19 | #include "llvm/ADT/SmallVector.h" |
20 | #include "llvm/CodeGen/SelectionDAGNodes.h" |
21 | #include "llvm/IR/IntrinsicInst.h" |
22 | #include <cassert> |
23 | |
24 | namespace llvm { |
25 | |
26 | class SelectionDAGBuilder; |
27 | |
28 | /// This class tracks both per-statepoint and per-selectiondag information. |
29 | /// For each statepoint it tracks locations of it's gc valuess (incoming and |
30 | /// relocated) and list of gcreloc calls scheduled for visiting (this is |
31 | /// used for a debug mode consistency check only). The spill slot tracking |
32 | /// works in concert with information in FunctionLoweringInfo. |
33 | class StatepointLoweringState { |
34 | public: |
35 | StatepointLoweringState() = default; |
36 | |
37 | /// Reset all state tracking for a newly encountered safepoint. Also |
38 | /// performs some consistency checking. |
39 | void startNewStatepoint(SelectionDAGBuilder &Builder); |
40 | |
41 | /// Clear the memory usage of this object. This is called from |
42 | /// SelectionDAGBuilder::clear. We require this is never called in the |
43 | /// midst of processing a statepoint sequence. |
44 | void clear(); |
45 | |
46 | /// Returns the spill location of a value incoming to the current |
47 | /// statepoint. Will return SDValue() if this value hasn't been |
48 | /// spilled. Otherwise, the value has already been spilled and no |
49 | /// further action is required by the caller. |
50 | SDValue getLocation(SDValue Val) { |
51 | auto I = Locations.find(Val); |
52 | if (I == Locations.end()) |
53 | return SDValue(); |
54 | return I->second; |
55 | } |
56 | |
57 | void setLocation(SDValue Val, SDValue Location) { |
58 | assert(!Locations.count(Val) && |
59 | "Trying to allocate already allocated location" ); |
60 | Locations[Val] = Location; |
61 | } |
62 | |
63 | /// Record the fact that we expect to encounter a given gc_relocate |
64 | /// before the next statepoint. If we don't see it, we'll report |
65 | /// an assertion. |
66 | void scheduleRelocCall(const GCRelocateInst &RelocCall) { |
67 | // We are not interested in lowering dead instructions. |
68 | if (!RelocCall.use_empty()) |
69 | PendingGCRelocateCalls.push_back(Elt: &RelocCall); |
70 | } |
71 | |
72 | /// Remove this gc_relocate from the list we're expecting to see |
73 | /// before the next statepoint. If we weren't expecting to see |
74 | /// it, we'll report an assertion. |
75 | void relocCallVisited(const GCRelocateInst &RelocCall) { |
76 | // We are not interested in lowering dead instructions. |
77 | if (RelocCall.use_empty()) |
78 | return; |
79 | auto I = llvm::find(Range&: PendingGCRelocateCalls, Val: &RelocCall); |
80 | assert(I != PendingGCRelocateCalls.end() && |
81 | "Visited unexpected gcrelocate call" ); |
82 | PendingGCRelocateCalls.erase(CI: I); |
83 | } |
84 | |
85 | // TODO: Should add consistency tracking to ensure we encounter |
86 | // expected gc_result calls too. |
87 | |
88 | /// Get a stack slot we can use to store an value of type ValueType. This |
89 | /// will hopefully be a recylced slot from another statepoint. |
90 | SDValue allocateStackSlot(EVT ValueType, SelectionDAGBuilder &Builder); |
91 | |
92 | void reserveStackSlot(int Offset) { |
93 | assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() && |
94 | "out of bounds" ); |
95 | assert(!AllocatedStackSlots.test(Offset) && "already reserved!" ); |
96 | assert(NextSlotToAllocate <= (unsigned)Offset && "consistency!" ); |
97 | AllocatedStackSlots.set(Offset); |
98 | } |
99 | |
100 | bool isStackSlotAllocated(int Offset) { |
101 | assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() && |
102 | "out of bounds" ); |
103 | return AllocatedStackSlots.test(Idx: Offset); |
104 | } |
105 | |
106 | private: |
107 | /// Maps pre-relocation value (gc pointer directly incoming into statepoint) |
108 | /// into it's location (currently only stack slots) |
109 | DenseMap<SDValue, SDValue> Locations; |
110 | |
111 | /// A boolean indicator for each slot listed in the FunctionInfo as to |
112 | /// whether it has been used in the current statepoint. Since we try to |
113 | /// preserve stack slots across safepoints, there can be gaps in which |
114 | /// slots have been allocated. |
115 | SmallBitVector AllocatedStackSlots; |
116 | |
117 | /// Points just beyond the last slot known to have been allocated |
118 | unsigned NextSlotToAllocate = 0; |
119 | |
120 | /// Keep track of pending gcrelocate calls for consistency check |
121 | SmallVector<const GCRelocateInst *, 10> PendingGCRelocateCalls; |
122 | }; |
123 | |
124 | } // end namespace llvm |
125 | |
126 | #endif // LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H |
127 | |