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. 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 GCRelocateInst & RelocCall)66 void scheduleRelocCall(const GCRelocateInst &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 GCRelocateInst & RelocCall)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(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 GCRelocateInst *, 10> PendingGCRelocateCalls; 122 }; 123 124 } // end namespace llvm 125 126 #endif // LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H 127