diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 69548902dc43b9..0c7eef59db53c9 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() || (CurFuncDecl && CurFuncDecl->hasAttr()))) 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(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(CurCodeDecl), + dyn_cast_or_null(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 b1dfe5bf8f274d..f242d9e36ed40a 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 4c32f510101f04..452dc049d51b4f 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(); 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()) 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(); + 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 94cf0d86f9bed7..717a27fc9c5744 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 CallerMap; llvm::StringMap 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 33c8d3bcd76f0e..95b7668aca1b0e 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@-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@-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@-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@-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@-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@-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@-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@-1 {{'call_indirect' requires 'float' type support, but ABI 'aapcs' does not support it}}