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 <cassert>
22 
23 namespace llvm {
24 
25 class CallInst;
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.
getLocation(SDValue Val)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 
setLocation(SDValue Val,SDValue Location)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.
scheduleRelocCall(const CallInst & RelocCall)66   void scheduleRelocCall(const CallInst &RelocCall) {
67     // We are not interested in lowering dead instructions.
68     if (!RelocCall.use_empty())
69       PendingGCRelocateCalls.push_back(&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.
relocCallVisited(const CallInst & RelocCall)75   void relocCallVisited(const CallInst &RelocCall) {
76     // We are not interested in lowering dead instructions.
77     if (RelocCall.use_empty())
78       return;
79     auto I = llvm::find(PendingGCRelocateCalls, &RelocCall);
80     assert(I != PendingGCRelocateCalls.end() &&
81            "Visited unexpected gcrelocate call");
82     PendingGCRelocateCalls.erase(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 
reserveStackSlot(int Offset)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 
isStackSlotAllocated(int Offset)100   bool isStackSlotAllocated(int Offset) {
101     assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() &&
102            "out of bounds");
103     return AllocatedStackSlots.test(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 CallInst *, 10> PendingGCRelocateCalls;
122 };
123 
124 } // end namespace llvm
125 
126 #endif // LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H
127