From ddb14ce76cbdf682d95765aa1e576fafeec180ae Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Sun, 21 Apr 2013 21:36:49 +0000 Subject: [PATCH] Passing arguments to varags functions under the SPARC v9 ABI. Arguments after the fixed arguments never use the floating point registers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179987 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Sparc/SparcISelLowering.cpp | 47 ++++++++++++++++++++++++++ test/CodeGen/SPARC/varargs.ll | 13 +++++++ 2 files changed, 60 insertions(+) diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index e839d45d1e3..3863e2cc1ca 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -931,6 +931,49 @@ SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const return getDataLayout()->getTypeAllocSize(ElementTy); } + +// Fixup floating point arguments in the ... part of a varargs call. +// +// The SPARC v9 ABI requires that floating point arguments are treated the same +// as integers when calling a varargs function. This does not apply to the +// fixed arguments that are part of the function's prototype. +// +// This function post-processes a CCValAssign array created by +// AnalyzeCallOperands(). +static void fixupVariableFloatArgs(SmallVectorImpl &ArgLocs, + ArrayRef Outs) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + const CCValAssign &VA = ArgLocs[i]; + // FIXME: What about f32 arguments? C promotes them to f64 when calling + // varargs functions. + if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64) + continue; + // The fixed arguments to a varargs function still go in FP registers. + if (Outs[VA.getValNo()].IsFixed) + continue; + + // This floating point argument should be reassigned. + CCValAssign NewVA; + + // Determine the offset into the argument array. + unsigned Offset = 8 * (VA.getLocReg() - SP::D0); + assert(Offset < 16*8 && "Offset out of range, bad register enum?"); + + if (Offset < 6*8) { + // This argument should go in %i0-%i5. + unsigned IReg = SP::I0 + Offset/8; + // Full register, just bitconvert into i64. + NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), + IReg, MVT::i64, CCValAssign::BCvt); + } else { + // This needs to go to memory, we're out of integer registers. + NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(), + Offset, VA.getLocVT(), VA.getLocInfo()); + } + ArgLocs[i] = NewVA; + } +} + // Lower a call for the 64-bit ABI. SDValue SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, @@ -954,6 +997,10 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, // Keep stack frames 16-byte aligned. ArgsSize = RoundUpToAlignment(ArgsSize, 16); + // Varargs calls require special treatment. + if (CLI.IsVarArg) + fixupVariableFloatArgs(ArgLocs, CLI.Outs); + // Adjust the stack pointer to make room for the arguments. // FIXME: Use hasReservedCallFrame to avoid %sp adjustments around all calls // with more than 6 arguments. diff --git a/test/CodeGen/SPARC/varargs.ll b/test/CodeGen/SPARC/varargs.ll index 2f832943a7f..b13f90e6ca7 100644 --- a/test/CodeGen/SPARC/varargs.ll +++ b/test/CodeGen/SPARC/varargs.ll @@ -60,3 +60,16 @@ sw.default: } declare void @llvm.va_start(i8*) + +@.str = private unnamed_addr constant [4 x i8] c"abc\00", align 1 + +; CHECK: call_1d +; The fixed-arg double goes in %d2, the second goes in %o2. +; CHECK: sethi 1048576 +; CHECK: , %o2 +; CHECK: , %f2 +define i32 @call_1d() #0 { +entry: + %call = call double (i8*, double, ...)* @varargsfunc(i8* undef, double 1.000000e+00, double 2.000000e+00) + ret i32 1 +} -- 2.34.1