Skip to content

[AArch64] Diagnose more functions when FP not enabled #90832

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

Merged
merged 3 commits into from
May 7, 2024
Merged
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
11 changes: 6 additions & 5 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5049,13 +5049,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.
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 @@ -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:
Expand Down
92 changes: 71 additions & 21 deletions clang/lib/CodeGen/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand All @@ -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 {
Expand Down
16 changes: 11 additions & 5 deletions clang/lib/CodeGen/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions clang/test/CodeGen/aarch64-soft-float-abi-errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,15 @@ 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.
__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
Expand All @@ -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}}