Skip to content

Commit ef395a4

Browse files
authored
[AArch64] Add soft-float ABI (#84146)
This is re-working of #74460, which adds a soft-float ABI for AArch64. That was reverted because it causes errors when building the linux and fuchsia kernels. The problem is that GCC's implementation of the ABI compatibility checks when using the hard-float ABI on a target without FP registers does it's checks after optimisation. The previous version of this patch reported errors for all uses of floating-point types, which is stricter than what GCC does in practice. This changes two things compared to the first version: * Only check the types of function arguments and returns, not the types of other values. This is more relaxed than GCC, while still guaranteeing ABI compatibility. * Move the check from Sema to CodeGen, so that inline functions are only checked if they are actually used. There are some cases in the linux kernel which depend on this behaviour of GCC.
1 parent d93363a commit ef395a4

19 files changed

+470
-47
lines changed

clang/include/clang/Basic/DiagnosticCommonKinds.td

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

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

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
281281
def err_function_needs_feature : Error<
282282
"always_inline function %1 requires target feature '%2', but would "
283283
"be inlined into function %0 that is compiled without support for '%2'">;
284+
285+
let CategoryName = "Codegen ABI Check" in {
284286
def err_function_always_inline_attribute_mismatch : Error<
285287
"always_inline function %1 and its caller %0 have mismatching %2 attributes">;
286288
def err_function_always_inline_new_za : Error<
@@ -292,6 +294,10 @@ def warn_avx_calling_convention
292294
InGroup<DiagGroup<"psabi">>;
293295
def err_avx_calling_convention : Error<warn_avx_calling_convention.Summary>;
294296

297+
def err_target_unsupported_type_for_abi
298+
: Error<"%0 requires %1 type support, but ABI '%2' does not support it">;
299+
}
300+
295301
def err_alias_to_undefined : Error<
296302
"%select{alias|ifunc}0 must point to a defined "
297303
"%select{variable or |}1function">;

clang/include/clang/Basic/DiagnosticIDs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,9 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
278278
/// category.
279279
static bool isARCDiagnostic(unsigned DiagID);
280280

281+
/// Return true if a given diagnostic is a codegen-time ABI check.
282+
static bool isCodegenABICheckDiagnostic(unsigned DiagID);
283+
281284
/// Enumeration describing how the emission of a diagnostic should
282285
/// be treated when it occurs during C++ template argument deduction.
283286
enum SFINAEResponse {

clang/lib/Basic/DiagnosticIDs.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,10 +861,18 @@ bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const {
861861
if (isARCDiagnostic(DiagID))
862862
return false;
863863

864+
if (isCodegenABICheckDiagnostic(DiagID))
865+
return false;
866+
864867
return true;
865868
}
866869

867870
bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
868871
unsigned cat = getCategoryNumberForDiag(DiagID);
869872
return DiagnosticIDs::getCategoryNameFromID(cat).starts_with("ARC ");
870873
}
874+
875+
bool DiagnosticIDs::isCodegenABICheckDiagnostic(unsigned DiagID) {
876+
unsigned cat = getCategoryNumberForDiag(DiagID);
877+
return DiagnosticIDs::getCategoryNameFromID(cat) == "Codegen ABI Check";
878+
}

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 14 additions & 2 deletions
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"
@@ -200,13 +201,23 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
200201
StringRef AArch64TargetInfo::getABI() const { return ABI; }
201202

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

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

211+
bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
212+
if (hasFeature("fp") && ABI == "aapcs-soft") {
213+
// aapcs-soft is not allowed for targets with an FPU, to avoid there being
214+
// two incomatible ABIs.
215+
Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI;
216+
return false;
217+
}
218+
return true;
219+
}
220+
210221
bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
211222
BranchProtectionInfo &BPI,
212223
StringRef &Err) const {
@@ -681,7 +692,8 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
681692
return llvm::StringSwitch<bool>(Feature)
682693
.Cases("aarch64", "arm64", "arm", true)
683694
.Case("fmv", HasFMV)
684-
.Cases("neon", "fp", "simd", FPU & NeonMode)
695+
.Case("fp", FPU & FPUMode)
696+
.Cases("neon", "simd", FPU & NeonMode)
685697
.Case("jscvt", HasJSCVT)
686698
.Case("fcma", HasFCMA)
687699
.Case("rng", HasRandGen)

clang/lib/Basic/Targets/AArch64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
201201
bool hasInt128Type() const override;
202202

203203
bool hasBitIntType() const override { return true; }
204+
205+
bool validateTarget(DiagnosticsEngine &Diags) const override;
204206
};
205207

206208
class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
13611361
FunctionArgList Args;
13621362
QualType ResTy = BuildFunctionArgList(GD, Args);
13631363

1364+
CGM.getTargetCodeGenInfo().checkFunctionABI(CGM, FD);
1365+
13641366
if (FD->isInlineBuiltinDeclaration()) {
13651367
// When generating code for a builtin with an inline declaration, use a
13661368
// mangled name to hold the actual body, while keeping an external

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
145145
Kind = AArch64ABIKind::DarwinPCS;
146146
else if (Triple.isOSWindows())
147147
return createWindowsAArch64TargetCodeGenInfo(CGM, AArch64ABIKind::Win64);
148+
else if (Target.getABI() == "aapcs-soft")
149+
Kind = AArch64ABIKind::AAPCSSoft;
148150

149151
return createAArch64TargetCodeGenInfo(CGM, Kind);
150152
}

clang/lib/CodeGen/ModuleBuilder.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ namespace {
180180

181181
bool HandleTopLevelDecl(DeclGroupRef DG) override {
182182
// FIXME: Why not return false and abort parsing?
183-
if (Diags.hasErrorOccurred())
183+
if (Diags.hasUnrecoverableErrorOccurred())
184184
return true;
185185

186186
HandlingTopLevelDeclRAII HandlingDecl(*this);
@@ -206,7 +206,7 @@ namespace {
206206
}
207207

208208
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
209-
if (Diags.hasErrorOccurred())
209+
if (Diags.hasUnrecoverableErrorOccurred())
210210
return;
211211

212212
assert(D->doesThisDeclarationHaveABody());
@@ -233,7 +233,7 @@ namespace {
233233
/// client hack on the type, which can occur at any point in the file
234234
/// (because these can be defined in declspecs).
235235
void HandleTagDeclDefinition(TagDecl *D) override {
236-
if (Diags.hasErrorOccurred())
236+
if (Diags.hasUnrecoverableErrorOccurred())
237237
return;
238238

239239
// Don't allow re-entrant calls to CodeGen triggered by PCH
@@ -269,7 +269,7 @@ namespace {
269269
}
270270

271271
void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
272-
if (Diags.hasErrorOccurred())
272+
if (Diags.hasUnrecoverableErrorOccurred())
273273
return;
274274

275275
// Don't allow re-entrant calls to CodeGen triggered by PCH
@@ -283,7 +283,7 @@ namespace {
283283

284284
void HandleTranslationUnit(ASTContext &Ctx) override {
285285
// Release the Builder when there is no error.
286-
if (!Diags.hasErrorOccurred() && Builder)
286+
if (!Diags.hasUnrecoverableErrorOccurred() && Builder)
287287
Builder->Release();
288288

289289
// If there are errors before or when releasing the Builder, reset
@@ -297,14 +297,14 @@ namespace {
297297
}
298298

299299
void AssignInheritanceModel(CXXRecordDecl *RD) override {
300-
if (Diags.hasErrorOccurred())
300+
if (Diags.hasUnrecoverableErrorOccurred())
301301
return;
302302

303303
Builder->RefreshTypeCacheForClass(RD);
304304
}
305305

306306
void CompleteTentativeDefinition(VarDecl *D) override {
307-
if (Diags.hasErrorOccurred())
307+
if (Diags.hasUnrecoverableErrorOccurred())
308308
return;
309309

310310
Builder->EmitTentativeDefinition(D);
@@ -315,7 +315,7 @@ namespace {
315315
}
316316

317317
void HandleVTable(CXXRecordDecl *RD) override {
318-
if (Diags.hasErrorOccurred())
318+
if (Diags.hasUnrecoverableErrorOccurred())
319319
return;
320320

321321
Builder->EmitVTable(RD);

clang/lib/CodeGen/TargetInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ class TargetCodeGenInfo {
8484
/// Provides a convenient hook to handle extra target-specific globals.
8585
virtual void emitTargetGlobals(CodeGen::CodeGenModule &CGM) const {}
8686

87+
/// Any further codegen related checks that need to be done on a function
88+
/// signature in a target specific manner.
89+
virtual void checkFunctionABI(CodeGenModule &CGM,
90+
const FunctionDecl *Decl) const {}
91+
8792
/// Any further codegen related checks that need to be done on a function call
8893
/// in a target specific manner.
8994
virtual void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
@@ -416,6 +421,7 @@ enum class AArch64ABIKind {
416421
AAPCS = 0,
417422
DarwinPCS,
418423
Win64,
424+
AAPCSSoft,
419425
};
420426

421427
std::unique_ptr<TargetCodeGenInfo>

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class AArch64ABIInfo : public ABIInfo {
2727
AArch64ABIInfo(CodeGenTypes &CGT, AArch64ABIKind Kind)
2828
: ABIInfo(CGT), Kind(Kind) {}
2929

30+
bool isSoftFloat() const { return Kind == AArch64ABIKind::AAPCSSoft; }
31+
3032
private:
3133
AArch64ABIKind getABIKind() const { return Kind; }
3234
bool isDarwinPCS() const { return Kind == AArch64ABIKind::DarwinPCS; }
@@ -55,8 +57,8 @@ class AArch64ABIInfo : public ABIInfo {
5557
Address EmitDarwinVAArg(Address VAListAddr, QualType Ty,
5658
CodeGenFunction &CGF) const;
5759

58-
Address EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
59-
CodeGenFunction &CGF) const;
60+
Address EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF,
61+
AArch64ABIKind Kind) const;
6062

6163
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
6264
QualType Ty) const override {
@@ -67,7 +69,7 @@ class AArch64ABIInfo : public ABIInfo {
6769

6870
return Kind == AArch64ABIKind::Win64 ? EmitMSVAArg(CGF, VAListAddr, Ty)
6971
: isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
70-
: EmitAAPCSVAArg(VAListAddr, Ty, CGF);
72+
: EmitAAPCSVAArg(VAListAddr, Ty, CGF, Kind);
7173
}
7274

7375
Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -163,6 +165,9 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
163165
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
164166
}
165167

168+
void checkFunctionABI(CodeGenModule &CGM,
169+
const FunctionDecl *Decl) const override;
170+
166171
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
167172
const FunctionDecl *Caller,
168173
const FunctionDecl *Callee,
@@ -494,6 +499,11 @@ bool AArch64SwiftABIInfo::isLegalVectorType(CharUnits VectorSize,
494499
}
495500

496501
bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
502+
// For the soft-float ABI variant, no types are considered to be homogeneous
503+
// aggregates.
504+
if (Kind == AArch64ABIKind::AAPCSSoft)
505+
return false;
506+
497507
// Homogeneous aggregates for AAPCS64 must have base types of a floating
498508
// point type or a short-vector type. This is the same as the 32-bit ABI,
499509
// but with the difference that any floating-point type is allowed,
@@ -525,7 +535,8 @@ bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate()
525535
}
526536

527537
Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
528-
CodeGenFunction &CGF) const {
538+
CodeGenFunction &CGF,
539+
AArch64ABIKind Kind) const {
529540
ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true,
530541
CGF.CurFnInfo->getCallingConvention());
531542
// Empty records are ignored for parameter passing purposes.
@@ -550,7 +561,8 @@ Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
550561
BaseTy = ArrTy->getElementType();
551562
NumRegs = ArrTy->getNumElements();
552563
}
553-
bool IsFPR = BaseTy->isFloatingPointTy() || BaseTy->isVectorTy();
564+
bool IsFPR = Kind != AArch64ABIKind::AAPCSSoft &&
565+
(BaseTy->isFloatingPointTy() || BaseTy->isVectorTy());
554566

555567
// The AArch64 va_list type and handling is specified in the Procedure Call
556568
// Standard, section B.4:
@@ -841,6 +853,34 @@ static bool isStreamingCompatible(const FunctionDecl *F) {
841853
return false;
842854
}
843855

856+
void AArch64TargetCodeGenInfo::checkFunctionABI(
857+
CodeGenModule &CGM, const FunctionDecl *FuncDecl) const {
858+
const AArch64ABIInfo &ABIInfo = getABIInfo<AArch64ABIInfo>();
859+
const TargetInfo &TI = ABIInfo.getContext().getTargetInfo();
860+
861+
// If we are using a hard-float ABI, but do not have floating point
862+
// registers, then report an error for any function arguments or returns
863+
// which would be passed in floating-pint registers.
864+
auto CheckType = [&CGM, &TI, &ABIInfo](const QualType &Ty,
865+
const NamedDecl *D) {
866+
const Type *HABase = nullptr;
867+
uint64_t HAMembers = 0;
868+
if (Ty->isFloatingType() || Ty->isVectorType() ||
869+
ABIInfo.isHomogeneousAggregate(Ty, HABase, HAMembers)) {
870+
CGM.getDiags().Report(D->getLocation(),
871+
diag::err_target_unsupported_type_for_abi)
872+
<< D->getDeclName() << Ty << TI.getABI();
873+
}
874+
};
875+
876+
if (!TI.hasFeature("fp") && !ABIInfo.isSoftFloat()) {
877+
CheckType(FuncDecl->getReturnType(), FuncDecl);
878+
for (ParmVarDecl *PVD : FuncDecl->parameters()) {
879+
CheckType(PVD->getType(), PVD);
880+
}
881+
}
882+
}
883+
844884
void AArch64TargetCodeGenInfo::checkFunctionCallABI(
845885
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
846886
const FunctionDecl *Callee, const CallArgList &Args) const {

0 commit comments

Comments
 (0)