From 7fc58a4ad8b36a0ffb9ed4a1e7bf7efd6383d478 Mon Sep 17 00:00:00 2001 From: Igor Laevsky Date: Fri, 20 Feb 2015 15:28:35 +0000 Subject: [PATCH] Generalize statepoint lowering to use ImmutableStatepoint. Move statepoint lowering into a separate function 'LowerStatepoint' which uses ImmutableStatepoint instead of a CallInst. Also related utility functions are changed to receive ImmutableCallSite. Differential Revision: http://reviews.llvm.org/D7756 llvm-svn: 230017 --- llvm/include/llvm/IR/Statepoint.h | 1 + .../lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 3 + .../CodeGen/SelectionDAG/StatepointLowering.cpp | 78 +++++++++++----------- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/llvm/include/llvm/IR/Statepoint.h b/llvm/include/llvm/IR/Statepoint.h index 8128705..38720ed 100644 --- a/llvm/include/llvm/IR/Statepoint.h +++ b/llvm/include/llvm/IR/Statepoint.h @@ -17,6 +17,7 @@ #define __LLVM_IR_STATEPOINT_H #include "llvm/ADT/iterator_range.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 30cc125..ad7411f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -20,6 +20,7 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/IR/CallSite.h" +#include "llvm/IR/Statepoint.h" #include "llvm/IR/Constants.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetLowering.h" @@ -660,6 +661,8 @@ public: /// references that need to refer to the last resulting block. void UpdateSplitBlock(MachineBasicBlock *First, MachineBasicBlock *Last); + // This function is responsible for the whole statepoint lowering process. + void LowerStatepoint(ImmutableStatepoint Statepoint); private: std::pair lowerInvokable( TargetLowering::CallLoweringInfo &CLI, diff --git a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp index f61b027..1271f6b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp @@ -223,32 +223,28 @@ static void removeDuplicatesGCPtrs(SmallVectorImpl &Bases, /// Extract call from statepoint, lower it and return pointer to the /// call node. Also update NodeMap so that getValue(statepoint) will /// reference lowered call result -static SDNode *lowerCallFromStatepoint(const CallInst &CI, +static SDNode *lowerCallFromStatepoint(ImmutableStatepoint StatepointSite, SelectionDAGBuilder &Builder) { - assert(Intrinsic::experimental_gc_statepoint == - dyn_cast(&CI)->getIntrinsicID() && - "function called must be the statepoint function"); - - ImmutableStatepoint StatepointOperands(&CI); + ImmutableCallSite CS(StatepointSite.getCallSite()); // Lower the actual call itself - This is a bit of a hack, but we want to // avoid modifying the actual lowering code. This is similiar in intent to // the LowerCallOperands mechanism used by PATCHPOINT, but is structured // differently. Hopefully, this is slightly more robust w.r.t. calling // convention, return values, and other function attributes. - Value *ActualCallee = const_cast(StatepointOperands.actualCallee()); + Value *ActualCallee = const_cast(StatepointSite.actualCallee()); std::vector Args; - CallInst::const_op_iterator arg_begin = StatepointOperands.call_args_begin(); - CallInst::const_op_iterator arg_end = StatepointOperands.call_args_end(); + CallInst::const_op_iterator arg_begin = StatepointSite.call_args_begin(); + CallInst::const_op_iterator arg_end = StatepointSite.call_args_end(); Args.insert(Args.end(), arg_begin, arg_end); // TODO: remove the creation of a new instruction! We should not be // modifying the IR (even temporarily) at this point. CallInst *Tmp = CallInst::Create(ActualCallee, Args); - Tmp->setTailCall(CI.isTailCall()); - Tmp->setCallingConv(CI.getCallingConv()); - Tmp->setAttributes(CI.getAttributes()); + Tmp->setTailCall(CS.isTailCall()); + Tmp->setCallingConv(CS.getCallingConv()); + Tmp->setAttributes(CS.getAttributes()); Builder.LowerCallTo(Tmp, Builder.getValue(ActualCallee), false); // Handle the return value of the call iff any. @@ -257,10 +253,10 @@ static SDNode *lowerCallFromStatepoint(const CallInst &CI, // The value of the statepoint itself will be the value of call itself. // We'll replace the actually call node shortly. gc_result will grab // this value. - Builder.setValue(&CI, Builder.getValue(Tmp)); + Builder.setValue(CS.getInstruction(), Builder.getValue(Tmp)); } else { // The token value is never used from here on, just generate a poison value - Builder.setValue(&CI, Builder.DAG.getIntPtrConstant(-1)); + Builder.setValue(CS.getInstruction(), Builder.DAG.getIntPtrConstant(-1)); } // Remove the fake entry we created so we don't have a hanging reference // after we delete this node. @@ -305,18 +301,11 @@ static void getIncomingStatepointGCValues(SmallVectorImpl &Bases, SmallVectorImpl &Ptrs, SmallVectorImpl &Relocs, - ImmutableCallSite Statepoint, + ImmutableStatepoint StatepointSite, SelectionDAGBuilder &Builder) { - // Search for relocated pointers. Note that working backwards from the - // gc_relocates ensures that we only get pairs which are actually relocated - // and used after the statepoint. - // TODO: This logic should probably become a utility function in Statepoint.h - for (const User *U : cast(Statepoint.getInstruction())->users()) { - if (!isGCRelocate(U)) { - continue; - } - GCRelocateOperands relocateOpers(U); - Relocs.push_back(cast(U)); + for (GCRelocateOperands relocateOpers : + StatepointSite.getRelocates(StatepointSite)) { + Relocs.push_back(relocateOpers.getUnderlyingCallSite().getInstruction()); Bases.push_back(relocateOpers.basePtr()); Ptrs.push_back(relocateOpers.derivedPtr()); } @@ -409,7 +398,7 @@ static void lowerIncomingStatepointValue(SDValue Incoming, /// statepoint. The chain nodes will have already been created and the DAG root /// will be set to the last value spilled (if any were). static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, - ImmutableStatepoint Statepoint, + ImmutableStatepoint StatepointSite, SelectionDAGBuilder &Builder) { // Lower the deopt and gc arguments for this statepoint. Layout will @@ -417,7 +406,7 @@ static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, SmallVector Bases, Ptrs, Relocations; getIncomingStatepointGCValues(Bases, Ptrs, Relocations, - Statepoint.getCallSite(), Builder); + StatepointSite, Builder); #ifndef NDEBUG // Check that each of the gc pointer and bases we've gotten out of the @@ -457,7 +446,8 @@ static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, // particular value. This is purely an optimization over the code below and // doesn't change semantics at all. It is important for performance that we // reserve slots for both deopt and gc values before lowering either. - for (auto I = Statepoint.vm_state_begin() + 1, E = Statepoint.vm_state_end(); + for (auto I = StatepointSite.vm_state_begin() + 1, + E = StatepointSite.vm_state_end(); I != E; ++I) { Value *V = *I; SDValue Incoming = Builder.getValue(V); @@ -473,13 +463,13 @@ static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, // First, prefix the list with the number of unique values to be // lowered. Note that this is the number of *Values* not the // number of SDValues required to lower them. - const int NumVMSArgs = Statepoint.numTotalVMSArgs(); + const int NumVMSArgs = StatepointSite.numTotalVMSArgs(); Ops.push_back( Builder.DAG.getTargetConstant(StackMaps::ConstantOp, MVT::i64)); Ops.push_back(Builder.DAG.getTargetConstant(NumVMSArgs, MVT::i64)); - assert(NumVMSArgs + 1 == std::distance(Statepoint.vm_state_begin(), - Statepoint.vm_state_end())); + assert(NumVMSArgs + 1 == std::distance(StatepointSite.vm_state_begin(), + StatepointSite.vm_state_end())); // The vm state arguments are lowered in an opaque manner. We do // not know what type of values are contained within. We skip the @@ -487,7 +477,8 @@ static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, // explicitly just above. We could have left it in the loop and // not done it explicitly, but it's far easier to understand this // way. - for (auto I = Statepoint.vm_state_begin() + 1, E = Statepoint.vm_state_end(); + for (auto I = StatepointSite.vm_state_begin() + 1, + E = StatepointSite.vm_state_end(); I != E; ++I) { const Value *V = *I; SDValue Incoming = Builder.getValue(V); @@ -506,28 +497,35 @@ static void lowerStatepointMetaArgs(SmallVectorImpl &Ops, lowerIncomingStatepointValue(Incoming, Ops, Builder); } } + void SelectionDAGBuilder::visitStatepoint(const CallInst &CI) { + // Check some preconditions for sanity + assert(isStatepoint(&CI) && + "function called must be the statepoint function"); + + LowerStatepoint(ImmutableStatepoint(&CI)); +} + +void SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP) { // The basic scheme here is that information about both the original call and // the safepoint is encoded in the CallInst. We create a temporary call and // lower it, then reverse engineer the calling sequence. - // Check some preconditions for sanity - assert(isStatepoint(&CI) && - "function called must be the statepoint function"); NumOfStatepoints++; // Clear state StatepointLowering.startNewStatepoint(*this); + ImmutableCallSite CS(ISP.getCallSite()); + #ifndef NDEBUG // Consistency check - for (const User *U : CI.users()) { + for (const User *U : CS->users()) { const CallInst *Call = cast(U); if (isGCRelocate(Call)) StatepointLowering.scheduleRelocCall(*Call); } #endif - ImmutableStatepoint ISP(&CI); #ifndef NDEBUG // If this is a malformed statepoint, report it early to simplify debugging. // This should catch any IR level mistake that's made when constructing or @@ -550,7 +548,7 @@ void SelectionDAGBuilder::visitStatepoint(const CallInst &CI) { lowerStatepointMetaArgs(LoweredArgs, ISP, *this); // Get call node, we will replace it later with statepoint - SDNode *CallNode = lowerCallFromStatepoint(CI, *this); + SDNode *CallNode = lowerCallFromStatepoint(ISP, *this); // Construct the actual STATEPOINT node with all the appropriate arguments // and return values. @@ -587,8 +585,8 @@ void SelectionDAGBuilder::visitStatepoint(const CallInst &CI) { // Add a leading constant argument with the Flags and the calling convention // masked together - CallingConv::ID CallConv = CI.getCallingConv(); - int Flags = dyn_cast(CI.getArgOperand(2))->getZExtValue(); + CallingConv::ID CallConv = CS.getCallingConv(); + int Flags = dyn_cast(CS.getArgument(2))->getZExtValue(); assert(Flags == 0 && "not expected to be used"); Ops.push_back(DAG.getTargetConstant(StackMaps::ConstantOp, MVT::i64)); Ops.push_back( -- 2.7.4