Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3996,11 +3996,22 @@ if (!Callee) return false; - // The prototype of a thunk is a lie. Don't directly call such a function. + // If this is a call to a thunk function, don't remove the cast. Thunks are + // used to transparently forward all incoming parameters and outgoing return + // values, so it's important to leave the cast in place. if (Callee->hasFnAttribute("thunk")) return false; Instruction *Caller = CS.getInstruction(); + + // If this is a musttail call, the callee's prototype must match the caller's + // prototype with the exception of pointee types. The code below doesn't + // implement that, so we can't do this transform. + // TODO: Do the transform if it only requires adding pointer casts. + CallInst *CI = dyn_cast(Caller); + if (CI && CI->isMustTailCall()) + return false; + const AttributeList &CallerPAL = CS.getAttributes(); // Okay, this is a cast from a function to a different type. Unless doing so Index: llvm/test/Transforms/InstCombine/musttail-thunk.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/musttail-thunk.ll @@ -0,0 +1,32 @@ +; RUN: opt -instcombine -S < %s | FileCheck %s + +; These are both direct calls, but make sure instcombine leaves the casts +; alone. + +define i32 @call_thunk(i32 %x, i32 %y) { + %r = call i32 bitcast (void (i32, ...)* @inc_first_arg_thunk to i32 (i32, i32)*)(i32 %x, i32 %y) + ret i32 %r +} + +; CHECK-LABEL: define i32 @call_thunk(i32 %x, i32 %y) +; CHECK: %r = call i32 bitcast (void (i32, ...)* @inc_first_arg_thunk to i32 (i32, i32)*)(i32 %x, i32 %y) +; CHECK: ret i32 %r + +define internal void @inc_first_arg_thunk(i32 %arg1, ...) #0 { +entry: + %inc = add i32 %arg1, 1 + musttail call void (i32, ...) bitcast (i32 (i32, i32)* @plus to void (i32, ...)*)(i32 %inc, ...) + ret void +} + +; CHECK-LABEL: define internal void @inc_first_arg_thunk(i32 %arg1, ...) #0 +; CHECK: %inc = add i32 %arg1, 1 +; CHECK: musttail call void (i32, ...) bitcast (i32 (i32, i32)* @plus to void (i32, ...)*)(i32 %inc, ...) +; CHECK: ret void + +define internal i32 @plus(i32 %x, i32 %y) { + %r = add i32 %x, %y + ret i32 %r +} + +attributes #0 = { "thunk" }