Skip to content

Commit

Permalink
PlaceSafepoints: use IRBuilder helpers
Browse files Browse the repository at this point in the history
Use the IRBuilder helpers for gc.statepoint and gc.result, instead of
coding the construction by hand. Note that the gc.statepoint IRBuilder
handles only CallInst, not InvokeInst; retain that part of hand-coding.

Differential Revision: http://reviews.llvm.org/D7518

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230591 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
artagnon committed Feb 26, 2015
1 parent 341f17d commit e10581a
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 45 deletions.
8 changes: 8 additions & 0 deletions include/llvm/IR/IRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,14 @@ class IRBuilderBase {
ArrayRef<Value *> GCArgs,
const Twine &Name = "");

// Conveninence function for the common case when CallArgs are filled in using
// makeArrayRef(CS.arg_begin(), .arg_end()); Use needs to be .get()'ed to get
// the Value *.
CallInst *CreateGCStatepoint(Value *ActualCallee, ArrayRef<Use> CallArgs,
ArrayRef<Value *> DeoptArgs,
ArrayRef<Value *> GCArgs,
const Twine &Name = "");

/// \brief Create a call to the experimental.gc.result intrinsic to extract
/// the result from a call wrapped in a statepoint.
CallInst *CreateGCResult(Instruction *Statepoint,
Expand Down
11 changes: 11 additions & 0 deletions lib/IR/IRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,17 @@ CallInst *IRBuilderBase::CreateGCStatepoint(Value *ActualCallee,
return createCallHelper(FnStatepoint, args, this, Name);
}

CallInst *IRBuilderBase::CreateGCStatepoint(Value *ActualCallee,
ArrayRef<Use> CallArgs,
ArrayRef<Value *> DeoptArgs,
ArrayRef<Value *> GCArgs,
const Twine &Name) {
std::vector<Value *> VCallArgs;
for (auto &U : CallArgs)
VCallArgs.push_back(U.get());
return CreateGCStatepoint(ActualCallee, VCallArgs, DeoptArgs, GCArgs, Name);
}

CallInst *IRBuilderBase::CreateGCResult(Instruction *Statepoint,
Type *ResultType,
const Twine &Name) {
Expand Down
83 changes: 39 additions & 44 deletions lib/Transforms/Scalar/PlaceSafepoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -873,37 +873,12 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
// this logic out to the initialization of the pass. Doesn't appear to
// matter in practice.

// Fill in the one generic type'd argument (the function is also vararg)
std::vector<Type *> argTypes;
argTypes.push_back(CS.getCalledValue()->getType());

Function *gc_statepoint_decl = Intrinsic::getDeclaration(
M, Intrinsic::experimental_gc_statepoint, argTypes);

// Then go ahead and use the builder do actually do the inserts. We insert
// immediately before the previous instruction under the assumption that all
// arguments will be available here. We can't insert afterwards since we may
// be replacing a terminator.
Instruction *insertBefore = CS.getInstruction();
IRBuilder<> Builder(insertBefore);
// First, create the statepoint (with all live ptrs as arguments).
std::vector<llvm::Value *> args;
// target, #call args, unused, call args..., #deopt args, deopt args..., gc args...
Value *Target = CS.getCalledValue();
args.push_back(Target);
int callArgSize = CS.arg_size();
args.push_back(
ConstantInt::get(Type::getInt32Ty(M->getContext()), callArgSize));
// TODO: add a 'Needs GC-rewrite' later flag
args.push_back(ConstantInt::get(Type::getInt32Ty(M->getContext()), 0));

// Copy all the arguments of the original call
args.insert(args.end(), CS.arg_begin(), CS.arg_end());

// # of deopt arguments: this pass currently does not support the
// identification of deopt arguments. If this is interesting to you,
// please ask on llvm-dev.
args.push_back(ConstantInt::get(Type::getInt32Ty(M->getContext()), 0));

// Note: The gc args are not filled in at this time, that's handled by
// RewriteStatepointsForGC (which is currently under review).
Expand All @@ -913,20 +888,21 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
AttributeSet return_attributes;
if (CS.isCall()) {
CallInst *toReplace = cast<CallInst>(CS.getInstruction());
CallInst *call =
Builder.CreateCall(gc_statepoint_decl, args, "safepoint_token");
call->setTailCall(toReplace->isTailCall());
call->setCallingConv(toReplace->getCallingConv());
CallInst *Call = Builder.CreateGCStatepoint(
CS.getCalledValue(), makeArrayRef(CS.arg_begin(), CS.arg_end()), None,
None, "safepoint_token");
Call->setTailCall(toReplace->isTailCall());
Call->setCallingConv(toReplace->getCallingConv());

// Before we have to worry about GC semantics, all attributes are legal
AttributeSet new_attrs = toReplace->getAttributes();
// In case if we can handle this set of sttributes - set up function attrs
// directly on statepoint and return attrs later for gc_result intrinsic.
call->setAttributes(new_attrs.getFnAttributes());
Call->setAttributes(new_attrs.getFnAttributes());
return_attributes = new_attrs.getRetAttributes();
// TODO: handle param attributes

token = call;
token = Call;

// Put the following gc_result and gc_relocate calls immediately after the
// the old call (which we're about to delete)
Expand All @@ -938,6 +914,33 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
Builder.SetCurrentDebugLocation(IP->getDebugLoc());

} else if (CS.isInvoke()) {
// TODO: make CreateGCStatepoint return an Instruction that we can cast to a
// Call or Invoke, instead of doing this junk here.

// Fill in the one generic type'd argument (the function is also
// vararg)
std::vector<Type *> argTypes;
argTypes.push_back(CS.getCalledValue()->getType());

Function *gc_statepoint_decl = Intrinsic::getDeclaration(
M, Intrinsic::experimental_gc_statepoint, argTypes);

// First, create the statepoint (with all live ptrs as arguments).
std::vector<llvm::Value *> args;
// target, #call args, unused, ... call parameters, #deopt args, ... deopt
// parameters, ... gc parameters
Value *Target = CS.getCalledValue();
args.push_back(Target);
int callArgSize = CS.arg_size();
// #call args
args.push_back(Builder.getInt32(callArgSize));
// unused
args.push_back(Builder.getInt32(0));
// call parameters
args.insert(args.end(), CS.arg_begin(), CS.arg_end());
// #deopt args: 0
args.push_back(Builder.getInt32(0));

InvokeInst *toReplace = cast<InvokeInst>(CS.getInstruction());

// Insert the new invoke into the old block. We'll remove the old one in a
Expand Down Expand Up @@ -973,19 +976,11 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */

// Only add the gc_result iff there is actually a used result
if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
Instruction *gc_result = nullptr;
std::vector<Type *> types; // one per 'any' type
types.push_back(CS.getType()); // result type
Intrinsic::ID Id = Intrinsic::experimental_gc_result;
Value *gc_result_func = Intrinsic::getDeclaration(M, Id, types);

std::vector<Value *> args;
args.push_back(token);
gc_result = Builder.CreateCall(
gc_result_func, args,
CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "");

cast<CallInst>(gc_result)->setAttributes(return_attributes);
std::string takenName =
CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
CallInst *gc_result =
Builder.CreateGCResult(token, CS.getType(), takenName);
gc_result->setAttributes(return_attributes);
return gc_result;
} else {
// No return value for the call.
Expand Down
2 changes: 1 addition & 1 deletion test/Transforms/PlaceSafepoints/basic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ define i1 @test_call_with_result() gc "statepoint-example" {
; CHECK: gc.statepoint.p0f_isVoidf
; CHECK: gc.statepoint.p0f_i1i1f
; CHECK: (i1 (i1)* @i1_return_i1, i32 1, i32 0, i1 false, i32 0)
; CHECK: gc.result.i1
; CHECK: %call12 = call i1 @llvm.experimental.gc.result.i1
entry:
%call1 = tail call i1 (i1)* @i1_return_i1(i1 false)
ret i1 %call1
Expand Down

0 comments on commit e10581a

Please sign in to comment.