Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ Non-comprehensive list of changes in this release
New Compiler Flags
------------------

* ``-fcomplex-ppc-gnu-abi`` follow ABI ATR-PASS-COMPLEX-IN-GPRS for ppc32 and pass
complex parameters on GPRs instead of stack.
For more info check `Power Architecture™ 32-bit ABI Supplement 1.0 - Embedded
<https://www.polyomino.org.uk/publications/2011/Power-Arch-32-bit-ABI-supp-1.0-Embedded.pdf>`_

Deprecated Compiler Flags
-------------------------

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ VALUE_CODEGENOPT(MCDCMaxTVs, 32, 0x7FFFFFFE) ///< MC/DC Maximum test vectors.

/// If -fpcc-struct-return or -freg-struct-return is specified.
ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default)
/// If -fcomplex-ppc-gnu-abi is specified on ppc32.
ENUM_CODEGENOPT(ComplexInRegABI, ComplexArgumentConventionKind, 2, CMPLX_OnStack)

CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
SRCK_InRegs // Small structs in registers (-freg-struct-return).
};

enum ComplexArgumentConventionKind {
CMPLX_OnStack,
CMPLX_InGPR, // If -fcomplex-ppc-gnu-abi is specified on ppc32
CMPLX_InFPR
};

enum ProfileInstrKind {
ProfileNone, // Profile instrumentation is turned off.
ProfileClangInstr, // Clang instrumentation to generate execution counts
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2640,6 +2640,10 @@ def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
HelpText<"Form fused FP ops (e.g. FMAs)">,
Values<"fast,on,off,fast-honor-pragmas">;

def fcomplex_ppc_gnu_abi : Flag<["-"], "fcomplex-ppc-gnu-abi">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
DocBrief<"Follow the GNU ABI, pass Complex values in GPRs instead of the stack for PowerPC-32">,
HelpText<"Pass Complex values in GPR instead of stack for PowerPC-32">;

defm strict_float_cast_overflow : BoolFOption<"strict-float-cast-overflow",
CodeGenOpts<"StrictFloatCastOverflow">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
Expand Down
85 changes: 80 additions & 5 deletions clang/lib/CodeGen/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,12 @@ namespace {
class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
bool IsSoftFloatABI;
bool IsRetSmallStructInRegABI;
// Size of GPR in bits.
static const unsigned GPRBits = 32;
static const int ArgGPRsNum = 8;

CharUnits getParamTypeAlignment(QualType Ty) const;
ABIArgInfo handleComplex(uint64_t &TypeSize) const;

public:
PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI,
Expand All @@ -338,12 +342,15 @@ class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
IsRetSmallStructInRegABI(RetSmallStructInRegABI) {}

ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft) const;

void computeInfo(CGFunctionInfo &FI) const override {
if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());

int ArgGPRsLeft = ArgGPRsNum;
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
I.info = classifyArgumentType(I.type, ArgGPRsLeft);
}

RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
Expand Down Expand Up @@ -394,12 +401,74 @@ CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
return CharUnits::fromQuantity(4);
}

ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(uint64_t &TypeSize) const {
llvm::Type *ElemTy;
unsigned RegsNeeded; // Registers Needed for Complex.

// Choice of using llvm::Type::getInt64Ty(getVMContext()) for complex
// single-precision floats is based on the ABI ATR-PASS-COMPLEX-IN-GPRS
// specification. According to the specification:
// - For complex single-precision floats: If the register (gr) is even, it's
// incremented by one, and the lower-addressed word of the argument is loaded
// into gr, while the higher-addressed word is loaded into gr + 1. Then, gr is
// incremented by 2.
// - For complex double-precision floats: The words of the argument are loaded
// in memory-address order into gr, gr + 1, gr + 2, and gr + 3, with gr being
// incremented by 4. Thus, to maintain even alignment and adhere to the ABI
// specification, llvm::Type::getInt64Ty(getVMContext()) is used when TypeSize
// is 64. Powerpc backend handles this alignment requirement. Specifically,
// you can refer to the CC_PPC32_SVR4_Custom_AlignArgRegs method from
// PPCCallingconvention.cpp. For more context, refer to the previous
// discussion: https://reviews.llvm.org/D146942 and the related LLVM pull
// request: #77732

if (TypeSize == 64) {
ElemTy = llvm::Type::getInt64Ty(getVMContext());
RegsNeeded = 1;
} else {
ElemTy = llvm::Type::getInt32Ty(getVMContext());
RegsNeeded = TypeSize >> 5;
}
return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, RegsNeeded));
}

ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
int &ArgGPRsLeft) const {
Ty = useFirstFieldIfTransparentUnion(Ty);
bool IsComplex = Ty->isAnyComplexType();

if ((getCodeGenOpts().getComplexInRegABI() != CodeGenOptions::CMPLX_InGPR) ||
!ArgGPRsLeft || (!IsComplex && Ty->isFloatingType() && !IsSoftFloatABI))
return DefaultABIInfo::classifyArgumentType(Ty);

assert(ArgGPRsLeft >= 0 && "Arg GPR must be large or equal than zero");
ASTContext &Context = getContext();
uint64_t TypeSize = Context.getTypeSize(Ty);

// For complex type or any other primitive types.
if (IsComplex || !isAggregateTypeForABI(Ty)) {
// If gr is even set gr = gr + 1 for TypeSize=64.
if (TypeSize == 64 && ArgGPRsLeft % 2 == 1)
--ArgGPRsLeft;

if (TypeSize <= GPRBits * ArgGPRsLeft) {
ArgGPRsLeft -= TypeSize / GPRBits;
if (IsComplex)
return handleComplex(TypeSize);
}
} else
--ArgGPRsLeft; // Records with non-trivial destructors/copy-constructors
// should not be passed by value.

return DefaultABIInfo::classifyArgumentType(Ty);
}

ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
uint64_t Size;

uint64_t Size = getContext().getTypeSize(RetTy);

// -msvr4-struct-return puts small aggregates in GPR3 and GPR4.
if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI &&
(Size = getContext().getTypeSize(RetTy)) <= 64) {
if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI && Size <= 64) {
// System V ABI (1995), page 3-22, specified:
// > A structure or union whose size is less than or equal to 8 bytes
// > shall be returned in r3 and r4, as if it were first stored in the
Expand All @@ -419,6 +488,10 @@ ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
}
}

if ((getCodeGenOpts().getComplexInRegABI() == CodeGenOptions::CMPLX_InGPR) &&
RetTy->isAnyComplexType())
return handleComplex(Size);

return DefaultABIInfo::classifyReturnType(RetTy);
}

Expand All @@ -429,10 +502,12 @@ RValue PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
if (getTarget().getTriple().isOSDarwin()) {
auto TI = getContext().getTypeInfoInChars(Ty);
TI.Align = getParamTypeAlignment(Ty);
int ArgGPRs = ArgGPRsNum;

CharUnits SlotSize = CharUnits::fromQuantity(4);
return emitVoidPtrVAArg(CGF, VAList, Ty,
classifyArgumentType(Ty).isIndirect(), TI, SlotSize,
classifyArgumentType(Ty, ArgGPRs).isIndirect(), TI,
SlotSize,
/*AllowHigherAlign=*/true, Slot);
}

Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5865,6 +5865,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

if (Arg *A = Args.getLastArg(options::OPT_fcomplex_ppc_gnu_abi)) {
if (!TC.getTriple().isPPC32() || !TC.getTriple().isOSBinFormatELF()) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
} else {
CmdArgs.push_back("-fcomplex-ppc-gnu-abi");
}
} else if (TC.getTriple().isPPC32() && TC.getTriple().isGNUEnvironment() &&
TC.getTriple().isOSBinFormatELF())
CmdArgs.push_back("-fcomplex-ppc-gnu-abi");

if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) {
if (Triple.getArch() == llvm::Triple::m68k)
CmdArgs.push_back("-fdefault-calling-conv=rtdcall");
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1786,6 +1786,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
GenerateArg(Consumer, Opt);
}

if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_InGPR)
GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi);

if (Opts.EnableAIXExtendedAltivecABI)
GenerateArg(Consumer, OPT_mabi_EQ_vec_extabi);

Expand Down Expand Up @@ -2184,6 +2187,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
}
}

if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi))
Opts.setComplexInRegABI(CodeGenOptions::CMPLX_InGPR);

if (Arg *A = Args.getLastArg(OPT_mxcoff_roptr)) {
if (!T.isOSAIX())
Diags.Report(diag::err_drv_unsupported_opt_for_target)
Expand Down
Loading