10b57cec5SDimitry Andric //===- StatepointLowering.h - SDAGBuilder's statepoint code ---*- C++ -*---===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file includes support code use by SelectionDAGBuilder when lowering a 100b57cec5SDimitry Andric // statepoint sequence in SelectionDAG IR. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H 150b57cec5SDimitry Andric #define LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 180b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 21*fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 220b57cec5SDimitry Andric #include <cassert> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric class SelectionDAGBuilder; 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric /// This class tracks both per-statepoint and per-selectiondag information. 290b57cec5SDimitry Andric /// For each statepoint it tracks locations of it's gc valuess (incoming and 300b57cec5SDimitry Andric /// relocated) and list of gcreloc calls scheduled for visiting (this is 310b57cec5SDimitry Andric /// used for a debug mode consistency check only). The spill slot tracking 320b57cec5SDimitry Andric /// works in concert with information in FunctionLoweringInfo. 330b57cec5SDimitry Andric class StatepointLoweringState { 340b57cec5SDimitry Andric public: 350b57cec5SDimitry Andric StatepointLoweringState() = default; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric /// Reset all state tracking for a newly encountered safepoint. Also 380b57cec5SDimitry Andric /// performs some consistency checking. 390b57cec5SDimitry Andric void startNewStatepoint(SelectionDAGBuilder &Builder); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric /// Clear the memory usage of this object. This is called from 420b57cec5SDimitry Andric /// SelectionDAGBuilder::clear. We require this is never called in the 430b57cec5SDimitry Andric /// midst of processing a statepoint sequence. 440b57cec5SDimitry Andric void clear(); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric /// Returns the spill location of a value incoming to the current 470b57cec5SDimitry Andric /// statepoint. Will return SDValue() if this value hasn't been 480b57cec5SDimitry Andric /// spilled. Otherwise, the value has already been spilled and no 490b57cec5SDimitry Andric /// further action is required by the caller. getLocation(SDValue Val)500b57cec5SDimitry Andric SDValue getLocation(SDValue Val) { 510b57cec5SDimitry Andric auto I = Locations.find(Val); 520b57cec5SDimitry Andric if (I == Locations.end()) 530b57cec5SDimitry Andric return SDValue(); 540b57cec5SDimitry Andric return I->second; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric setLocation(SDValue Val,SDValue Location)570b57cec5SDimitry Andric void setLocation(SDValue Val, SDValue Location) { 580b57cec5SDimitry Andric assert(!Locations.count(Val) && 590b57cec5SDimitry Andric "Trying to allocate already allocated location"); 600b57cec5SDimitry Andric Locations[Val] = Location; 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric /// Record the fact that we expect to encounter a given gc_relocate 640b57cec5SDimitry Andric /// before the next statepoint. If we don't see it, we'll report 650b57cec5SDimitry Andric /// an assertion. scheduleRelocCall(const GCRelocateInst & RelocCall)66*fe6060f1SDimitry Andric void scheduleRelocCall(const GCRelocateInst &RelocCall) { 670b57cec5SDimitry Andric // We are not interested in lowering dead instructions. 680b57cec5SDimitry Andric if (!RelocCall.use_empty()) 690b57cec5SDimitry Andric PendingGCRelocateCalls.push_back(&RelocCall); 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric /// Remove this gc_relocate from the list we're expecting to see 730b57cec5SDimitry Andric /// before the next statepoint. If we weren't expecting to see 740b57cec5SDimitry Andric /// it, we'll report an assertion. relocCallVisited(const GCRelocateInst & RelocCall)75*fe6060f1SDimitry Andric void relocCallVisited(const GCRelocateInst &RelocCall) { 760b57cec5SDimitry Andric // We are not interested in lowering dead instructions. 770b57cec5SDimitry Andric if (RelocCall.use_empty()) 780b57cec5SDimitry Andric return; 790b57cec5SDimitry Andric auto I = llvm::find(PendingGCRelocateCalls, &RelocCall); 800b57cec5SDimitry Andric assert(I != PendingGCRelocateCalls.end() && 810b57cec5SDimitry Andric "Visited unexpected gcrelocate call"); 820b57cec5SDimitry Andric PendingGCRelocateCalls.erase(I); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // TODO: Should add consistency tracking to ensure we encounter 860b57cec5SDimitry Andric // expected gc_result calls too. 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// Get a stack slot we can use to store an value of type ValueType. This 890b57cec5SDimitry Andric /// will hopefully be a recylced slot from another statepoint. 900b57cec5SDimitry Andric SDValue allocateStackSlot(EVT ValueType, SelectionDAGBuilder &Builder); 910b57cec5SDimitry Andric reserveStackSlot(int Offset)920b57cec5SDimitry Andric void reserveStackSlot(int Offset) { 930b57cec5SDimitry Andric assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() && 940b57cec5SDimitry Andric "out of bounds"); 950b57cec5SDimitry Andric assert(!AllocatedStackSlots.test(Offset) && "already reserved!"); 960b57cec5SDimitry Andric assert(NextSlotToAllocate <= (unsigned)Offset && "consistency!"); 970b57cec5SDimitry Andric AllocatedStackSlots.set(Offset); 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric isStackSlotAllocated(int Offset)1000b57cec5SDimitry Andric bool isStackSlotAllocated(int Offset) { 1010b57cec5SDimitry Andric assert(Offset >= 0 && Offset < (int)AllocatedStackSlots.size() && 1020b57cec5SDimitry Andric "out of bounds"); 1030b57cec5SDimitry Andric return AllocatedStackSlots.test(Offset); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric private: 1070b57cec5SDimitry Andric /// Maps pre-relocation value (gc pointer directly incoming into statepoint) 1080b57cec5SDimitry Andric /// into it's location (currently only stack slots) 1090b57cec5SDimitry Andric DenseMap<SDValue, SDValue> Locations; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric /// A boolean indicator for each slot listed in the FunctionInfo as to 1120b57cec5SDimitry Andric /// whether it has been used in the current statepoint. Since we try to 1130b57cec5SDimitry Andric /// preserve stack slots across safepoints, there can be gaps in which 1140b57cec5SDimitry Andric /// slots have been allocated. 1150b57cec5SDimitry Andric SmallBitVector AllocatedStackSlots; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric /// Points just beyond the last slot known to have been allocated 1180b57cec5SDimitry Andric unsigned NextSlotToAllocate = 0; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Keep track of pending gcrelocate calls for consistency check 121*fe6060f1SDimitry Andric SmallVector<const GCRelocateInst *, 10> PendingGCRelocateCalls; 1220b57cec5SDimitry Andric }; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric } // end namespace llvm 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric #endif // LLVM_LIB_CODEGEN_SELECTIONDAG_STATEPOINTLOWERING_H 127