Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -447,6 +447,14 @@ ArrayRef 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 CallArgs, + ArrayRef DeoptArgs, + ArrayRef 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, Index: lib/IR/IRBuilder.cpp =================================================================== --- lib/IR/IRBuilder.cpp +++ lib/IR/IRBuilder.cpp @@ -260,6 +260,17 @@ return createCallHelper(FnStatepoint, args, this, Name); } +CallInst *IRBuilderBase::CreateGCStatepoint(Value *ActualCallee, + ArrayRef CallArgs, + ArrayRef DeoptArgs, + ArrayRef GCArgs, + const Twine &Name) { + std::vector 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) { Index: lib/Transforms/Scalar/PlaceSafepoints.cpp =================================================================== --- lib/Transforms/Scalar/PlaceSafepoints.cpp +++ lib/Transforms/Scalar/PlaceSafepoints.cpp @@ -847,56 +847,33 @@ // 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 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 args; - // target, #args, unused, ... args, #deopt args, ... deopt args, ... gc - // paramters - Value *Target = CS.getCalledValue(); - args.push_back(Target); - int callArgSize = CS.arg_size(); - args.push_back( - ConstantInt::get(Type::getInt32Ty(M->getContext()), callArgSize)); - // unused - 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()); - - // deopt - args.push_back(ConstantInt::get(Type::getInt32Ty(M->getContext()), 0)); // Create the statepoint given all the arguments Instruction *token = nullptr; AttributeSet return_attributes; if (CS.isCall()) { CallInst *toReplace = cast(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) @@ -908,6 +885,33 @@ 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 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 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(CS.getInstruction()); // Insert the new invoke into the old block. We'll remove the old one in a @@ -943,19 +947,9 @@ // 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 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 args; - args.push_back(token); - gc_result = Builder.CreateCall( - gc_result_func, args, - CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : ""); - - cast(gc_result)->setAttributes(return_attributes); + CallInst *gc_result = + Builder.CreateGCResult(token, CS.getType(), "gcresult"); + gc_result->setAttributes(return_attributes); return gc_result; } else { // No return value for the call.