From a46f82dbf94e970f6e61b56a7da8bb19d217f31a Mon Sep 17 00:00:00 2001 From: Timur Iskhodzhanov Date: Thu, 28 Mar 2013 21:30:04 +0000 Subject: Make Win32 put the SRet address into EAX, fixes PR15556 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178291 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FastISel.cpp | 10 +++-- lib/Target/X86/X86ISelLowering.cpp | 15 +++++--- test/CodeGen/X86/win32_sret.ll | 78 ++++++++++++++++++++++++++++++++------ 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index 85155f55e0..c5da0b9b16 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -816,14 +816,16 @@ bool X86FastISel::X86SelectRet(const Instruction *I) { // The x86-64 ABI for returning structs by value requires that we copy // the sret argument into %rax for the return. We saved the argument into // a virtual register in the entry block, so now we copy the value out - // and into %rax. - if (Subtarget->is64Bit() && F.hasStructRetAttr()) { + // and into %rax. We also do the same with %eax for Win32. + if (F.hasStructRetAttr() && + (Subtarget->is64Bit() || Subtarget->isTargetWindows())) { unsigned Reg = X86MFInfo->getSRetReturnReg(); assert(Reg && "SRetReturnReg should have been set in LowerFormalArguments()!"); + unsigned RetReg = Subtarget->is64Bit() ? X86::RAX : X86::EAX; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), - X86::RAX).addReg(Reg); - RetRegs.push_back(X86::RAX); + RetReg).addReg(Reg); + RetRegs.push_back(RetReg); } // Now emit the RET. diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 0eaab0f818..bff5426f90 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1666,10 +1666,11 @@ X86TargetLowering::LowerReturn(SDValue Chain, // The x86-64 ABIs require that for returning structs by value we copy // the sret argument into %rax/%eax (depending on ABI) for the return. + // Win32 requires us to put the sret argument to %eax as well. // We saved the argument into a virtual register in the entry block, // so now we copy the value out and into %rax/%eax. - if (Subtarget->is64Bit() && - DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { + if (DAG.getMachineFunction().getFunction()->hasStructRetAttr() && + (Subtarget->is64Bit() || Subtarget->isTargetWindows())) { MachineFunction &MF = DAG.getMachineFunction(); X86MachineFunctionInfo *FuncInfo = MF.getInfo(); unsigned Reg = FuncInfo->getSRetReturnReg(); @@ -1677,12 +1678,14 @@ X86TargetLowering::LowerReturn(SDValue Chain, "SRetReturnReg should have been set in LowerFormalArguments()."); SDValue Val = DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy()); - unsigned RetValReg = Subtarget->isTarget64BitILP32() ? X86::EAX : X86::RAX; + unsigned RetValReg + = (Subtarget->is64Bit() && !Subtarget->isTarget64BitILP32()) ? + X86::RAX : X86::EAX; Chain = DAG.getCopyToReg(Chain, dl, RetValReg, Val, Flag); Flag = Chain.getValue(1); // RAX/EAX now acts like a return value. - RetOps.push_back(DAG.getRegister(RetValReg, MVT::i64)); + RetOps.push_back(DAG.getRegister(RetValReg, getPointerTy())); } RetOps[0] = Chain; // Update chain. @@ -2036,9 +2039,11 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, // The x86-64 ABIs require that for returning structs by value we copy // the sret argument into %rax/%eax (depending on ABI) for the return. + // Win32 requires us to put the sret argument to %eax as well. // Save the argument into a virtual register so that we can access it // from the return points. - if (Is64Bit && MF.getFunction()->hasStructRetAttr()) { + if (MF.getFunction()->hasStructRetAttr() && + (Subtarget->is64Bit() || Subtarget->isTargetWindows())) { X86MachineFunctionInfo *FuncInfo = MF.getInfo(); unsigned Reg = FuncInfo->getSRetReturnReg(); if (!Reg) { diff --git a/test/CodeGen/X86/win32_sret.ll b/test/CodeGen/X86/win32_sret.ll index 878c6db992..19cbfd45ed 100644 --- a/test/CodeGen/X86/win32_sret.ll +++ b/test/CodeGen/X86/win32_sret.ll @@ -1,28 +1,84 @@ -; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN_X32 -; RUN: llc < %s -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X32 +; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN32 +; RUN: llc < %s -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X86 ; RUN: llc < %s -mtriple=i386-pc-linux | FileCheck %s -check-prefix=LINUX -; RUN: llc < %s -O0 -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN_X32 -; RUN: llc < %s -O0 -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X32 +; RUN: llc < %s -O0 -mtriple=i686-pc-win32 | FileCheck %s -check-prefix=WIN32 +; RUN: llc < %s -O0 -mtriple=i686-pc-mingw32 | FileCheck %s -check-prefix=MINGW_X86 ; RUN: llc < %s -O0 -mtriple=i386-pc-linux | FileCheck %s -check-prefix=LINUX ; The SysV ABI used by most Unixes and Mingw on x86 specifies that an sret pointer ; is callee-cleanup. However, in MSVC's cdecl calling convention, sret pointer ; arguments are caller-cleanup like normal arguments. -define void @sret1(i8* sret) nounwind { +define void @sret1(i8* sret %x) nounwind { entry: -; WIN_X32: {{ret$}} -; MINGW_X32: ret $4 +; WIN32: sret1 +; WIN32: movb $42, (%eax) +; WIN32-NOT: popl %eax +; WIN32: {{ret$}} + +; MINGW_X86: sret1 +; MINGW_X86: ret $4 + +; LINUX: sret1 ; LINUX: ret $4 + + store i8 42, i8* %x, align 4 ret void } -define void @sret2(i32* sret %x, i32 %y) nounwind { +define void @sret2(i8* sret %x, i8 %y) nounwind { entry: -; WIN_X32: {{ret$}} -; MINGW_X32: ret $4 +; WIN32: sret2 +; WIN32: movb {{.*}}, (%eax) +; WIN32-NOT: popl %eax +; WIN32: {{ret$}} + +; MINGW_X86: sret2 +; MINGW_X86: ret $4 + +; LINUX: sret2 ; LINUX: ret $4 - store i32 %y, i32* %x + + store i8 %y, i8* %x ret void } +define void @sret3(i8* sret %x, i8* %y) nounwind { +entry: +; WIN32: sret3 +; WIN32: movb $42, (%eax) +; WIN32-NOT: movb $13, (%eax) +; WIN32-NOT: popl %eax +; WIN32: {{ret$}} + +; MINGW_X86: sret3 +; MINGW_X86: ret $4 + +; LINUX: sret3 +; LINUX: ret $4 + + store i8 42, i8* %x + store i8 13, i8* %y + ret void +} + +; PR15556 +%struct.S4 = type { i32, i32, i32 } + +define void @sret4(%struct.S4* noalias sret %agg.result) { +entry: +; WIN32: sret4 +; WIN32: movl $42, (%eax) +; WIN32-NOT: popl %eax +; WIN32: {{ret$}} + +; MINGW_X86: sret4 +; MINGW_X86: ret $4 + +; LINUX: sret4 +; LINUX: ret $4 + + %x = getelementptr inbounds %struct.S4* %agg.result, i32 0, i32 0 + store i32 42, i32* %x, align 4 + ret void +} -- cgit v1.2.3-18-g5258