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