diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 16e69c0b0d0..3bf5463efe1 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1733,6 +1733,32 @@ static bool canSinkInstructions( })) return false; + // For calls to be sinkable, they must all be indirect, or have same callee. + // I.e. if we have two direct calls to different callees, we don't want to + // turn that into an indirect call. Likewise, if we have an indirect call, + // and a direct call, we don't actually want to have a single indirect call. + if (isa(I0)) { + auto IsIndirectCall = [](const Instruction *I) { + return cast(I)->isIndirectCall(); + }; + bool HaveIndirectCalls = any_of(Insts, IsIndirectCall); + bool AllCallsAreIndirect = all_of(Insts, IsIndirectCall); + if (HaveIndirectCalls) { + if (!AllCallsAreIndirect) + return false; + } else { + // All callees must be identical. + Value *Callee = nullptr; + for (const Instruction *I : Insts) { + Value *CurrCallee = cast(I)->getCalledOperand(); + if (!Callee) + Callee = CurrCallee; + else if (Callee != CurrCallee) + return false; + } + } + } + for (unsigned OI = 0, OE = I0->getNumOperands(); OI != OE; ++OI) { Value *Op = I0->getOperand(OI); if (Op->getType()->isTokenTy()) @@ -1748,11 +1774,6 @@ static bool canSinkInstructions( !canReplaceOperandWithVariable(I0, OI)) // We can't create a PHI from this GEP. return false; - // Don't create indirect calls! The called value is the final operand. - if (isa(I0) && OI == OE - 1) { - // FIXME: if the call was *already* indirect, we should do this. - return false; - } for (auto *I : Insts) PHIOperands[I].push_back(I->getOperand(OI)); } diff --git a/test/Transforms/SimplifyCFG/X86/sink-common-code.ll b/test/Transforms/SimplifyCFG/X86/sink-common-code.ll index 84b7f75ab03..5c7f5d07ef0 100644 --- a/test/Transforms/SimplifyCFG/X86/sink-common-code.ll +++ b/test/Transforms/SimplifyCFG/X86/sink-common-code.ll @@ -1409,14 +1409,9 @@ end: define void @indirect_caller(i1 %c, i32 %v, void (i32)* %foo, void (i32)* %bar) { ; CHECK-LABEL: @indirect_caller( -; CHECK-NEXT: br i1 [[C:%.*]], label [[CALL_FOO:%.*]], label [[CALL_BAR:%.*]] -; CHECK: call_foo: -; CHECK-NEXT: tail call void [[FOO:%.*]](i32 [[V:%.*]]) -; CHECK-NEXT: br label [[END:%.*]] -; CHECK: call_bar: -; CHECK-NEXT: tail call void [[BAR:%.*]](i32 [[V]]) -; CHECK-NEXT: br label [[END]] -; CHECK: end: +; CHECK-NEXT: end: +; CHECK-NEXT: [[BAR_SINK:%.*]] = select i1 [[C:%.*]], void (i32)* [[FOO:%.*]], void (i32)* [[BAR:%.*]] +; CHECK-NEXT: tail call void [[BAR_SINK]](i32 [[V:%.*]]) ; CHECK-NEXT: ret void ; br i1 %c, label %call_foo, label %call_bar