Skip to content

Commit 3017b8a

Browse files
committed
[AArch64] Add the -mabi=aapcs-soft option for AArch64
* The default is unchanged ("aapcs", except for targets where it already defaults to "darwinpcs"), independent of whether the target has an FPU * If -mabi=aapcs-soft is used and the target has an FPU, the driver reports an error, to prevent having two incompatible ABIs for one target. * If a hard-float ABI is requested for a target without an FPU, this is accepted by the driver, but any use of floating-point types is an error. This matches GCC's behaviour with -mgeneral-regs-only, and allows for writing code which is compatible with both ABIs.
1 parent 06f5701 commit 3017b8a

14 files changed

+157
-9
lines changed

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ def warn_target_unrecognized_env : Warning<
352352
def warn_knl_knm_isa_support_removed : Warning<
353353
"KNL, KNM related Intel Xeon Phi CPU's specific ISA's supports will be removed in LLVM 19.">,
354354
InGroup<DiagGroup<"knl-knm-isa-support-removed">>;
355+
def err_target_unsupported_abi_with_fpu : Error<
356+
"'%0' ABI is not supported with FPU">;
355357

356358
// Source manager
357359
def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11268,6 +11268,8 @@ def err_omp_wrong_dependency_iterator_type : Error<
1126811268
def err_target_unsupported_type
1126911269
: Error<"%0 requires %select{|%2 bit size}1 %3 %select{|return }4type support,"
1127011270
" but target '%5' does not support it">;
11271+
def err_target_unsupported_type_for_abi
11272+
: Error<"%0 requires %1 type support, but ABI '%2' does not support it">;
1127111273
def err_omp_lambda_capture_in_declare_target_not_to : Error<
1127211274
"variable captured in declare target region must appear in a to clause">;
1127311275
def err_omp_device_type_mismatch : Error<

clang/include/clang/Basic/TargetInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class TargetInfo : public TransferrableTargetInfo,
231231
bool HasIbm128;
232232
bool HasLongDouble;
233233
bool HasFPReturn;
234+
bool HasFPTypes;
234235
bool HasStrictFP;
235236

236237
unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth;
@@ -689,6 +690,9 @@ class TargetInfo : public TransferrableTargetInfo,
689690
/// on this target.
690691
virtual bool hasFPReturn() const { return HasFPReturn; }
691692

693+
/// Determine whether floating point types are supported for this target.
694+
virtual bool hasFPTypes() const { return HasFPTypes; }
695+
692696
/// Determine whether constrained floating point is supported on this target.
693697
virtual bool hasStrictFP() const { return HasStrictFP; }
694698

@@ -1329,6 +1333,10 @@ class TargetInfo : public TransferrableTargetInfo,
13291333
return false;
13301334
}
13311335

1336+
/// Make changes to the supported types which depend on both the target
1337+
/// features and ABI.
1338+
virtual void setSupportedArgTypes() {}
1339+
13321340
/// Use the specified unit for FP math.
13331341
///
13341342
/// \return False on error (invalid unit name).

clang/lib/Basic/TargetInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
6767
HasFullBFloat16 = false;
6868
HasLongDouble = true;
6969
HasFPReturn = true;
70+
HasFPTypes = true;
7071
HasStrictFP = false;
7172
PointerWidth = PointerAlign = 32;
7273
BoolWidth = BoolAlign = 8;

clang/lib/Basic/Targets.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
828828
Target->setSupportedOpenCLOpts();
829829
Target->setCommandLineOpenCLOpts();
830830
Target->setMaxAtomicWidth();
831+
Target->setSupportedArgTypes();
831832

832833
if (!Opts->DarwinTargetVariantTriple.empty())
833834
Target->DarwinTargetVariantTriple =

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "AArch64.h"
14+
#include "clang/Basic/Diagnostic.h"
1415
#include "clang/Basic/LangOptions.h"
1516
#include "clang/Basic/TargetBuiltins.h"
1617
#include "clang/Basic/TargetInfo.h"
@@ -199,13 +200,32 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
199200
StringRef AArch64TargetInfo::getABI() const { return ABI; }
200201

201202
bool AArch64TargetInfo::setABI(const std::string &Name) {
202-
if (Name != "aapcs" && Name != "darwinpcs")
203+
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs")
203204
return false;
204205

205206
ABI = Name;
206207
return true;
207208
}
208209

210+
void AArch64TargetInfo::setSupportedArgTypes() {
211+
if (!(FPU & FPUMode) && ABI != "aapcs-soft") {
212+
// When a hard-float ABI is used on a target without an FPU, all
213+
// floating-point argument and return types are rejected because they must
214+
// be passed in FP registers.
215+
HasFPTypes = false;
216+
}
217+
}
218+
219+
bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
220+
if (hasFeature("fp") && ABI == "aapcs-soft") {
221+
// aapcs-soft is not allowed for targets with an FPU, to avoid there being
222+
// two incomatible ABIs.
223+
Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI;
224+
return false;
225+
}
226+
return true;
227+
}
228+
209229
bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
210230
BranchProtectionInfo &BPI,
211231
StringRef &Err) const {

clang/lib/Basic/Targets/AArch64.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
9494

9595
StringRef getABI() const override;
9696
bool setABI(const std::string &Name) override;
97+
void setSupportedArgTypes() override;
9798

9899
bool validateBranchProtection(StringRef Spec, StringRef Arch,
99100
BranchProtectionInfo &BPI,
@@ -197,6 +198,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
197198
bool hasInt128Type() const override;
198199

199200
bool hasBitIntType() const override { return true; }
201+
202+
bool validateTarget(DiagnosticsEngine &Diags) const override;
200203
};
201204

202205
class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
143143
Kind = AArch64ABIKind::DarwinPCS;
144144
else if (Triple.isOSWindows())
145145
return createWindowsAArch64TargetCodeGenInfo(CGM, AArch64ABIKind::Win64);
146-
else if (!Target.hasFeature("fp"))
146+
else if (Target.getABI() == "aapcs-soft")
147147
Kind = AArch64ABIKind::AAPCSSoft;
148148

149149
return createAArch64TargetCodeGenInfo(CGM, Kind);

clang/lib/Sema/Sema.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,21 @@ Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID,
19431943
return DB;
19441944
}
19451945

1946+
static bool typeIsOrContainsFloat(const Type &Ty) {
1947+
if (Ty.isFloatingType())
1948+
return true;
1949+
1950+
if (const RecordDecl *Decl = Ty.getAsRecordDecl()) {
1951+
for (const FieldDecl *FD : Decl->fields()) {
1952+
const Type &FieldType = *FD->getType();
1953+
if (typeIsOrContainsFloat(FieldType))
1954+
return true;
1955+
}
1956+
}
1957+
1958+
return false;
1959+
}
1960+
19461961
void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
19471962
if (isUnevaluatedContext() || Ty.isNull())
19481963
return;
@@ -2087,6 +2102,25 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
20872102
!Builtin::evaluateRequiredTargetFeatures("sme", CallerFeatureMap))
20882103
Diag(D->getLocation(), diag::err_sve_vector_in_non_sve_target) << Ty;
20892104
}
2105+
2106+
// Don't allow any floating-point types (including structs containing
2107+
// floats) for ABIs which do not support them.
2108+
if (!TI.hasFPTypes() && typeIsOrContainsFloat(*UnqualTy)) {
2109+
PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type_for_abi);
2110+
2111+
if (D)
2112+
PD << D;
2113+
else
2114+
PD << "expression";
2115+
2116+
if (Diag(Loc, PD, FD) << Ty << TI.getABI()) {
2117+
if (D)
2118+
D->setInvalidDecl();
2119+
}
2120+
2121+
if (D)
2122+
targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
2123+
}
20902124
};
20912125

20922126
CheckType(Ty);

clang/test/CodeGen/aarch64-soft-float-abi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -triple aarch64 -target-feature +fp-armv8 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD
2-
// RUN: %clang_cc1 -triple aarch64 -target-feature -fp-armv8 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,SOFT
1+
// RUN: %clang_cc1 -triple aarch64 -target-feature +fp-armv8 -target-abi aapcs -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,HARD
2+
// RUN: %clang_cc1 -triple aarch64 -target-feature -fp-armv8 -target-abi aapcs-soft -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,SOFT
33

44
// See also llvm/test/CodeGen/AArch64/soft-float-abi.ll, which checks the LLVM
55
// backend parts of the soft-float ABI.

clang/test/CodeGen/attr-target-clones-aarch64.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --check-globals --include-generated-funcs
2-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -S -emit-llvm -o - %s | FileCheck %s
3-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -target-feature -fmv -S -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -target-abi aapcs-soft -S -emit-llvm -o - %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -target-abi aapcs-soft -target-feature -fmv -S -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV
44

55
int __attribute__((target_clones("lse+aes", "sve2"))) ftc(void) { return 0; }
66
int __attribute__((target_clones("sha2", "sha2+memtag2", " default "))) ftc_def(void) { return 1; }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Hard-float, valid
2+
// RUN: %clang --target=aarch64-none-elf -c %s -o /dev/null
3+
// RUN: %clang --target=aarch64-none-elf -mabi=aapcs -c %s -o /dev/null
4+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r -c %s -o /dev/null
5+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r -mabi=aapcs -c %s -o /dev/null
6+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r+fp -mabi=aapcs -c %s -o /dev/null
7+
8+
// Soft-float, no FP
9+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r+nofp -mabi=aapcs-soft -c %s -o /dev/null
10+
// RUN: %clang --target=aarch64-none-elf -mgeneral-regs-only -mabi=aapcs-soft -c %s -o /dev/null
11+
12+
// Soft-float, FP hardware: Rejected, to avoid having two incompatible ABIs for common targets.
13+
// RUN: not %clang --target=aarch64-none-elf -mabi=aapcs-soft -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-SOFT
14+
// RUN: not %clang --target=aarch64-none-elf -march=armv8-r+fp -mabi=aapcs-soft -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-SOFT
15+
// RUN: not %clang --target=aarch64-none-elf -march=armv8-r+nofp+fp -mabi=aapcs-soft -c %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-SOFT
16+
17+
// No FP, hard-float. This is accepted by the driver, but any use of
18+
// floating-point types will be rejected by Sema (tested elsewhere).
19+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r+nofp -c %s -o /dev/null
20+
// RUN: %clang --target=aarch64-none-elf -march=armv8-r+nofp -mabi=aapcs -c %s -o /dev/null
21+
// RUN: %clang --target=aarch64-none-elf -mgeneral-regs-only -mabi=aapcs -c %s -o /dev/null
22+
23+
// INVALID-SOFT: error: 'aapcs-soft' ABI is not supported with FPU

clang/test/Preprocessor/aarch64-target-features.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,15 @@
337337

338338
// RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
339339
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
340-
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
341-
// RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto+nofp+nosimd+nocrc+nocrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
340+
// RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
341+
// RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
342342
// RUN: %clang -target aarch64 -march=armv8-a+nosimd -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-3 %s
343343
// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+crc" "-target-feature" "+crypto"
344344
// CHECK-MARCH-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-fp-armv8" "-target-feature" "-neon" "-target-feature" "-crc" "-target-feature" "-crypto"
345345
// CHECK-MARCH-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-neon"
346346

347347
// While we're checking +nofp, also make sure it stops defining __ARM_FP
348-
// RUN: %clang -target aarch64-none-linux-gnu -march=armv8-r+nofp -x c -E -dM %s -o - | FileCheck -check-prefix=CHECK-NOFP %s
348+
// RUN: %clang -target aarch64-none-linux-gnu -march=armv8-r+nofp -mabi=aapcs-soft -x c -E -dM %s -o - | FileCheck -check-prefix=CHECK-NOFP %s
349349
// CHECK-NOFP-NOT: #define __ARM_FP{{ }}
350350

351351
// Check +sm4:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +fp-armv8 -fsyntax-only -target-abi aapcs -verify=fp-hard %s
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -fsyntax-only -target-abi aapcs-soft -verify=nofp-soft %s
3+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fp-armv8 -fsyntax-only -target-abi aapcs -verify=nofp-hard %s
4+
// No run line needed for soft-float ABI with an FPU because that is rejected by the driver
5+
6+
// With the hard-float ABI and a target with an FPU, FP arguments are passed in
7+
// FP registers, no diagnostics needed.
8+
// fp-hard-no-diagnostics
9+
10+
// With the soft-float ABI, FP arguments are passed in integer registers, no
11+
// diagnostics needed.
12+
// nofp-soft-no-diagnostics
13+
14+
// With the hard-float ABI but no FPU, FP arguments cannot be passed in an
15+
// ABI-compatible way, so we report errors for these cases:
16+
17+
struct HFA {
18+
float x, y;
19+
};
20+
21+
struct non_HFA {
22+
float x;
23+
int y;
24+
};
25+
26+
float test_float_ret(void) { return 3.141f; } // #1
27+
// nofp-hard-error@#1 {{'test_float_ret' requires 'float' type support, but ABI 'aapcs' does not support it}}
28+
// nofp-hard-note@#1 {{'test_float_ret' defined here}}
29+
30+
struct HFA test_hfa_ret(void) { return (struct HFA){}; } // #2
31+
// nofp-hard-error@#2 {{'test_hfa_ret' requires 'struct HFA' type support, but ABI 'aapcs' does not support it}}
32+
// nofp-hard-note@#2 {{'test_hfa_ret' defined here}}
33+
34+
struct non_HFA test_non_hfa_ret(void) { return (struct non_HFA){}; } // #3
35+
// nofp-hard-error@#3 {{'test_non_hfa_ret' requires 'struct non_HFA' type support, but ABI 'aapcs' does not support it}}
36+
// nofp-hard-note@#3 {{'test_non_hfa_ret' defined here}}
37+
38+
void test_float_arg(float a) {} // #4
39+
// nofp-hard-error@#4 {{'test_float_arg' requires 'float' type support, but ABI 'aapcs' does not support it}}
40+
// nofp-hard-note@#4 {{'test_float_arg' defined here}}
41+
42+
void test_hfa_arg(struct HFA a) {} // #5
43+
// nofp-hard-error@#5 {{'test_hfa_arg' requires 'struct HFA' type support, but ABI 'aapcs' does not support it}}
44+
// nofp-hard-note@#5 {{'test_hfa_arg' defined here}}
45+
46+
void test_non_hfa_arg(struct non_HFA a) {} // #6
47+
// nofp-hard-error@#6 {{'test_non_hfa_arg' requires 'struct non_HFA' type support, but ABI 'aapcs' does not support it}}
48+
// nofp-hard-note@#6 {{'test_non_hfa_arg' defined here}}
49+
50+
int test_expr_float(int a) { return a + 1.0f; } // #7
51+
// nofp-hard-error@#7 {{expression requires 'float' type support, but ABI 'aapcs' does not support it}}
52+
53+
int test_expr_double(int a) { return a + 1.0; } // #8
54+
// nofp-hard-error@#8 {{expression requires 'double' type support, but ABI 'aapcs' does not support it}}

0 commit comments

Comments
 (0)