diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 3d81afa4507..aeaa7c6816d 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -3258,6 +3258,16 @@ PPCTargetLowering::LowerCall_Darwin(SDValue Chain, SDValue Callee, false, false, 0); } + // On Darwin, R12 must contain the address of an indirect callee. This does + // not mean the MTCTR instruction must use R12; it's easier to model this as + // an extra parameter, so do that. + if (!isTailCall && + !dyn_cast(Callee) && + !dyn_cast(Callee) && + !isBLACompatibleAddress(Callee, DAG)) + RegsToPass.push_back(std::make_pair((unsigned)(isPPC64 ? PPC::X12 : + PPC::R12), Callee)); + // Build a sequence of copy-to-reg nodes chained together with token chain // and flag operands which copy the outgoing args into the appropriate regs. SDValue InFlag; diff --git a/test/CodeGen/PowerPC/2010-03-09-indirect-call.ll b/test/CodeGen/PowerPC/2010-03-09-indirect-call.ll new file mode 100644 index 00000000000..d09450950d0 --- /dev/null +++ b/test/CodeGen/PowerPC/2010-03-09-indirect-call.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -march=ppc32 -mcpu=g5 -mtriple=powerpc-apple-darwin10.0 | FileCheck %s +; ModuleID = 'nn.c' +target datalayout = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f128:64:128" +target triple = "powerpc-apple-darwin11.0" +; Indirect calls must use R12 on Darwin (i.e., R12 must contain the address of +; the function being called; the mtctr is not required to use it). + +@p = external global void (...)* ; [#uses=1] + +define void @foo() nounwind ssp { +entry: +; CHECK: mtctr r12 + %0 = load void (...)** @p, align 4 ; [#uses=1] + call void (...)* %0() nounwind + br label %return + +return: ; preds = %entry + ret void +}