-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][PowerPC] Add flag to enable compatibility with GNU for complex arguments #77732
base: main
Are you sure you want to change the base?
Conversation
Long5hot
commented
Jan 11, 2024
•
edited
Loading
edited
@llvm/pr-subscribers-clang-driver @llvm/pr-subscribers-clang-codegen Author: Kishan Parmar (Long5hot) Changes
Patch is 23.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/77732.diff 9 Files Affected:
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 2c4fb6745bc172..beeefae15c63f8 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -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.
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 6952b48e898a81..8abca0e3dda334 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -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
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 19becba4a5ad83..251bcb8c49782f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -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],
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 4fd32337cccc09..003848984d5f7a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -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())
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 0c0781a2d5ab9d..89ee2965f6f2e1 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -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);
diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp
index 40dddde508c177..f4885a927ab0ba 100644
--- a/clang/lib/CodeGen/Targets/PPC.cpp
+++ b/clang/lib/CodeGen/Targets/PPC.cpp
@@ -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,
@@ -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);
@@ -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
@@ -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);
}
@@ -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;
@@ -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>
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 2d8ef841d4f6be..47ad15c100ef45 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5454,6 +5454,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");
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 11f3f2c2d6425c..5c1f7da805db87 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -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);
@@ -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)
diff --git a/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c b/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c
new file mode 100644
index 00000000000000..b0df1dc836ba81
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/ppc32-complex-gnu-abi.c
@@ -0,0 +1,132 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2
+
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 \
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEF
+// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 -fcomplex-ppc-gnu-abi \
+// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU
+
+// CHECK-DEF-LABEL: define dso_local void @foo1
+// CHECK-DEF-SAME: (ptr noalias sret({ float, float }) align 4 [[AGG_RESULT:%.*]], ptr noundef byval({ float, float }) align 4 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-DEF-NEXT: entry:
+// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[X]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[X_REAL:%.*]] = load float, ptr [[X_REALP]], align 4
+// CHECK-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[X]], i32 0, i32 1
+// CHECK-DEF-NEXT: [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP]], align 4
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: store float [[X_REAL]], ptr [[AGG_RESULT_REALP]], align 4
+// CHECK-DEF-NEXT: store float [[X_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 4
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load float, ptr [[AGG_RESULT_REALP1]], align 4
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load float, ptr [[AGG_RESULT_IMAGP2]], align 4
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds { float, float }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: store float [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 4
+// CHECK-DEF-NEXT: store float [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 4
+// CHECK-DEF-NEXT: ret void
+//
+// CHECK-GNU-LABEL: define dso_local [1 x i64] @foo1
+// CHECK-GNU-SAME: ([1 x i64] noundef [[X_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-GNU-NEXT: entry:
+// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { float, float }, align 4
+// CHECK-GNU-NEXT: [[X:%.*]] = alloca { float, float }, align 4
+// CHECK-GNU-NEXT: store [1 x i64] [[X_COERCE]], ptr [[X]], align 4
+// CHECK-GNU-NEXT: [[X_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[X]], i32 0, i32 0
+// CHECK-GNU-NEXT: [[X_REAL:%.*]] = load float, ptr [[X_REALP]], align 4
+// CHECK-GNU-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[X]], i32 0, i32 1
+// CHECK-GNU-NEXT: [[X_IMAG:%.*]] = load float, ptr [[X_IMAGP]], align 4
+// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { float, float }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { float, float }, ptr [[RETVAL]], i32 0, i32 1
+// CHECK-GNU-NEXT: store float [[X_REAL]], ptr [[RETVAL_REALP]], align 4
+// CHECK-GNU-NEXT: store float [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 4
+// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [1 x i64], ptr [[RETVAL]], align 4
+// CHECK-GNU-NEXT: ret [1 x i64] [[TMP0]]
+//
+_Complex float foo1(_Complex float x) {
+ return x;
+}
+
+// CHECK-DEF-LABEL: define dso_local void @foo2
+// CHECK-DEF-SAME: (ptr noalias sret({ double, double }) align 8 [[AGG_RESULT:%.*]], ptr noundef byval({ double, double }) align 8 [[X:%.*]]) #[[ATTR0]] {
+// CHECK-DEF-NEXT: entry:
+// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementptr inbounds { double, double }, ptr [[X]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[X_REAL:%.*]] = load double, ptr [[X_REALP]], align 8
+// CHECK-DEF-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds { double, double }, ptr [[X]], i32 0, i32 1
+// CHECK-DEF-NEXT: [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP]], align 8
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: store double [[X_REAL]], ptr [[AGG_RESULT_REALP]], align 8
+// CHECK-DEF-NEXT: store double [[X_IMAG]], ptr [[AGG_RESULT_IMAGP]], align 8
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP1:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_REAL:%.*]] = load double, ptr [[AGG_RESULT_REALP1]], align 8
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP2:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAG:%.*]] = load double, ptr [[AGG_RESULT_IMAGP2]], align 8
+// CHECK-DEF-NEXT: [[AGG_RESULT_REALP3:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-DEF-NEXT: [[AGG_RESULT_IMAGP4:%.*]] = getelementptr inbounds { double, double }, ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-DEF-NEXT: store double [[AGG_RESULT_REAL]], ptr [[AGG_RESULT_REALP3]], align 8
+// CHECK-DEF-NEXT: store double [[AGG_RESULT_IMAG]], ptr [[AGG_RESULT_IMAGP4]], align 8
+// CHECK-DEF-NEXT: ret void
+//
+// CHECK-GNU-LABEL: define dso_local [4 x i32] @foo2
+// CHECK-GNU-SAME: ([4 x i32] noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK-GNU-NEXT: entry:
+// CHECK-GNU-NEXT: [[RETVAL:%.*]] = alloca { double, double }, align 8
+// CHECK-GNU-NEXT: [[X:%.*]] = alloca { double, double }, align 8
+// CHECK-GNU-NEXT: store [4 x i32] [[X_COERCE]], ptr [[X]], align 8
+// CHECK-GNU-NEXT: [[X_REALP:%.*]] = getelementptr inbounds { double, double }, ptr [[X]], i32 0, i32 0
+// CHECK-GNU-NEXT: [[X_REAL:%.*]] = load double, ptr [[X_REALP]], align 8
+// CHECK-GNU-NEXT: [[X_IMAGP:%.*]] = getelementptr inbounds { double, double }, ptr [[X]], i32 0, i32 1
+// CHECK-GNU-NEXT: [[X_IMAG:%.*]] = load double, ptr [[X_IMAGP]], align 8
+// CHECK-GNU-NEXT: [[RETVAL_REALP:%.*]] = getelementptr inbounds { double, double }, ptr [[RETVAL]], i32 0, i32 0
+// CHECK-GNU-NEXT: [[RETVAL_IMAGP:%.*]] = getelementptr inbounds { double, double }, ptr [[RETVAL]], i32 0, i32 1
+// CHECK-GNU-NEXT: store double [[X_REAL]], ptr [[RETVAL_REALP]], align 8
+// CHECK-GNU-NEXT: store double [[X_IMAG]], ptr [[RETVAL_IMAGP]], align 8
+// CHECK-GNU-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8
+// CHECK-GNU-NEXT: ret [4 x i32] [[TMP0]]
+//
+_Complex double foo2(_Complex double x) {
+ return x;
+}
+
+// CHECK-DEF-LABEL: define dso_local void @foo3
+// CHECK-DEF-SAME: (ptr noalias sret({ ppc_fp128, ppc_fp128 }) align 16 [[AGG_RESULT:%.*]], ptr noundef byval({ ppc_fp128, ppc_fp128 }) align 16 [[X:%.*]]) #[[ATTR0]] {
+// CHECK-DEF-NEXT: entry:
+// CHECK-DEF-NEXT: [[X_REALP:%.*]] = getelementp...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
f79b66c
to
ec05087
Compare
ec05087
to
6a209fb
Compare
ping! @chmeeedalf @nemanjai |
I know nothing about the complex ABI, so all I can say is the code looks okay from a structural point, can't say anything to the logic. |
enum ComplexArgumentConventionKind { | ||
CMPLX_Default, | ||
CMPLX_OnStack, | ||
CMPLX_OnGPR, // if ppc32 -fcomplex-ppc-gnu-abi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we use In[GF]PR
in the names as "in registers"/"on stack" are in common usage.
@@ -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">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use "Pass" instead of "Store" as the latter generally refers to storing values in memory and this actually affects parameter passing.
clang/lib/CodeGen/TargetInfo.h
Outdated
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain this change. It is not clear to me why we're adding this parameter. Are we adding support for 32-bit targets with 64-bit pointers? If so, please justify. Also, this is something that would belong in a separate patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not sure about hardcoding Register Width(RLen) "32" for RLen here.. https://github.com/llvm/llvm-project/pull/77732/files#diff-05339beb4a6cf7efdfc537984255dd372dcf1edd2d00eabed25831da4d1d0a9fR276
So i used similiar approach like, how RISC-V does to calculate Register Width here.
PPC : https://github.com/llvm/llvm-project/pull/77732/files#diff-e724febedab9c1a2832bf2056d208ff02ddcb2e6f90b5a653afc9b19ac78a5d7R187
RISCV : https://github.com/llvm/llvm-project/pull/77732/files#diff-e724febedab9c1a2832bf2056d208ff02ddcb2e6f90b5a653afc9b19ac78a5d7L226
My review is not complete, I just submitted what I have so far so at least we can get started on answering the questions I have so far. |
clang/lib/CodeGen/CodeGenModule.cpp
Outdated
@@ -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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the variable is used only once , do not need to introduce a new variable.
clang/lib/CodeGen/CodeGenModule.cpp
Outdated
} | ||
case llvm::Triple::ppcle: { | ||
bool IsSoftFloat = CodeGenOpts.FloatABI == "soft"; | ||
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat); | ||
unsigned RLen = Target.getPointerWidth(LangAS::Default); | ||
return createPPC32TargetCodeGenInfo(CGM, IsSoftFloat, RLen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the variable RLen
is used only once , do not need to introduce a new variable.
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
@@ -271,22 +271,33 @@ namespace { | |||
class PPC32_SVR4_ABIInfo : public DefaultABIInfo { | |||
bool IsSoftFloatABI; | |||
bool IsRetSmallStructInRegABI; | |||
bool isComplexInRegABI; | |||
// Size of GPR in bits | |||
unsigned RLen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RLen
is too short to understand what R
means , suggest to change to RegLen
and RegisterLen
. and Do we need to add RLen
? since the class is PPC32_SVR4_ABIInfo, Should the Register Len be default to 32 bit ?
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
|
||
assert(Ty->isAnyComplexType()); | ||
llvm::Type *ElemTy; | ||
unsigned SizeRegs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a comment for SizeRegs what is stand for?
should it rename to ElemNum ?
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(QualType Ty, | ||
uint64_t &TypeSize) const { | ||
|
||
assert(Ty->isAnyComplexType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks the Ty pass in the function is only used for assert ?
ElemTy = llvm::Type::getInt64Ty(getVMContext()); | ||
SizeRegs = 1; | ||
} else { | ||
ElemTy = llvm::Type::getInt32Ty(getVMContext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am curiously why not get ElemTy = llvm::Type::getInt64Ty(getVMContext());
instead of ElemTy = llvm::Type::getInt32Ty(getVMContext());
and change following code as
llvm::Type *ElemTy = llvm::Type::getInt64Ty(getVMContext()):
unsigned SizeRegs = TypeSize/64;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reason for using llvm::Type::getInt64Ty(getVMContext()) for floats here was to follow ABI ATR-PASS-COMPLEX-IN-GPRS
complex single-precision float : If gr is even, set gr = gr + 1. Load the lower-addressed word of the
argument into gr and the higher-addressed word into gr + 1, set gr = gr + 2.complex double-precision float: Load the words of the argument, in memory-address order, into gr, gr + 1,
gr + 2 and gr + 3, set gr = gr + 4.
You can check the previous discussion here. : https://reviews.llvm.org/D146942
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
llvm::Type *ElemTy = llvm::Type::getInt64Ty(getVMContext());
unsigned SizeRegs = TypeSize/64;
Since Typesize will be 64, in if is it necessary to replace 1 to TypeSize/64?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it, thanks for explain. can you add your explain as comment ?
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
if (TypeSize > RLen && TypeSize <= 2 * RLen) | ||
ArgGPRsLeft -= 2; | ||
else | ||
ArgGPRsLeft--; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a potential bug here, you decrease the ArgGPRsLeft no mater whether ArgGPRsLeft >0;
and change the code here as
if(!Ty->isFloatingType() && TypeSize <= RLen * ArgGPRsLeft)
ArgGPRsLeft -= TypeSize / RLen;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the braces can also be omitted on the conditions within the clang/*
files.
@@ -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">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DocBrief<"Follow the GNU ABI, store Complex values in GPR instead of stack for PowerPC-32">, | |
DocBrief<"Follow the GNU ABI, pass Complex values in GPRs instead of the stack for PowerPC-32">, |
@@ -223,6 +223,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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// If -fcomplex-ppc-gnu-abi for ppc32 | |
/// If -fcomplex-ppc-gnu-abi is specified on ppc32. |
This sentence might read a bit better.
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
bool isComplexInRegABI; | ||
// Size of GPR in bits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bool isComplexInRegABI; | |
// Size of GPR in bits | |
bool IsComplexInRegABI; | |
// Size of GPR in bits. |
End sentence with a period, and capitalize the boolean variable for consistency.
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
ABIArgInfo PPC32_SVR4_ABIInfo::handleComplex(QualType Ty, | ||
uint64_t &TypeSize) const { | ||
|
||
assert(Ty->isAnyComplexType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would also be good if the assert has a message.
Additionally, for people who do not do assert builds, since Ty
is only used for the assert, they may get an unused variable warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if only use for the assert, suggest putting assert outside the function,
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
@@ -361,6 +439,9 @@ ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { | |||
return ABIArgInfo::getDirect(CoerceTy); | |||
} | |||
} | |||
if (isComplexInRegABI && RetTy->isAnyComplexType()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Braces not needed here.
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
: Context.LongLongTy)) | ||
return getNaturalAlignIndirect(Ty); | ||
|
||
return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since most of the code is same as DefaultABIInfo::classifyArgumentType(QualType Ty)
, I suggest rewrite the function PPC32_SVR4_ABIInfo::classifyArgumentType
as
ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
int &ArgGPRsLeft) const {
....
special functionality code of the function here
.....
DefaultABIInfo::classifyArgumentType(Ty)
}
duplication code is not a good idea.
@@ -78,6 +78,13 @@ class CodeGenOptions : public CodeGenOptionsBase { | |||
SRCK_InRegs // Small structs in registers (-freg-struct-return). | |||
}; | |||
|
|||
enum ComplexArgumentConventionKind { | |||
CMPLX_Default, | |||
CMPLX_OnStack, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks you define the CMPLX_Default
and CMPLX_OnStack
, but never use them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was for future reference, if any arch wants to use this.
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
|
||
void computeInfo(CGFunctionInfo &FI) const override { | ||
|
||
int ArgGPRsLeft = NumArgGPRs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move the definition to the closest first be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't understand what you mean here..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put int ArgGPRsLeft = NumArgGPRs;
in front of
for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, ArgGPRsLeft);
@@ -0,0 +1,132 @@ | |||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 | |||
|
|||
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you really need -target-cpu pwr8
since the test case only check generated IR?
|
||
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 \ | ||
// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEF | ||
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -target-cpu pwr8 -fcomplex-ppc-gnu-abi \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
return handleComplex(Ty, TypeSize); | ||
} | ||
|
||
if (isAggregateTypeForABI(Ty)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it look that you only has Complex as parameter in your test case .for example _Complex float foo1(_Complex float x)
I think you need more test case with other parameters to test the functionality of function classifyArgumentType()
6a209fb
to
a89cd20
Compare
81d57b4
to
3c5fcb0
Compare
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
Ty = useFirstFieldIfTransparentUnion(Ty); | ||
|
||
if (!(getCodeGenOpts().getComplexInRegABI() == CodeGenOptions::CMPLX_InGPR) || | ||
!ArgGPRsLeft) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!(getCodeGenOpts().getComplexInRegABI() == CodeGenOptions::CMPLX_InGPR) || !ArgGPRsLeft)
-->
if (getCodeGenOpts().getComplexInRegABI() != CodeGenOptions::CMPLX_InGPR || !ArgGPRsLeft)
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
--ArgGPRsLeft; // If gr is even set gr = gr + 1 for TypeSize=64. | ||
if (TypeSize <= ArgGPRsLeft * RegLen) | ||
ArgGPRsLeft -= TypeSize / RegLen; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the code line 467-472 is duplicated with the code 452-458 ,I would rewrite the function as
ABIArgInfo PPC32_SVR4_ABIInfo::classifyArgumentType(QualType Ty,
int &ArgGPRsLeft) const {
Ty = useFirstFieldIfTransparentUnion(Ty);
if ( getCodeGenOpts().getComplexInRegABI() != CodeGenOptions::CMPLX_InGPR ||
!ArgGPRsLeft || (Ty->isFloatingType() && !IsSoftFloatABI)
return DefaultABIInfo::classifyArgumentType(Ty);
assert(ArgGPRsLeft >= 0 && "Arg GPR must be large or equal than zero");
// Records with non-trivial destructors/copy-constructors should not be
// passed by value.
if (isAggregateTypeForABI(Ty))
--ArgGPRsLeft;
ASTContext &Context = getContext();
uint64_t TypeSize = Context.getTypeSize(Ty);
// If gr is even set gr = gr + 1 for TypeSize=64.
if (TypeSize == 64 && ArgGPRsLeft % 2 == 1)
--ArgGPRsLeft;
if (TypeSize <= RegLen * ArgGPRsLeft) {
ArgGPRsLeft -= TypeSize / RegLen;
return handleComplex(TypeSize);
}
return DefaultABIInfo::classifyArgumentType(Ty);
}
@@ -5585,6 +5585,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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need a test case for this.
// CHECK-GNU-SOFT-FLOAT-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 | ||
// CHECK-GNU-SOFT-FLOAT-NEXT: ret [4 x i32] [[TMP0]] | ||
// | ||
_Complex double _cdouble(_Complex double x) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is not float or double as parameter in the test case , I think we have tested the scenario in the ppc32-complex-gnu-abi.c
, do we still need it ?
// CHECK-GNU-SOFT-FLOAT-NEXT: [[TMP0:%.*]] = load [8 x i32], ptr [[RETVAL]], align 16 | ||
// CHECK-GNU-SOFT-FLOAT-NEXT: ret [8 x i32] [[TMP0]] | ||
// | ||
_Complex long double _cldouble(float f, _Complex long double x) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you need the test scenario ?
I think we only need test case which have float
or double
as parameter and make a _Complex
parameter is passed as pointer because option '-msoft-float` is enabled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TestCase is same as above, just replacing integer premitives with floating point, Considering this because for soft float also get's passed in gprs..
4cdfaf0
to
cc5fe4a
Compare
clang/lib/CodeGen/Targets/PPC.cpp
Outdated
@@ -330,8 +330,12 @@ namespace { | |||
class PPC32_SVR4_ABIInfo : public DefaultABIInfo { | |||
bool IsSoftFloatABI; | |||
bool IsRetSmallStructInRegABI; | |||
// Size of GPR in bits. | |||
static const unsigned RegLen = 32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest change RegLen to GPRBits as
https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp#L615
// CHECK-GNU-DEF-NEXT: ret [8 x i32] [[TMP0]] | ||
// | ||
// CHECK-GNU-SOFT-FLOAT-LABEL: define dso_local [8 x i32] @_cldouble | ||
// CHECK-GNU-SOFT-FLOAT-SAME: (float noundef [[F:%.*]], ptr noundef byval({ ppc_fp128, ppc_fp128 }) align 16 [[X:%.*]]) #[[ATTR0:[0-9]+]] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by the way, I am curiously that option -msoft-float
do not change the float noundef [[F:%.*]]
to i32 noundef [[F:%.*]]
, it looks there is a different implement between the -msoft-float
and '-fcomplex-ppc-gnu-abi' ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Below assembly's generated with -fcomplex-ppc-gnu-abi -O1 --target=ppc32 -S -msoft-float
"use-soft-float"="true" get's passed in IR in attributes
_Complex double testComplexDouble(float w, _Complex float x, _Complex double z)
{
return z;
}
testComplexDouble: # @testComplexDouble
.Lfunc_begin2:
.cfi_startproc
# %bb.0:
mr 6, 10
mr 5, 9
mr 4, 8
mr 3, 7
blr
.Lfunc_end2:
.size testComplexDouble, .Lfunc_end2-.Lfunc_begin2
.cfi_endproc
# -- End function
_Complex double checkComplexDoubleOnStack(float x1, _Complex float cf, float x2, _Complex double cd)
{
return testComplexDouble(x2, cf, cd);
}
.globl checkComplexDoubleOnStack # -- Begin function checkComplexDoubleOnStack
.p2align 2
.type checkComplexDoubleOnStack,@function
checkComplexDoubleOnStack: # @checkComplexDoubleOnStack
.Lfunc_begin3:
.cfi_startproc
# %bb.0:
lwz 3, 0(8)
lwz 4, 4(8)
lwz 5, 8(8)
lwz 6, 12(8)
blr
// CHECK-GNU-DEF-NEXT: store double [[Z_IMAG]], ptr [[RETVAL_IMAGP]], align 8 | ||
// CHECK-GNU-DEF-NEXT: [[TMP0:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 | ||
// CHECK-GNU-DEF-NEXT: ret [4 x i32] [[TMP0]] | ||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit : using empty line instead using this //
line, please do for all of them.
// CHECK-GNU-SOFT-FLOAT-NEXT: [[TMP3:%.*]] = load [4 x i32], ptr [[RETVAL]], align 8 | ||
// CHECK-GNU-SOFT-FLOAT-NEXT: ret [4 x i32] [[TMP3]] | ||
// | ||
_Complex double checkComplexDoubleOnStack(float x1, _Complex float cf, float x2, _Complex double cd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we only the test senario is enough to test the float
parameter occups one gpr in the PPC32_SVR4_ABIInfo::classifyArgumentType
. We can delete all other scenarios.
// RUN: | FileCheck %s -check-prefix=X86_64 | ||
// X86_64: error: unsupported option '-fcomplex-ppc-gnu-abi' for target 'x86_64' | ||
|
||
// RUN: not %clang %s --target=ppc64 -fcomplex-ppc-gnu-abi 2>&1 \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think two test scenarios is enough ,
if (!TC.getTriple().isPPC32() || !TC.getTriple().isOSBinFormatELF()) {
one for !TC.getTriple().isPPC32()
, other for !TC.getTriple().isOSBinFormatELF()
please do not merge the commit if possible, merging the commit make the review difficult, We want to compare what is changed between the two commit when we review. otherwise we have review the patch from scratch. |
I do not further comment on the PR, but the PR have different mechanism with "-msoft-float" , the -msoft-float pass "use-soft-float"="true" in the IR, the llc will l put float parameter in the GPR, but the PR implement
if compile with option "-msoft-float" and can we implement |
|
I think I do not express comment clearly, My comment should be "Can we implement -fcomplex-ppc-gnu-abi in llc instead of in the Clang frontend similar to how -msoft-float was implemented in llc ?" I went through the code which implement of the I do not have further comment on the PR, I approved it, but please wait for several days to see whether there is other comment from other reviewer before you merge. |
ping!! @nemanjai |
Ping!! |
ping @chmeeedalf @daltenty @diggerlin @amy-kwan !! |
ping! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering why the GNU-compatible behavior is not on by default, especially when in GNU mode (e.g., -std=gnu17
)?
Also, the changes should come with a release note in clang/docs/ReleaseNotes.rst
so users know about the new functionality.
if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_InGPR) { | ||
GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_InGPR) { | |
GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi); | |
} | |
if (T.isPPC32() && Opts.ComplexInRegABI == CodeGenOptions::CMPLX_InGPR) | |
GenerateArg(Consumer, OPT_fcomplex_ppc_gnu_abi); | |
if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) { | ||
Opts.setComplexInRegABI(CodeGenOptions::CMPLX_InGPR); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) { | |
Opts.setComplexInRegABI(CodeGenOptions::CMPLX_InGPR); | |
} | |
if (Args.getLastArg(OPT_fcomplex_ppc_gnu_abi)) | |
Opts.setComplexInRegABI(CodeGenOptions::CMPLX_InGPR); |
@@ -0,0 +1,9 @@ | |||
// RUN: %clang -c --target=ppc32 -fcomplex-ppc-gnu-abi %s 2>&1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be nice for this to check -###
output to ensure that it's passing along the correct -cc1
option.
// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-DEF | ||
// RUN: %clang_cc1 -triple powerpc-unknown-linux-gnu -fcomplex-ppc-gnu-abi \ | ||
// RUN: -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK-GNU | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just use one single blank line as a separator.
473e188
to
2d4ae49
Compare
ATR-PASS-COMPLEX-IN-GPRS was missing in clang as shown in ABI doc : https://example61560.wordpress.com/wp-content/uploads/2016/11/powerpc_abi.pdf
@AaronBallman, can you guide me, in which section of ReleaseNotes.rst i should add info about new flag? |
I'm sorry but I still don't understand why it's not on by default in GNU mode. If the user is in GNU mode, they presumably are doing so because they want to be GNU-compatible, yes?
I'd add it under |
We were compiling simple testcase with complex parameters with clang and it was crashing because libraries was built using gcc. @AaronBallman, Reason for new flag was to enable this for other C standards as well. Currently we use c11 as standard in VxWorks toolchain, which has to work with gcc compiled libraries. |
2d4ae49
to
f463f28
Compare
Ah, perhaps I was unclear -- I'm not opposed to the flag existing so users can opt into/out of it as they want. I'm wondering why the flag needs to be specified when compiling with |
@AaronBallman, Yes you are right. I will work on it! |
…x arguments (llvm#77732) Fixes : llvm#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. Following up with this patch : https://reviews.llvm.org/D146942
869a686
to
d5c328d
Compare