Skip to content

Commit

Permalink
[Statepoint] Sink actual_args and gc_args to GCStatepointInst [NFC]
Browse files Browse the repository at this point in the history
These are the two operand sets which are expected to survive more than another week or so.  Instead of bothering to update the deopt and gc-transition operands, we'll just wait until those are removed and delete the code.

For those following along, this is likely to be the last (major) change in this sequence for about a week.  I want to wait until all of this has been merged downstream to ensure I haven't introduced any bugs (and migrate some downstream code to the new interfaces).  Once that's done, we should be able to delete Statepoint/ImmutableStatepoint without too much work.
  • Loading branch information
preames committed May 28, 2020
1 parent 4d6cda9 commit a0d2fd4
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 34 deletions.
82 changes: 59 additions & 23 deletions llvm/include/llvm/IR/Statepoint.h
Expand Up @@ -134,6 +134,53 @@ class GCStatepointInst : public CallBase {
cast<PointerType>(getActualCalledOperand()->getType())->getElementType();
return cast<FunctionType>(CalleeTy)->getReturnType();
}


/// Return the number of arguments to the underlying call.
size_t actual_arg_size() const { return getNumCallArgs(); }
/// Return an iterator to the begining of the arguments to the underlying call
const_op_iterator actual_arg_begin() const {
assert(CallArgsBeginPos <= (int)arg_size());
return arg_begin() + CallArgsBeginPos;
}
/// Return an end iterator of the arguments to the underlying call
const_op_iterator actual_arg_end() const {
auto I = actual_arg_begin() + actual_arg_size();
assert((arg_end() - I) >= 0);
return I;
}
/// range adapter for actual call arguments
iterator_range<const_op_iterator> actual_args() const {
return make_range(actual_arg_begin(), actual_arg_end());
}

/// Returns an iterator to the begining of the argument range describing gc
/// values for the statepoint.
const_op_iterator gc_args_begin() const {
// The current format has two length prefix bundles between call args and
// start of gc args. This will be removed in the near future.
const Value *NumGCTransitionArgs = *actual_arg_end();
uint64_t NumTrans = cast<ConstantInt>(NumGCTransitionArgs)->getZExtValue();
const_op_iterator trans_end = actual_arg_end() + 1 + NumTrans;
const Value *NumDeoptArgs = *trans_end;
uint64_t NumDeopt = cast<ConstantInt>(NumDeoptArgs)->getZExtValue();
auto I = trans_end + 1 + NumDeopt;
assert((arg_end() - I) >= 0);
return I;
}

/// Return an end iterator for the gc argument range
const_op_iterator gc_args_end() const { return arg_end(); }

/// Return the operand index at which the gc args begin
unsigned gcArgsStartIdx() const {
return gc_args_begin() - op_begin();
}

/// range adapter for gc arguments
iterator_range<const_op_iterator> gc_args() const {
return make_range(gc_args_begin(), gc_args_end());
}
};

/// A wrapper around a GC intrinsic call, this provides most of the actual
Expand Down Expand Up @@ -201,28 +248,18 @@ class StatepointBase {
return getCall()->doesNotThrow() || (F ? F->doesNotThrow() : false);
}


size_t arg_size() const { return getNumCallArgs(); }
arg_iterator arg_begin() const {
assert(CallArgsBeginPos <= (int)getCall()->arg_size());
return getCall()->arg_begin() + CallArgsBeginPos;
}
arg_iterator arg_end() const {
auto I = arg_begin() + arg_size();
assert((getCall()->arg_end() - I) >= 0);
return I;
size_t arg_size() const { return getCall()->actual_arg_size(); }
arg_iterator arg_begin() const { return getCall()->actual_arg_begin(); }
arg_iterator arg_end() const { return getCall()->actual_arg_end(); }
iterator_range<arg_iterator> call_args() const {
return getCall()->actual_args();
}

ValueTy *getArgument(unsigned Index) {
assert(Index < arg_size() && "out of bounds!");
return *(arg_begin() + Index);
}

/// range adapter for call arguments
iterator_range<arg_iterator> call_args() const {
return make_range(arg_begin(), arg_end());
}

/// Return true if the call or the callee has the given attribute.
bool paramHasAttr(unsigned i, Attribute::AttrKind A) const {
Function *F = getCalledFunction();
Expand Down Expand Up @@ -274,16 +311,15 @@ class StatepointBase {
return make_range(deopt_begin(), deopt_end());
}

arg_iterator gc_args_begin() const { return deopt_end(); }
arg_iterator gc_args_end() const { return getCall()->arg_end(); }

unsigned gcArgsStartIdx() const {
return gc_args_begin() - getCall()->op_begin();
arg_iterator gc_args_begin() const {
auto I = getCall()->gc_args_begin();
assert(I == deopt_end());
return I;
}

/// range adapter for gc arguments
arg_iterator gc_args_end() const { return getCall()->gc_args_end(); }
unsigned gcArgsStartIdx() const { return getCall()->gcArgsStartIdx(); }
iterator_range<arg_iterator> gc_args() const {
return make_range(gc_args_begin(), gc_args_end());
return getCall()->gc_args();
}

/// Get list of all gc reloactes linked to this statepoint
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/SelectionDAG/StatepointLowering.cpp
Expand Up @@ -864,7 +864,7 @@ SelectionDAGBuilder::LowerStatepoint(const GCStatepointInst &I,
}
}

SI.GCArgs = ArrayRef<const Use>(ISP.gc_args_begin(), ISP.gc_args_end());
SI.GCArgs = ArrayRef<const Use>(I.gc_args_begin(), I.gc_args_end());
SI.StatepointInstr = &I;
SI.ID = I.getID();

Expand Down
19 changes: 9 additions & 10 deletions llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
Expand Up @@ -271,7 +271,7 @@ struct PartiallyConstructedSafepointRecord {

/// The *new* gc.statepoint instruction itself. This produces the token
/// that normal path gc.relocates and the gc.result are tied to.
Instruction *StatepointToken;
GCStatepointInst *StatepointToken;

/// Instruction to which exceptional gc relocates are attached
/// Makes it easier to iterate through them during relocationViaAlloca.
Expand Down Expand Up @@ -1546,7 +1546,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
}

// Create the statepoint given all the arguments
Instruction *Token = nullptr;
GCStatepointInst *Token = nullptr;
if (auto *CI = dyn_cast<CallInst>(Call)) {
CallInst *SPCall = Builder.CreateGCStatepointCall(
StatepointID, NumPatchBytes, CallTarget, Flags, CallArgs,
Expand All @@ -1562,7 +1562,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
SPCall->setAttributes(
legalizeCallAttributes(CI->getContext(), CI->getAttributes()));

Token = SPCall;
Token = cast<GCStatepointInst>(SPCall);

// Put the following gc_result and gc_relocate calls immediately after the
// the old call (which we're about to delete)
Expand All @@ -1589,7 +1589,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
SPInvoke->setAttributes(
legalizeCallAttributes(II->getContext(), II->getAttributes()));

Token = SPInvoke;
Token = cast<GCStatepointInst>(SPInvoke);

// Generate gc relocates in exceptional path
BasicBlock *UnwindBlock = II->getUnwindDest();
Expand All @@ -1604,7 +1604,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
Instruction *ExceptionalToken = UnwindBlock->getLandingPadInst();
Result.UnwindToken = ExceptionalToken;

const unsigned LiveStartIdx = Statepoint(Token).gcArgsStartIdx();
const unsigned LiveStartIdx = Token->gcArgsStartIdx();
CreateGCRelocates(LiveVariables, LiveStartIdx, BasePtrs, ExceptionalToken,
Builder);

Expand Down Expand Up @@ -1652,7 +1652,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
Result.StatepointToken = Token;

// Second, create a gc.relocate for every live variable
const unsigned LiveStartIdx = Statepoint(Token).gcArgsStartIdx();
const unsigned LiveStartIdx = Token->gcArgsStartIdx();
CreateGCRelocates(LiveVariables, LiveStartIdx, BasePtrs, Token, Builder);
}

Expand Down Expand Up @@ -2409,17 +2409,16 @@ static bool insertParsePoints(Function &F, DominatorTree &DT,
// That Value* no longer exists and we need to use the new gc_result.
// Thankfully, the live set is embedded in the statepoint (and updated), so
// we just grab that.
Statepoint Statepoint(Info.StatepointToken);
Live.insert(Live.end(), Statepoint.gc_args_begin(),
Statepoint.gc_args_end());
Live.insert(Live.end(), Info.StatepointToken->gc_args_begin(),
Info.StatepointToken->gc_args_end());
#ifndef NDEBUG
// Do some basic sanity checks on our liveness results before performing
// relocation. Relocation can and will turn mistakes in liveness results
// into non-sensical code which is must harder to debug.
// TODO: It would be nice to test consistency as well
assert(DT.isReachableFromEntry(Info.StatepointToken->getParent()) &&
"statepoint must be reachable or liveness is meaningless");
for (Value *V : Statepoint.gc_args()) {
for (Value *V : Info.StatepointToken->gc_args()) {
if (!isa<Instruction>(V))
// Non-instruction values trivial dominate all possible uses
continue;
Expand Down

0 comments on commit a0d2fd4

Please sign in to comment.