[clang] 1fd196c - [AArch64] Diagnose more functions when FP not enabled (#90832)
via cfe-commits
cfe-commits at lists.llvm.org
Tue May 7 01:17:09 PDT 2024
Author: ostannard
Date: 2024-05-07T09:17:05+01:00
New Revision: 1fd196c8df8e9fa4e0eddddc92b012824d8d1b0b
URL: https://github.com/llvm/llvm-project/commit/1fd196c8df8e9fa4e0eddddc92b012824d8d1b0b
DIFF: https://github.com/llvm/llvm-project/commit/1fd196c8df8e9fa4e0eddddc92b012824d8d1b0b.diff
LOG: [AArch64] Diagnose more functions when FP not enabled (#90832)
When using a hard-float ABI for a target without FP registers, it's not
possible to correctly generate code for functions with arguments which
must be passed in floating-point registers. This is diagnosed in CodeGen
instead of Sema, to more closely match GCC's behaviour around inline
functions, which is relied on by the Linux kernel.
Previously, this only checked function signatures as they were
code-generated, but this missed some cases:
* Calls to functions not defined in this translation unit.
* Calls through function pointers.
* Calls to variadic functions, where the variadic arguments have a
floating-point type.
This adds checks to function calls, as well as definitions, so that
these cases are correctly diagnosed.
Added:
Modified:
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/TargetInfo.h
clang/lib/CodeGen/Targets/AArch64.cpp
clang/lib/CodeGen/Targets/X86.cpp
clang/test/CodeGen/aarch64-soft-float-abi-errors.c
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 69548902dc43b..0c7eef59db53c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5050,13 +5050,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
(TargetDecl->hasAttr<TargetAttr>() ||
(CurFuncDecl && CurFuncDecl->hasAttr<TargetAttr>())))
checkTargetFeatures(Loc, FD);
-
- // Some architectures (such as x86-64) have the ABI changed based on
- // attribute-target/features. Give them a chance to diagnose.
- CGM.getTargetCodeGenInfo().checkFunctionCallABI(
- CGM, Loc, dyn_cast_or_null<FunctionDecl>(CurCodeDecl), FD, CallArgs);
}
+ // Some architectures (such as x86-64) have the ABI changed based on
+ // attribute-target/features. Give them a chance to diagnose.
+ CGM.getTargetCodeGenInfo().checkFunctionCallABI(
+ CGM, Loc, dyn_cast_or_null<FunctionDecl>(CurCodeDecl),
+ dyn_cast_or_null<FunctionDecl>(TargetDecl), CallArgs, RetTy);
+
// 1. Set up the arguments.
// If we're using inalloca, insert the allocation after the stack save.
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index b1dfe5bf8f274..f242d9e36ed40 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -94,7 +94,8 @@ class TargetCodeGenInfo {
virtual void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
const FunctionDecl *Caller,
const FunctionDecl *Callee,
- const CallArgList &Args) const {}
+ const CallArgList &Args,
+ QualType ReturnType) const {}
/// Determines the size of struct _Unwind_Exception on this platform,
/// in 8-bit units. The Itanium ABI defines this as:
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index 4c32f510101f0..452dc049d51b4 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -170,8 +170,22 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
const FunctionDecl *Caller,
- const FunctionDecl *Callee,
- const CallArgList &Args) const override;
+ const FunctionDecl *Callee, const CallArgList &Args,
+ QualType ReturnType) const override;
+
+private:
+ // Diagnose calls between functions with incompatible Streaming SVE
+ // attributes.
+ void checkFunctionCallABIStreaming(CodeGenModule &CGM, SourceLocation CallLoc,
+ const FunctionDecl *Caller,
+ const FunctionDecl *Callee) const;
+ // Diagnose calls which must pass arguments in floating-point registers when
+ // the selected target does not have floating-point registers.
+ void checkFunctionCallABISoftFloat(CodeGenModule &CGM, SourceLocation CallLoc,
+ const FunctionDecl *Caller,
+ const FunctionDecl *Callee,
+ const CallArgList &Args,
+ QualType ReturnType) const;
};
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
@@ -853,37 +867,42 @@ static bool isStreamingCompatible(const FunctionDecl *F) {
return false;
}
+// Report an error if an argument or return value of type Ty would need to be
+// passed in a floating-point register.
+static void diagnoseIfNeedsFPReg(DiagnosticsEngine &Diags,
+ const StringRef ABIName,
+ const AArch64ABIInfo &ABIInfo,
+ const QualType &Ty, const NamedDecl *D) {
+ const Type *HABase = nullptr;
+ uint64_t HAMembers = 0;
+ if (Ty->isFloatingType() || Ty->isVectorType() ||
+ ABIInfo.isHomogeneousAggregate(Ty, HABase, HAMembers)) {
+ Diags.Report(D->getLocation(), diag::err_target_unsupported_type_for_abi)
+ << D->getDeclName() << Ty << ABIName;
+ }
+}
+
+// If we are using a hard-float ABI, but do not have floating point registers,
+// then report an error for any function arguments or returns which would be
+// passed in floating-pint registers.
void AArch64TargetCodeGenInfo::checkFunctionABI(
CodeGenModule &CGM, const FunctionDecl *FuncDecl) const {
const AArch64ABIInfo &ABIInfo = getABIInfo<AArch64ABIInfo>();
const TargetInfo &TI = ABIInfo.getContext().getTargetInfo();
- // If we are using a hard-float ABI, but do not have floating point
- // registers, then report an error for any function arguments or returns
- // which would be passed in floating-pint registers.
- auto CheckType = [&CGM, &TI, &ABIInfo](const QualType &Ty,
- const NamedDecl *D) {
- const Type *HABase = nullptr;
- uint64_t HAMembers = 0;
- if (Ty->isFloatingType() || Ty->isVectorType() ||
- ABIInfo.isHomogeneousAggregate(Ty, HABase, HAMembers)) {
- CGM.getDiags().Report(D->getLocation(),
- diag::err_target_unsupported_type_for_abi)
- << D->getDeclName() << Ty << TI.getABI();
- }
- };
-
if (!TI.hasFeature("fp") && !ABIInfo.isSoftFloat()) {
- CheckType(FuncDecl->getReturnType(), FuncDecl);
+ diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo,
+ FuncDecl->getReturnType(), FuncDecl);
for (ParmVarDecl *PVD : FuncDecl->parameters()) {
- CheckType(PVD->getType(), PVD);
+ diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, PVD->getType(),
+ PVD);
}
}
}
-void AArch64TargetCodeGenInfo::checkFunctionCallABI(
+void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming(
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
- const FunctionDecl *Callee, const CallArgList &Args) const {
+ const FunctionDecl *Callee) const {
if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>())
return;
@@ -903,6 +922,37 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABI(
<< Callee->getDeclName();
}
+// If the target does not have floating-point registers, but we are using a
+// hard-float ABI, there is no way to pass floating-point, vector or HFA values
+// to functions, so we report an error.
+void AArch64TargetCodeGenInfo::checkFunctionCallABISoftFloat(
+ CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
+ const FunctionDecl *Callee, const CallArgList &Args,
+ QualType ReturnType) const {
+ const AArch64ABIInfo &ABIInfo = getABIInfo<AArch64ABIInfo>();
+ const TargetInfo &TI = ABIInfo.getContext().getTargetInfo();
+
+ if (!Caller || TI.hasFeature("fp") || ABIInfo.isSoftFloat())
+ return;
+
+ diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, ReturnType,
+ Caller);
+
+ for (const CallArg &Arg : Args)
+ diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, Arg.getType(),
+ Caller);
+}
+
+void AArch64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM,
+ SourceLocation CallLoc,
+ const FunctionDecl *Caller,
+ const FunctionDecl *Callee,
+ const CallArgList &Args,
+ QualType ReturnType) const {
+ checkFunctionCallABIStreaming(CGM, CallLoc, Caller, Callee);
+ checkFunctionCallABISoftFloat(CGM, CallLoc, Caller, Callee, Args, ReturnType);
+}
+
void AArch64ABIInfo::appendAttributeMangling(TargetClonesAttr *Attr,
unsigned Index,
raw_ostream &Out) const {
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 94cf0d86f9bed..717a27fc9c574 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1482,8 +1482,8 @@ class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
const FunctionDecl *Caller,
- const FunctionDecl *Callee,
- const CallArgList &Args) const override;
+ const FunctionDecl *Callee, const CallArgList &Args,
+ QualType ReturnType) const override;
};
} // namespace
@@ -1558,9 +1558,15 @@ static bool checkAVXParam(DiagnosticsEngine &Diag, ASTContext &Ctx,
return false;
}
-void X86_64TargetCodeGenInfo::checkFunctionCallABI(
- CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
- const FunctionDecl *Callee, const CallArgList &Args) const {
+void X86_64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM,
+ SourceLocation CallLoc,
+ const FunctionDecl *Caller,
+ const FunctionDecl *Callee,
+ const CallArgList &Args,
+ QualType ReturnType) const {
+ if (!Callee)
+ return;
+
llvm::StringMap<bool> CallerMap;
llvm::StringMap<bool> CalleeMap;
unsigned ArgIndex = 0;
diff --git a/clang/test/CodeGen/aarch64-soft-float-abi-errors.c b/clang/test/CodeGen/aarch64-soft-float-abi-errors.c
index 33c8d3bcd76f0..95b7668aca1b0 100644
--- a/clang/test/CodeGen/aarch64-soft-float-abi-errors.c
+++ b/clang/test/CodeGen/aarch64-soft-float-abi-errors.c
@@ -69,6 +69,7 @@ inline void test_float_arg_inline(float a) {}
inline void test_float_arg_inline_used(float a) {}
// nofp-hard-opt-error at -1 {{'a' requires 'float' type support, but ABI 'aapcs' does not support it}}
void use_inline() { test_float_arg_inline_used(1.0f); }
+// nofp-hard-error at -1 {{'use_inline' requires 'float' type support, but ABI 'aapcs' does not support it}}
// The always_inline attribute causes an inline function to always be
// code-genned, even at -O0, so we always emit the error.
@@ -76,6 +77,7 @@ __attribute((always_inline))
inline void test_float_arg_always_inline_used(float a) {}
// nofp-hard-error at -1 {{'a' requires 'float' type support, but ABI 'aapcs' does not support it}}
void use_always_inline() { test_float_arg_always_inline_used(1.0f); }
+// nofp-hard-error at -1 {{'use_always_inline' requires 'float' type support, but ABI 'aapcs' does not support it}}
// Floating-point expressions, global variables and local variables do not
// affect the ABI, so are allowed. GCC does reject some uses of floating point
@@ -97,3 +99,25 @@ int test_var_double(int a) {
d *= 6.0;
return (int)d;
}
+
+extern void extern_float_arg(float);
+extern float extern_float_ret(void);
+void call_extern_float_arg() { extern_float_arg(1.0f); }
+// nofp-hard-error at -1 {{'call_extern_float_arg' requires 'float' type support, but ABI 'aapcs' does not support it}}
+void call_extern_float_ret() { extern_float_ret(); }
+// nofp-hard-error at -1 {{'call_extern_float_ret' requires 'float' type support, but ABI 'aapcs' does not support it}}
+
+// Definitions of variadic functions, and calls to them which only use integer
+// argument registers, are both fine.
+void variadic(int, ...);
+void call_variadic_int() { variadic(0, 1); }
+
+// Calls to variadic functions with floating-point arguments are an error,
+// since this would require floating-point registers.
+void call_variadic_double() { variadic(0, 1.0); }
+// nofp-hard-error at -1 {{'call_variadic_double' requires 'double' type support, but ABI 'aapcs' does not support it}}
+
+// Calls through function pointers are also diagnosed.
+void (*fptr)(float);
+void call_indirect() { fptr(1.0f); }
+// nofp-hard-error at -1 {{'call_indirect' requires 'float' type support, but ABI 'aapcs' does not support it}}
More information about the cfe-commits
mailing list