Skip to content

[ARM] fix "+fp.dp" in multilib selection #67412

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 2 commits into from
Oct 19, 2023
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
5 changes: 5 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,11 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
if (!llvm::ARM::getFPUFeatures(FPUKind, Features))
D.Diag(clang::diag::err_drv_clang_unsupported)
<< std::string("-mfpu=") + AndroidFPU;
} else if (ArchArgFPUKind != llvm::ARM::FK_INVALID ||
CPUArgFPUKind != llvm::ARM::FK_INVALID) {
FPUKind =
CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind;
(void)llvm::ARM::getFPUFeatures(FPUKind, Features);
} else {
if (!ForAS) {
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
Expand Down
15 changes: 15 additions & 0 deletions clang/test/Driver/print-multi-selection-flags.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@
// CHECK-MVENOFP-NOT: -march=thumbv8.1m.main{{.*}}+mve.fp{{.*}}
// CHECK-MVENOFP: -mfpu=none

// RUN: %clang -print-multi-flags-experimental --target=arm-none-eabihf -march=armv8.1m.main+fp.dp | FileCheck --check-prefix=CHECK-V8_1_FP_DP %s
// CHECK-V8_1_FP_DP: -march=thumbv8.1m.main{{.*}}
// CHECK-V8_1_FP_DP: -mfloat-abi=hard
// CHECK-V8_1_FP_DP: -mfpu=fp-armv8-fullfp16-d16

// RUN: %clang -print-multi-flags-experimental --target=arm-none-eabihf -march=armv8.1m.main+nofp+fp+nofp.dp | FileCheck --check-prefix=CHECK-V8_1_NO_FP_DP %s
// CHECK-V8_1_NO_FP_DP: -march=thumbv8.1m.main{{.*}}
// CHECK-V8_1_NO_FP_DP: -mfloat-abi=hard
// CHECK-V8_1_NO_FP_DP: -mfpu=fp-armv8-fullfp16-sp-d16

// RUN: %clang -print-multi-flags-experimental --target=arm-none-eabihf -mcpu=cortex-m85+nofp.dp | FileCheck --check-prefix=CHECK-M85_NO_FP_DP %s
// CHECK-M85_NO_FP_DP: -march=thumbv8.1m.main{{.*}}
// CHECK-M85_NO_FP_DP: -mfloat-abi=hard
// CHECK-M85_NO_FP_DP: -mfpu=fp-armv8-fullfp16-sp-d16

// RUN: %clang -print-multi-flags-experimental --target=aarch64-none-elf -march=armv8-a+lse | FileCheck --check-prefix=CHECK-LSE %s
// CHECK-LSE: -march=aarch64{{.*}}+lse{{.*}}

Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/TargetParser/ARMTargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,14 @@ enum class FPURestriction {
SP_D16 ///< Only single-precision instructions, with 16 D registers
};

inline bool isDoublePrecision(const FPURestriction restriction) {
return restriction != FPURestriction::SP_D16;
}

inline bool has32Regs(const FPURestriction restriction) {
return restriction == FPURestriction::None;
}

// An FPU name implies one of three levels of Neon support:
enum class NeonSupportLevel {
None = 0, ///< No Neon
Expand Down
70 changes: 55 additions & 15 deletions llvm/lib/TargetParser/ARMTargetParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,26 +366,51 @@ StringRef ARM::getArchExtFeature(StringRef ArchExt) {
}

static ARM::FPUKind findDoublePrecisionFPU(ARM::FPUKind InputFPUKind) {
if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE)
return ARM::FK_INVALID;

const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];

// If the input FPU already supports double-precision, then there
// isn't any different FPU we can return here.
//
// The current available FPURestriction values are None (no
// restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
// and single precision only); there's no value representing
// SP restriction without D16. So this test just means 'is it
// SP only?'.
if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
if (ARM::isDoublePrecision(InputFPU.Restriction))
return InputFPUKind;

// Otherwise, look for an FPU entry with all the same fields, except
// that it supports double precision.
for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
ARM::has32Regs(CandidateFPU.Restriction) ==
ARM::has32Regs(InputFPU.Restriction) &&
ARM::isDoublePrecision(CandidateFPU.Restriction)) {
return CandidateFPU.ID;
}
}

// nothing found
return ARM::FK_INVALID;
}

static ARM::FPUKind findSinglePrecisionFPU(ARM::FPUKind InputFPUKind) {
if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE)
return ARM::FK_INVALID;

const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];

// If the input FPU already is single-precision only, then there
// isn't any different FPU we can return here.
if (!ARM::isDoublePrecision(InputFPU.Restriction))
return InputFPUKind;

// Otherwise, look for an FPU entry with all the same fields, except
// that SP_D16 has been replaced with just D16, representing adding
// double precision and not changing anything else.
// that it does not support double precision.
for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
CandidateFPU.Restriction == ARM::FPURestriction::D16) {
ARM::has32Regs(CandidateFPU.Restriction) ==
ARM::has32Regs(InputFPU.Restriction) &&
!ARM::isDoublePrecision(CandidateFPU.Restriction)) {
return CandidateFPU.ID;
}
}
Expand Down Expand Up @@ -420,20 +445,35 @@ bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK,
CPU = "generic";

if (ArchExt == "fp" || ArchExt == "fp.dp") {
const ARM::FPUKind DefaultFPU = getDefaultFPU(CPU, AK);
ARM::FPUKind FPUKind;
if (ArchExt == "fp.dp") {
const bool IsDP = ArgFPUKind != ARM::FK_INVALID &&
ArgFPUKind != ARM::FK_NONE &&
isDoublePrecision(getFPURestriction(ArgFPUKind));
if (Negated) {
Features.push_back("-fp64");
return true;
/* If there is no FPU selected yet, we still need to set ArgFPUKind, as
* leaving it as FK_INVALID, would cause default FPU to be selected
* later and that could be double precision one. */
if (ArgFPUKind != ARM::FK_INVALID && !IsDP)
return true;
FPUKind = findSinglePrecisionFPU(DefaultFPU);
if (FPUKind == ARM::FK_INVALID)
FPUKind = ARM::FK_NONE;
} else {
if (IsDP)
return true;
FPUKind = findDoublePrecisionFPU(DefaultFPU);
if (FPUKind == ARM::FK_INVALID)
return false;
}
FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
} else if (Negated) {
FPUKind = ARM::FK_NONE;
} else {
FPUKind = getDefaultFPU(CPU, AK);
FPUKind = DefaultFPU;
}
ArgFPUKind = FPUKind;
return ARM::getFPUFeatures(FPUKind, Features);
return true;
}
return StartingNumFeatures != Features.size();
}
Expand Down