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