Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3826,6 +3826,32 @@ return nullptr; } +// Try to convert VarArg calls to regular calls if the callee is a regular +// function, but is casted to a VarArg function, in case the actual arguments +// match the callee's signature. +static bool transformVarArgCast(CallSite CS) { + auto *Callee = dyn_cast(CS.getCalledValue()->stripPointerCasts()); + if (CS.getCalledValue() == Callee || !Callee) + return false; + + FunctionType *CalleeTy = Callee->getFunctionType(); + if (CalleeTy->isVarArg() || + CalleeTy->getNumParams() != CS.getNumArgOperands() || + CalleeTy->getReturnType() != CS.getFunctionType()->getReturnType()) + return false; + + // Check if operand types at the call site match the parameter types + // of the original function. + for (unsigned i = 0; i < CS.getNumArgOperands(); i++) + if (CS.getArgOperand(i)->getType() != + Callee->getFunctionType()->getParamType(i)) + return false; + + CS.mutateFunctionType(Callee->getFunctionType()); + CS.setCalledFunction(Callee); + return true; +} + // Given a call to llvm.adjust.trampoline, find and return the corresponding // call to llvm.init.trampoline if the call to the trampoline can be optimized // to a direct call to a function. Otherwise return NULL. @@ -3976,6 +4002,7 @@ if (I) return eraseInstFromFunction(*I); } + transformVarArgCast(CS); return Changed ? CS.getInstruction() : nullptr; } Index: test/Transforms/InstCombine/call.ll =================================================================== --- test/Transforms/InstCombine/call.ll +++ test/Transforms/InstCombine/call.ll @@ -287,3 +287,12 @@ ; CHECK-LABEL: @test17( ; CHECK: call i32 @pr28655(i32 0) ; CHECK: ret i32 0 + +declare void @ext_method(i8*, i32) local_unnamed_addr + +define void @test_cast_to_vararg(i8* %this) { +; CHECK-LABEL: test_cast_to_vararg +; CHECK: call void @ext_method(i8* %this, i32 42) + call void (i8*, ...) bitcast (void (i8*, i32)* @ext_method to void (i8*, ...)*)(i8* %this, i32 42) + ret void +}