mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
PlaceSafepoints: use IRBuilder helpers
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
This commit is contained in:
parent
341f17d0f0
commit
e10581ac39
@ -447,6 +447,14 @@ public:
|
|||||||
ArrayRef<Value *> GCArgs,
|
ArrayRef<Value *> GCArgs,
|
||||||
const Twine &Name = "");
|
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
|
/// \brief Create a call to the experimental.gc.result intrinsic to extract
|
||||||
/// the result from a call wrapped in a statepoint.
|
/// the result from a call wrapped in a statepoint.
|
||||||
CallInst *CreateGCResult(Instruction *Statepoint,
|
CallInst *CreateGCResult(Instruction *Statepoint,
|
||||||
|
@ -260,6 +260,17 @@ CallInst *IRBuilderBase::CreateGCStatepoint(Value *ActualCallee,
|
|||||||
return createCallHelper(FnStatepoint, args, this, Name);
|
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,
|
CallInst *IRBuilderBase::CreateGCResult(Instruction *Statepoint,
|
||||||
Type *ResultType,
|
Type *ResultType,
|
||||||
const Twine &Name) {
|
const Twine &Name) {
|
||||||
|
@ -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
|
// this logic out to the initialization of the pass. Doesn't appear to
|
||||||
// matter in practice.
|
// 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
|
// Then go ahead and use the builder do actually do the inserts. We insert
|
||||||
// immediately before the previous instruction under the assumption that all
|
// immediately before the previous instruction under the assumption that all
|
||||||
// arguments will be available here. We can't insert afterwards since we may
|
// arguments will be available here. We can't insert afterwards since we may
|
||||||
// be replacing a terminator.
|
// be replacing a terminator.
|
||||||
Instruction *insertBefore = CS.getInstruction();
|
Instruction *insertBefore = CS.getInstruction();
|
||||||
IRBuilder<> Builder(insertBefore);
|
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
|
// Note: The gc args are not filled in at this time, that's handled by
|
||||||
// RewriteStatepointsForGC (which is currently under review).
|
// RewriteStatepointsForGC (which is currently under review).
|
||||||
@ -913,20 +888,21 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
|
|||||||
AttributeSet return_attributes;
|
AttributeSet return_attributes;
|
||||||
if (CS.isCall()) {
|
if (CS.isCall()) {
|
||||||
CallInst *toReplace = cast<CallInst>(CS.getInstruction());
|
CallInst *toReplace = cast<CallInst>(CS.getInstruction());
|
||||||
CallInst *call =
|
CallInst *Call = Builder.CreateGCStatepoint(
|
||||||
Builder.CreateCall(gc_statepoint_decl, args, "safepoint_token");
|
CS.getCalledValue(), makeArrayRef(CS.arg_begin(), CS.arg_end()), None,
|
||||||
call->setTailCall(toReplace->isTailCall());
|
None, "safepoint_token");
|
||||||
call->setCallingConv(toReplace->getCallingConv());
|
Call->setTailCall(toReplace->isTailCall());
|
||||||
|
Call->setCallingConv(toReplace->getCallingConv());
|
||||||
|
|
||||||
// Before we have to worry about GC semantics, all attributes are legal
|
// Before we have to worry about GC semantics, all attributes are legal
|
||||||
AttributeSet new_attrs = toReplace->getAttributes();
|
AttributeSet new_attrs = toReplace->getAttributes();
|
||||||
// In case if we can handle this set of sttributes - set up function attrs
|
// 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.
|
// 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();
|
return_attributes = new_attrs.getRetAttributes();
|
||||||
// TODO: handle param attributes
|
// TODO: handle param attributes
|
||||||
|
|
||||||
token = call;
|
token = Call;
|
||||||
|
|
||||||
// Put the following gc_result and gc_relocate calls immediately after the
|
// Put the following gc_result and gc_relocate calls immediately after the
|
||||||
// the old call (which we're about to delete)
|
// the old call (which we're about to delete)
|
||||||
@ -938,6 +914,33 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
|
|||||||
Builder.SetCurrentDebugLocation(IP->getDebugLoc());
|
Builder.SetCurrentDebugLocation(IP->getDebugLoc());
|
||||||
|
|
||||||
} else if (CS.isInvoke()) {
|
} 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());
|
InvokeInst *toReplace = cast<InvokeInst>(CS.getInstruction());
|
||||||
|
|
||||||
// Insert the new invoke into the old block. We'll remove the old one in a
|
// Insert the new invoke into the old block. We'll remove the old one in a
|
||||||
@ -973,19 +976,11 @@ static Value *ReplaceWithStatepoint(const CallSite &CS, /* to replace */
|
|||||||
|
|
||||||
// Only add the gc_result iff there is actually a used result
|
// Only add the gc_result iff there is actually a used result
|
||||||
if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
|
if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
|
||||||
Instruction *gc_result = nullptr;
|
std::string takenName =
|
||||||
std::vector<Type *> types; // one per 'any' type
|
CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
|
||||||
types.push_back(CS.getType()); // result type
|
CallInst *gc_result =
|
||||||
Intrinsic::ID Id = Intrinsic::experimental_gc_result;
|
Builder.CreateGCResult(token, CS.getType(), takenName);
|
||||||
Value *gc_result_func = Intrinsic::getDeclaration(M, Id, types);
|
gc_result->setAttributes(return_attributes);
|
||||||
|
|
||||||
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);
|
|
||||||
return gc_result;
|
return gc_result;
|
||||||
} else {
|
} else {
|
||||||
// No return value for the call.
|
// No return value for the call.
|
||||||
|
@ -74,7 +74,7 @@ define i1 @test_call_with_result() gc "statepoint-example" {
|
|||||||
; CHECK: gc.statepoint.p0f_isVoidf
|
; CHECK: gc.statepoint.p0f_isVoidf
|
||||||
; CHECK: gc.statepoint.p0f_i1i1f
|
; CHECK: gc.statepoint.p0f_i1i1f
|
||||||
; CHECK: (i1 (i1)* @i1_return_i1, i32 1, i32 0, i1 false, i32 0)
|
; 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:
|
entry:
|
||||||
%call1 = tail call i1 (i1)* @i1_return_i1(i1 false)
|
%call1 = tail call i1 (i1)* @i1_return_i1(i1 false)
|
||||||
ret i1 %call1
|
ret i1 %call1
|
||||||
|
Loading…
Reference in New Issue
Block a user