diff options
Diffstat (limited to 'clang/lib/CodeGen/CGVTables.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGVTables.cpp | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 3cb3d354483..3055ea3bfd7 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -166,6 +166,15 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); llvm::Function *BaseFn = cast<llvm::Function>(Callee); + // Cloning can't work if we don't have a definition. The Microsoft ABI may + // require thunks when a definition is not available. Emit an error in these + // cases. + if (!MD->isDefined()) { + CGM.ErrorUnsupported(MD, "return-adjusting thunk with variadic arguments"); + return Fn; + } + assert(!BaseFn->isDeclaration() && "cannot clone undefined variadic method"); + // Clone to thunk. llvm::ValueToValueMapTy VMap; @@ -201,6 +210,8 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, Builder.SetInsertPoint(&*ThisStore); llvm::Value *AdjustedThisPtr = CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This); + AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, + ThisStore->getOperand(0)->getType()); ThisStore->setOperand(0, AdjustedThisPtr); if (!Thunk.Return.isEmpty()) { @@ -291,14 +302,17 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, *this, LoadCXXThisAddress(), Thunk->This) : LoadCXXThis(); - if (CurFnInfo->usesInAlloca() || IsUnprototyped) { - // We don't handle return adjusting thunks, because they require us to call - // the copy constructor. For now, fall through and pretend the return - // adjustment was empty so we don't crash. + // If perfect forwarding is required a variadic method, a method using + // inalloca, or an unprototyped thunk, use musttail. Emit an error if this + // thunk requires a return adjustment, since that is impossible with musttail. + if (CurFnInfo->usesInAlloca() || CurFnInfo->isVariadic() || IsUnprototyped) { if (Thunk && !Thunk->Return.isEmpty()) { if (IsUnprototyped) CGM.ErrorUnsupported( MD, "return-adjusting thunk with incomplete parameter type"); + else if (CurFnInfo->isVariadic()) + llvm_unreachable("shouldn't try to emit musttail return-adjusting " + "thunks for variadic functions"); else CGM.ErrorUnsupported( MD, "non-trivial argument copy for return-adjusting thunk"); @@ -549,16 +563,32 @@ llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD, CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn); + // Thunks for variadic methods are special because in general variadic + // arguments cannot be perferctly forwarded. In the general case, clang + // implements such thunks by cloning the original function body. However, for + // thunks with no return adjustment on targets that support musttail, we can + // use musttail to perfectly forward the variadic arguments. + bool ShouldCloneVarArgs = false; if (!IsUnprototyped && ThunkFn->isVarArg()) { - // Varargs thunks are special; we can't just generate a call because - // we can't copy the varargs. Our implementation is rather - // expensive/sucky at the moment, so don't generate the thunk unless - // we have to. - // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly. + ShouldCloneVarArgs = true; + if (TI.Return.isEmpty()) { + switch (CGM.getTriple().getArch()) { + case llvm::Triple::x86_64: + case llvm::Triple::x86: + case llvm::Triple::aarch64: + ShouldCloneVarArgs = false; + break; + default: + break; + } + } + } + + if (ShouldCloneVarArgs) { if (UseAvailableExternallyLinkage) return ThunkFn; - ThunkFn = CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, - TI); + ThunkFn = + CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, TI); } else { // Normal thunk body generation. CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped); |