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