diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -628,6 +628,8 @@ SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVASTART_ELF(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerVASTART_XPLINK(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const; SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue lowerDYNAMIC_STACKALLOC_ELF(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -3505,6 +3505,32 @@ SDValue SystemZTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { + + if (Subtarget.isTargetXPLINK64()) + return lowerVASTART_XPLINK(Op, DAG); + else + return lowerVASTART_ELF(Op, DAG); +} + +SDValue SystemZTargetLowering::lowerVASTART_XPLINK(SDValue Op, + SelectionDAG &DAG) const { + MachineFunction &MF = DAG.getMachineFunction(); + SystemZMachineFunctionInfo *FuncInfo = + MF.getInfo(); + + SDLoc DL(Op); + + // vastart just stores the address of the VarArgsFrameIndex slot into the + // memory location argument. + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); + const Value *SV = cast(Op.getOperand(2))->getValue(); + return DAG.getStore(Op.getOperand(0), DL, FR, Op.getOperand(1), + MachinePointerInfo(SV)); +} + +SDValue SystemZTargetLowering::lowerVASTART_ELF(SDValue Op, + SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); SystemZMachineFunctionInfo *FuncInfo = MF.getInfo(); @@ -3548,7 +3574,9 @@ const Value *SrcSV = cast(Op.getOperand(4))->getValue(); SDLoc DL(Op); - return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, DAG.getIntPtrConstant(32, DL), + uint32_t Sz = + Subtarget.isTargetXPLINK64() ? getTargetMachine().getPointerSize(0) : 32; + return DAG.getMemcpy(Chain, DL, DstPtr, SrcPtr, DAG.getIntPtrConstant(Sz, DL), Align(8), /*isVolatile*/ false, /*AlwaysInline*/ false, /*isTailCall*/ false, MachinePointerInfo(DstSV), MachinePointerInfo(SrcSV)); diff --git a/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll b/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll --- a/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll +++ b/llvm/test/CodeGen/SystemZ/call-zos-vararg.ll @@ -189,6 +189,40 @@ ret i64 %retval } +; Derived from C source: +; #define _VARARG_EXT_ +; #include +; +; long pass(long x, ...) { +; va_list va; +; va_start(va, x); +; long ret = va_arg(va, long); +; va_end(va); +; return ret; +; } +; +; CHECK-LABEL: pass_vararg: +; CHECK: aghi 4, -160 +; CHECK: la 0, 2208(4) +; CHECK: stg 0, 2200(4) +define hidden i64 @pass_vararg(i64 %x, ...) { +entry: + %va = alloca i8*, align 8 + %va1 = bitcast i8** %va to i8* + call void @llvm.va_start(i8* %va1) + %argp.cur = load i8*, i8** %va, align 8 + %argp.next = getelementptr inbounds i8, i8* %argp.cur, i64 8 + store i8* %argp.next, i8** %va, align 8 + %0 = bitcast i8* %argp.cur to i64* + %ret = load i64, i64* %0, align 8 + %va2 = bitcast i8** %va to i8* + call void @llvm.va_end(i8* %va2) + ret i64 %ret +} + +declare void @llvm.va_start(i8*) +declare void @llvm.va_end(i8*) + declare i64 @pass_vararg0(i64 %arg0, i64 %arg1, ...) declare i64 @pass_vararg1(fp128 %arg0, ...) declare i64 @pass_vararg2(i64 %arg0, ...)