xref: /openbsd-src/gnu/llvm/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.h (revision 73471bf04ceb096474c7f0fa83b1b65c70a787a1)
109467b48Spatrick //===- StatepointLowering.h - SDAGBuilder's statepoint code ---*- C++ -*---===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file includes support code use by SelectionDAGBuilder when lowering a
1009467b48Spatrick // statepoint sequence in SelectionDAG IR.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick 
1409467b48Spatrick #ifndef LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H
1509467b48Spatrick #define LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H
1609467b48Spatrick 
1709467b48Spatrick #include "llvm/ADT/DenseMap.h"
1809467b48Spatrick #include "llvm/ADT/SmallBitVector.h"
1909467b48Spatrick #include "llvm/ADT/SmallVector.h"
2009467b48Spatrick #include "llvm/CodeGen/SelectionDAGNodes.h"
21*73471bf0Spatrick #include "llvm/IR/IntrinsicInst.h"
2209467b48Spatrick #include <cassert>
2309467b48Spatrick 
2409467b48Spatrick namespace llvm {
2509467b48Spatrick 
2609467b48Spatrick class SelectionDAGBuilder;
2709467b48Spatrick 
2809467b48Spatrick /// This class tracks both per-statepoint and per-selectiondag information.
2909467b48Spatrick /// For each statepoint it tracks locations of it's gc valuess (incoming and
3009467b48Spatrick /// relocated) and list of gcreloc calls scheduled for visiting (this is
3109467b48Spatrick /// used for a debug mode consistency check only).  The spill slot tracking
3209467b48Spatrick /// works in concert with information in FunctionLoweringInfo.
3309467b48Spatrick class StatepointLoweringState {
3409467b48Spatrick public:
3509467b48Spatrick   StatepointLoweringState() = default;
3609467b48Spatrick 
3709467b48Spatrick   /// Reset all state tracking for a newly encountered safepoint.  Also
3809467b48Spatrick   /// performs some consistency checking.
3909467b48Spatrick   void startNewStatepoint(SelectionDAGBuilder &Builder);
4009467b48Spatrick 
4109467b48Spatrick   /// Clear the memory usage of this object.  This is called from
4209467b48Spatrick   /// SelectionDAGBuilder::clear.  We require this is never called in the
4309467b48Spatrick   /// midst of processing a statepoint sequence.
4409467b48Spatrick   void clear();
4509467b48Spatrick 
4609467b48Spatrick   /// Returns the spill location of a value incoming to the current
4709467b48Spatrick   /// statepoint.  Will return SDValue() if this value hasn't been
4809467b48Spatrick   /// spilled.  Otherwise, the value has already been spilled and no
4909467b48Spatrick   /// further action is required by the caller.
getLocation(SDValue Val)5009467b48Spatrick   SDValue getLocation(SDValue Val) {
5109467b48Spatrick     auto I = Locations.find(Val);
5209467b48Spatrick     if (I == Locations.end())
5309467b48Spatrick       return SDValue();
5409467b48Spatrick     return I->second;
5509467b48Spatrick   }
5609467b48Spatrick 
setLocation(SDValue Val,SDValue Location)5709467b48Spatrick   void setLocation(SDValue Val, SDValue Location) {
5809467b48Spatrick     assert(!Locations.count(Val) &&
5909467b48Spatrick            "Trying to allocate already allocated location");
6009467b48Spatrick     Locations[Val] = Location;
6109467b48Spatrick   }
6209467b48Spatrick 
6309467b48Spatrick   /// Record the fact that we expect to encounter a given gc_relocate
6409467b48Spatrick   /// before the next statepoint.  If we don't see it, we'll report
6509467b48Spatrick   /// an assertion.
scheduleRelocCall(const GCRelocateInst & RelocCall)66*73471bf0Spatrick   void scheduleRelocCall(const GCRelocateInst &RelocCall) {
6709467b48Spatrick     // We are not interested in lowering dead instructions.
6809467b48Spatrick     if (!RelocCall.use_empty())
6909467b48Spatrick       PendingGCRelocateCalls.push_back(&RelocCall);
7009467b48Spatrick   }
7109467b48Spatrick 
7209467b48Spatrick   /// Remove this gc_relocate from the list we're expecting to see
7309467b48Spatrick   /// before the next statepoint.  If we weren't expecting to see
7409467b48Spatrick   /// it, we'll report an assertion.
relocCallVisited(const GCRelocateInst & RelocCall)75*73471bf0Spatrick   void relocCallVisited(const GCRelocateInst &RelocCall) {
7609467b48Spatrick     // We are not interested in lowering dead instructions.
7709467b48Spatrick     if (RelocCall.use_empty())
7809467b48Spatrick       return;
7909467b48Spatrick     auto I = llvm::find(PendingGCRelocateCalls, &RelocCall);
8009467b48Spatrick     assert(I != PendingGCRelocateCalls.end() &&
8109467b48Spatrick            "Visited unexpected gcrelocate call");
8209467b48Spatrick     PendingGCRelocateCalls.erase(I);
8309467b48Spatrick   }
8409467b48Spatrick 
8509467b48Spatrick   // TODO: Should add consistency tracking to ensure we encounter
8609467b48Spatrick   // expected gc_result calls too.
8709467b48Spatrick 
8809467b48Spatrick   /// Get a stack slot we can use to store an value of type ValueType.  This
8909467b48Spatrick   /// will hopefully be a recylced slot from another statepoint.
9009467b48Spatrick   SDValue allocateStackSlot(EVT ValueType, SelectionDAGBuilder &Builder);
9109467b48Spatrick 
reserveStackSlot(int Offset)9209467b48Spatrick   void reserveStackSlot(int Offset) {
9309467b48Spatrick     assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() &&
9409467b48Spatrick            "out of bounds");
9509467b48Spatrick     assert(!AllocatedStackSlots.test(Offset) && "already reserved!");
9609467b48Spatrick     assert(NextSlotToAllocate <= (unsigned)Offset && "consistency!");
9709467b48Spatrick     AllocatedStackSlots.set(Offset);
9809467b48Spatrick   }
9909467b48Spatrick 
isStackSlotAllocated(int Offset)10009467b48Spatrick   bool isStackSlotAllocated(int Offset) {
10109467b48Spatrick     assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() &&
10209467b48Spatrick            "out of bounds");
10309467b48Spatrick     return AllocatedStackSlots.test(Offset);
10409467b48Spatrick   }
10509467b48Spatrick 
10609467b48Spatrick private:
10709467b48Spatrick   /// Maps pre-relocation value (gc pointer directly incoming into statepoint)
10809467b48Spatrick   /// into it's location (currently only stack slots)
10909467b48Spatrick   DenseMap<SDValue, SDValue> Locations;
11009467b48Spatrick 
11109467b48Spatrick   /// A boolean indicator for each slot listed in the FunctionInfo as to
11209467b48Spatrick   /// whether it has been used in the current statepoint.  Since we try to
11309467b48Spatrick   /// preserve stack slots across safepoints, there can be gaps in which
11409467b48Spatrick   /// slots have been allocated.
11509467b48Spatrick   SmallBitVector AllocatedStackSlots;
11609467b48Spatrick 
11709467b48Spatrick   /// Points just beyond the last slot known to have been allocated
11809467b48Spatrick   unsigned NextSlotToAllocate = 0;
11909467b48Spatrick 
12009467b48Spatrick   /// Keep track of pending gcrelocate calls for consistency check
121*73471bf0Spatrick   SmallVector<const GCRelocateInst *, 10> PendingGCRelocateCalls;
12209467b48Spatrick };
12309467b48Spatrick 
12409467b48Spatrick } // end namespace llvm
12509467b48Spatrick 
12609467b48Spatrick #endif // LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H
127