Skip to content

Commit

Permalink
[clang][PowerPC] Add flag to enable compatibility with GNU for comple…
Browse files Browse the repository at this point in the history
…x arguments

Fixes : #56023

https://godbolt.org/z/1bsW1sKMs

newFlag : -fcomplex-ppc-gnu-abi

GNU uses GPRs for complex parameters and return values storing for PowerPC-32bit,
which can be enabled which above flag.
Intent of this patch is to make clang compatible with GNU libraries of complex.
  • Loading branch information
Long5hot committed Jan 17, 2024
1 parent 3e0d71c commit ec05087
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 15 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ CODEGENOPT(MCDCCoverage , 1, 0) ///< Enable MC/DC code coverage criteria.

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

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

enum ComplexArgumentConventionKind {
CMPLX_Default,
CMPLX_OnStack,
CMPLX_OnGPR, // if ppc32 -fcomplex-ppc-gnu-abi
CMPLX_OnFPR
};

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 @@ -2540,6 +2540,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, store Complex values in GPR instead of stack for PowerPC-32">,
HelpText<"Store 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
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,13 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {

bool IsSoftFloat =
CodeGenOpts.FloatABI == "soft" || Target.hasFeature("spe");
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat);
unsigned RLen = Target.getPointerWidth(LangAS::Default);
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat, RLen);
}
case llvm::Triple::ppcle: {
bool IsSoftFloat = CodeGenOpts.FloatABI == "soft";
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat);
unsigned RLen = Target.getPointerWidth(LangAS::Default);
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat, RLen);
}
case llvm::Triple::ppc64:
if (Triple.isOSAIX())
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ std::unique_ptr<TargetCodeGenInfo>
createAIXTargetCodeGenInfo(CodeGenModule &CGM, bool Is64Bit);

std::unique_ptr<TargetCodeGenInfo>
createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI);
createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI,
unsigned RLen);

std::unique_ptr<TargetCodeGenInfo>
createPPC64TargetCodeGenInfo(CodeGenModule &CGM);
Expand Down
110 changes: 98 additions & 12 deletions clang/lib/CodeGen/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,22 +271,33 @@ namespace {
class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
bool IsSoftFloatABI;
bool IsRetSmallStructInRegABI;
bool isComplexInRegABI;
// Size of GPR in bits
unsigned RLen;
static const int NumArgGPRs = 8;

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

public:
PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI,
bool RetSmallStructInRegABI)
bool RetSmallStructInRegABI, unsigned RLen,
bool ComplexInRegABI)
: DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI),
IsRetSmallStructInRegABI(RetSmallStructInRegABI) {}
IsRetSmallStructInRegABI(RetSmallStructInRegABI),
isComplexInRegABI(ComplexInRegABI), RLen(RLen) {}

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

void computeInfo(CGFunctionInfo &FI) const override {

int ArgGPRsLeft = NumArgGPRs;

if (!getCXXABI().classifyReturnType(FI))
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (auto &I : FI.arguments())
I.info = classifyArgumentType(I.type);
I.info = classifyArgumentType(I.type, ArgGPRsLeft);
}

Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
Expand All @@ -296,9 +307,11 @@ class PPC32_SVR4_ABIInfo : public DefaultABIInfo {
class PPC32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI,
bool RetSmallStructInRegABI)
bool RetSmallStructInRegABI, unsigned RLen,
bool ComplexInRegABI)
: TargetCodeGenInfo(std::make_unique<PPC32_SVR4_ABIInfo>(
CGT, SoftFloatABI, RetSmallStructInRegABI)) {}
CGT, SoftFloatABI, RetSmallStructInRegABI, RLen, ComplexInRegABI)) {
}

static bool isStructReturnInRegABI(const llvm::Triple &Triple,
const CodeGenOptions &Opts);
Expand Down Expand Up @@ -337,12 +350,77 @@ CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const {
return CharUnits::fromQuantity(4);
}

ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(QualType Ty,
uint64_t &TypeSize) const {

assert(Ty->isAnyComplexType());
llvm::Type *ElemTy;
unsigned SizeRegs;

if (TypeSize == 64) {
ElemTy = llvm::Type::getInt64Ty(getVMContext());
SizeRegs = 1;
} else {
ElemTy = llvm::Type::getInt32Ty(getVMContext());
SizeRegs = (TypeSize + 31) / 32;
}
return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs));
}

ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
int &ArgGPRsLeft) const {

assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
Ty = useFirstFieldIfTransparentUnion(Ty);

ASTContext &Context = getContext();

uint64_t TypeSize = Context.getTypeSize(Ty);

if (isComplexInRegABI && Ty->isAnyComplexType() &&
TypeSize <= RLen * ArgGPRsLeft) {
ArgGPRsLeft -= TypeSize / RLen;
return handleComplex(Ty, TypeSize);
}

if (isAggregateTypeForABI(Ty)) {
if (ArgGPRsLeft)
ArgGPRsLeft -= 1;
// Records with non-trivial destructors/copy-constructors should not be
// passed by value.
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);
}
return getNaturalAlignIndirect(Ty);
}

if (!Ty->isFloatingType()) {
if (TypeSize > RLen && TypeSize <= 2 * RLen)
ArgGPRsLeft -= 2;
else
ArgGPRsLeft--;
}

// Treat an enum type as its underlying type.
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();

if (const auto *EIT = Ty->getAs<BitIntType>())
if (EIT->getNumBits() >
Context.getTypeSize(Context.getTargetInfo().hasInt128Type()
? Context.Int128Ty
: Context.LongLongTy))
return getNaturalAlignIndirect(Ty);

return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
: ABIArgInfo::getDirect());
}

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 @@ -361,6 +439,9 @@ ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getDirect(CoerceTy);
}
}
if (isComplexInRegABI && RetTy->isAnyComplexType()) {
return handleComplex(RetTy, Size);
}

return DefaultABIInfo::classifyReturnType(RetTy);
}
Expand All @@ -372,11 +453,12 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList,
if (getTarget().getTriple().isOSDarwin()) {
auto TI = getContext().getTypeInfoInChars(Ty);
TI.Align = getParamTypeAlignment(Ty);
int ArgGPRs = NumArgGPRs;

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

const unsigned OverflowLimit = 8;
Expand Down Expand Up @@ -974,11 +1056,15 @@ CodeGen::createAIXTargetCodeGenInfo(CodeGenModule &CGM, bool Is64Bit) {
}

std::unique_ptr<TargetCodeGenInfo>
CodeGen::createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI) {
CodeGen::createPPC32TargetCodeGenInfo(CodeGenModule &CGM, bool SoftFloatABI,
unsigned RLen) {
bool RetSmallStructInRegABI = PPC32TargetCodeGenInfo::isStructReturnInRegABI(
CGM.getTriple(), CGM.getCodeGenOpts());
bool isComplexInRegABI = (CGM.getCodeGenOpts().getComplexInRegABI() ==
CodeGenOptions::CMPLX_OnGPR);
return std::make_unique<PPC32TargetCodeGenInfo>(CGM.getTypes(), SoftFloatABI,
RetSmallStructInRegABI);
RetSmallStructInRegABI, RLen,
isComplexInRegABI);
}

std::unique_ptr<TargetCodeGenInfo>
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5470,6 +5470,15 @@ 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");
}
}

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
8 changes: 8 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1640,6 +1640,10 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
GenerateArg(Consumer, Opt);
}

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

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

Expand Down Expand Up @@ -2034,6 +2038,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
}
}

if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) {
Opts.setComplexInRegABI(CodeGenOptions::CMPLX_OnGPR);
}

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

0 comments on commit ec05087

Please sign in to comment.