From b8b52972c72b2ba6fe171c522e5d3d7d69503021 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 18 Jun 2013 02:46:29 +0000 Subject: [PATCH] Add support for -fpcc-struct-return. Patch by Arthur O'Dwyer! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184166 91177308-0d34-0410-b5e6-96231b3b80d8 --- CodeGen/x86_32-fpcc-struct-return.c | 34 +++++++++++ include/clang/Driver/Options.td | 4 ++ include/clang/Frontend/CodeGenOptions.def | 4 ++ include/clang/Frontend/CodeGenOptions.h | 6 ++ lib/CodeGen/TargetInfo.cpp | 69 +++++++++++++++-------- lib/Driver/Tools.cpp | 12 ++++ lib/Frontend/CompilerInvocation.cpp | 9 +++ test/CodeGen/x86_32-fpcc-struct-return.c | 34 +++++++++++ 8 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 CodeGen/x86_32-fpcc-struct-return.c create mode 100644 test/CodeGen/x86_32-fpcc-struct-return.c diff --git a/CodeGen/x86_32-fpcc-struct-return.c b/CodeGen/x86_32-fpcc-struct-return.c new file mode 100644 index 0000000000..68511024bb --- /dev/null +++ b/CodeGen/x86_32-fpcc-struct-return.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-apple-darwin9 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-win32 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-win32 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG + +typedef struct { int a,b,c,d; } Big; +typedef struct { int i; } Small; +typedef struct { short s; } Short; +typedef struct { } ZeroSized; + +// CHECK: define void @returnBig +// CHECK: ret void +Big returnBig(Big x) { return x; } + +// CHECK-PCC: define void @returnSmall +// CHECK-PCC: ret void +// CHECK-REG: define i32 @returnSmall +// CHECK-REG: ret i32 +Small returnSmall(Small x) { return x; } + +// CHECK-PCC: define void @returnShort +// CHECK-PCC: ret void +// CHECK-REG: define i16 @returnShort +// CHECK-REG: ret i16 +Short returnShort(Short x) { return x; } + +// CHECK: define void @returnZero() +// CHECK: ret void +ZeroSized returnZero(ZeroSized x) { return x; } diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index c0e4c4988e..5eb4286cc8 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -687,6 +687,8 @@ def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group, Flags<[CC1 HelpText<"Specify the default maximum struct packing alignment">; def fpascal_strings : Flag<["-"], "fpascal-strings">, Group, Flags<[CC1Option]>, HelpText<"Recognize and construct Pascal-style string literals">; +def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group, Flags<[CC1Option]>, + HelpText<"Override the default ABI to return all structs on the stack">; def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group; def fpic : Flag<["-"], "fpic">, Group; def fno_pic : Flag<["-"], "fno-pic">, Group; @@ -696,6 +698,8 @@ def fprofile_arcs : Flag<["-"], "fprofile-arcs">, Group; def fprofile_generate : Flag<["-"], "fprofile-generate">, Group; def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group; +def freg_struct_return : Flag<["-"], "freg-struct-return">, Group, Flags<[CC1Option]>, + HelpText<"Override the default ABI to return small structs in registers">; def frtti : Flag<["-"], "frtti">, Group; def fsched_interblock : Flag<["-"], "fsched-interblock">, Group; def fshort_enums : Flag<["-"], "fshort-enums">, Group, Flags<[CC1Option]>, diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index f6e2472cb9..b414d7554f 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -85,6 +85,10 @@ CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer ///< enabled. VALUE_CODEGENOPT(OptimizationLevel, 3, 0) ///< The -O[0-4] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. + + /// If -fpcc-struct-return or -freg-struct-return is specified. +ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) + CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions. CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA. diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h index db6b418673..6717791466 100644 --- a/include/clang/Frontend/CodeGenOptions.h +++ b/include/clang/Frontend/CodeGenOptions.h @@ -71,6 +71,12 @@ public: FPC_Fast // Aggressively fuse FP ops (E.g. FMA). }; + enum StructReturnConventionKind { + SRCK_Default, // No special option was passed. + SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return). + SRCK_InRegs // Small structs in registers (-freg-struct-return). + }; + /// The code model to use (-mcmodel). std::string CodeModel; diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 09f7779146..01fd8e7d79 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -575,6 +575,9 @@ public: bool d, bool p, bool w, unsigned r) :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, w, r)) {} + static bool isStructReturnInRegABI( + const llvm::Triple &Triple, const CodeGenOptions &Opts); + void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const; @@ -1293,8 +1296,9 @@ static std::string qualifyWindowsLibrary(llvm::StringRef Lib) { class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo { public: - WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned RegParms) - : X86_32TargetCodeGenInfo(CGT, false, true, true, RegParms) {} + WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, + bool d, bool p, bool w, unsigned RegParms) + : X86_32TargetCodeGenInfo(CGT, d, p, w, RegParms) {} void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const { @@ -4444,6 +4448,36 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return ResAddr; } +bool X86_32TargetCodeGenInfo::isStructReturnInRegABI( + const llvm::Triple &Triple, const CodeGenOptions &Opts) { + assert(Triple.getArch() == llvm::Triple::x86); + + switch (Opts.getStructReturnConvention()) { + case CodeGenOptions::SRCK_Default: + break; + case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return + return false; + case CodeGenOptions::SRCK_InRegs: // -freg-struct-return + return true; + } + + if (Triple.isOSDarwin()) + return true; + + switch (Triple.getOS()) { + case llvm::Triple::Cygwin: + case llvm::Triple::MinGW32: + case llvm::Triple::AuroraUX: + case llvm::Triple::DragonFly: + case llvm::Triple::FreeBSD: + case llvm::Triple::OpenBSD: + case llvm::Triple::Bitrig: + case llvm::Triple::Win32: + return true; + default: + return false; + } +} ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) @@ -5506,31 +5540,22 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types)); case llvm::Triple::x86: { - if (Triple.isOSDarwin()) - return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, true, true, false, - CodeGenOpts.NumRegisterParameters)); + bool IsDarwinVectorABI = Triple.isOSDarwin(); + bool IsSmallStructInRegABI = + X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts); + bool IsWin32FloatStructABI = (Triple.getOS() == llvm::Triple::Win32); - switch (Triple.getOS()) { - case llvm::Triple::Cygwin: - case llvm::Triple::MinGW32: - case llvm::Triple::AuroraUX: - case llvm::Triple::DragonFly: - case llvm::Triple::FreeBSD: - case llvm::Triple::OpenBSD: - case llvm::Triple::Bitrig: - return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, true, false, - CodeGenOpts.NumRegisterParameters)); - - case llvm::Triple::Win32: + if (Triple.getOS() == llvm::Triple::Win32) { return *(TheTargetCodeGenInfo = new WinX86_32TargetCodeGenInfo(Types, + IsDarwinVectorABI, IsSmallStructInRegABI, + IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters)); - - default: + } else { return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Types, false, false, false, + new X86_32TargetCodeGenInfo(Types, + IsDarwinVectorABI, IsSmallStructInRegABI, + IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters)); } } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index add0c623aa..373939cd93 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -2165,6 +2165,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, options::OPT_freg_struct_return)) { + if (getToolChain().getTriple().getArch() != llvm::Triple::x86) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << getToolChain().getTriple().str(); + } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { + CmdArgs.push_back("-fpcc-struct-return"); + } else { + assert(A->getOption().matches(options::OPT_freg_struct_return)); + CmdArgs.push_back("-freg-struct-return"); + } + } + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-mrtd"); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 4e62fda4a3..1407e105f2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -478,6 +478,15 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + if (Arg *A = Args.getLastArg(OPT_fpcc_struct_return, OPT_freg_struct_return)) { + if (A->getOption().matches(OPT_fpcc_struct_return)) { + Opts.setStructReturnConvention(CodeGenOptions::SRCK_OnStack); + } else { + assert(A->getOption().matches(OPT_freg_struct_return)); + Opts.setStructReturnConvention(CodeGenOptions::SRCK_InRegs); + } + } + return Success; } diff --git a/test/CodeGen/x86_32-fpcc-struct-return.c b/test/CodeGen/x86_32-fpcc-struct-return.c new file mode 100644 index 0000000000..68511024bb --- /dev/null +++ b/test/CodeGen/x86_32-fpcc-struct-return.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-apple-darwin9 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-apple-darwin9 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm -o - %s | FileCheck %s --check-prefix=REG +// RUN: %clang_cc1 -triple i386-pc-win32 -fpcc-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=PCC +// RUN: %clang_cc1 -triple i386-pc-win32 -freg-struct-return -emit-llvm -o - %s | FileCheck %s --check-prefix=REG + +typedef struct { int a,b,c,d; } Big; +typedef struct { int i; } Small; +typedef struct { short s; } Short; +typedef struct { } ZeroSized; + +// CHECK: define void @returnBig +// CHECK: ret void +Big returnBig(Big x) { return x; } + +// CHECK-PCC: define void @returnSmall +// CHECK-PCC: ret void +// CHECK-REG: define i32 @returnSmall +// CHECK-REG: ret i32 +Small returnSmall(Small x) { return x; } + +// CHECK-PCC: define void @returnShort +// CHECK-PCC: ret void +// CHECK-REG: define i16 @returnShort +// CHECK-REG: ret i16 +Short returnShort(Short x) { return x; } + +// CHECK: define void @returnZero() +// CHECK: ret void +ZeroSized returnZero(ZeroSized x) { return x; } -- 2.40.0