Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -176,7 +176,6 @@ SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG, const SparcTargetLowering &TLI) const ; - unsigned getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const; SDValue withTargetFlags(SDValue Op, unsigned TF, SelectionDAG &DAG) const; SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF, SelectionDAG &DAG) const; Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -780,6 +780,7 @@ const unsigned StackOffset = 92; bool hasStructRetAttr = false; + unsigned SRetArgSize = 0; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size(); i != e; @@ -824,6 +825,11 @@ MemOpChains.push_back( DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo())); hasStructRetAttr = true; + // sret only allowed on first argument + assert(Outs[realArgIdx].OrigArgIndex == 0); + PointerType *Ty = cast(CLI.getArgs()[0].Ty); + Type *ElementTy = Ty->getElementType(); + SRetArgSize = DAG.getDataLayout().getTypeAllocSize(ElementTy); continue; } @@ -932,7 +938,6 @@ InFlag = Chain.getValue(1); } - unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0; bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); // If the callee is a GlobalAddress node (quite common, every direct call is) @@ -1032,51 +1037,6 @@ report_fatal_error("Invalid register name global variable"); } -// This functions returns true if CalleeName is a ABI function that returns -// a long double (fp128). -static bool isFP128ABICall(const char *CalleeName) -{ - static const char *const ABICalls[] = - { "_Q_add", "_Q_sub", "_Q_mul", "_Q_div", - "_Q_sqrt", "_Q_neg", - "_Q_itoq", "_Q_stoq", "_Q_dtoq", "_Q_utoq", - "_Q_lltoq", "_Q_ulltoq", - nullptr - }; - for (const char * const *I = ABICalls; *I != nullptr; ++I) - if (strcmp(CalleeName, *I) == 0) - return true; - return false; -} - -unsigned -SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const -{ - const Function *CalleeFn = nullptr; - if (GlobalAddressSDNode *G = dyn_cast(Callee)) { - CalleeFn = dyn_cast(G->getGlobal()); - } else if (ExternalSymbolSDNode *E = - dyn_cast(Callee)) { - const Function &F = DAG.getMachineFunction().getFunction(); - const Module *M = F.getParent(); - const char *CalleeName = E->getSymbol(); - CalleeFn = M->getFunction(CalleeName); - if (!CalleeFn && isFP128ABICall(CalleeName)) - return 16; // Return sizeof(fp128) - } - - if (!CalleeFn) - return 0; - - // It would be nice to check for the sret attribute on CalleeFn here, - // but since it is not part of the function type, any check will misfire. - - PointerType *Ty = cast(CalleeFn->arg_begin()->getType()); - Type *ElementTy = Ty->getElementType(); - return DAG.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 Index: test/CodeGen/SPARC/cast-sret-func.ll =================================================================== --- /dev/null +++ test/CodeGen/SPARC/cast-sret-func.ll @@ -0,0 +1,17 @@ +; RUN: llc < %s -march=sparc + +; CHECK: call func +; CHECK: st %i0, [%sp+64] +; CHECK: unimp 8 + +%struct = type { i32, i32 } + +define void @test() nounwind { +entry: + %tmp = alloca %struct, align 4 + call void bitcast (void ()* @func to void (%struct*)*) + (%struct* nonnull sret %tmp) + ret void +} + +declare void @func() Index: test/CodeGen/SPARC/fp128.ll =================================================================== --- test/CodeGen/SPARC/fp128.ll +++ test/CodeGen/SPARC/fp128.ll @@ -14,9 +14,13 @@ ; HARD: fmulq [[R4]], [[R5:.+]], [[R6:.+]] ; HARD: fdivq [[R6]], [[R2]] ; SOFT: call _Q_add +; SOFT: unimp 16 ; SOFT: call _Q_sub +; SOFT: unimp 16 ; SOFT: call _Q_mul +; SOFT: unimp 16 ; SOFT: call _Q_div +; SOFT: unimp 16 ; CHECK: std ; CHECK: std @@ -101,6 +105,7 @@ ; CHECK-LABEL: int_to_f128: ; HARD: fitoq ; SOFT: _Q_itoq +; SOFT: unimp 16 define void @int_to_f128(fp128* noalias sret %scalar.result, i32 %i) { entry: @@ -113,6 +118,7 @@ ; CHECK: ldub ; HARD: faddq ; SOFT: call _Q_add +; SOFT: unimp 16 ; CHECK: stb ; CHECK: ret @@ -128,6 +134,7 @@ ; CHECK-LABEL: uint_to_f128: ; HARD: fdtoq ; SOFT: _Q_utoq +; SOFT: unimp 16 define void @uint_to_f128(fp128* noalias sret %scalar.result, i32 %i) { entry: @@ -159,8 +166,10 @@ ; HARD-DAG: fitoq ; HARD-DAG: fqtoi ; SOFT-DAG: call _Q_lltoq +; SOFT-DAG: unimp 16 ; SOFT-DAG: call _Q_qtoll ; SOFT-DAG: call _Q_itoq +; SOFT-DAG: unimp 16 ; SOFT-DAG: call _Q_qtoi define void @test_itoq_qtoi(i64 %a, i32 %b, fp128* %c, fp128* %d, i64* %ptr0, fp128* %ptr1) { @@ -185,6 +194,7 @@ ; HARD-DAG: fdtoq ; HARD-DAG: fqtoi ; SOFT-DAG: call _Q_utoq +; SOFT-DAG: unimp 16 ; SOFT-DAG: call _Q_qtou define void @test_utoq_qtou(i64 %a, i32 %b, fp128* %c, fp128* %d, i64* %ptr0, fp128* %ptr1) {