Skip to content

Commit b3c4f64

Browse files
authored
[ARM] fix "+fp.dp" in multilib selection (llvm#67412)
When the FPU was selected with "+(no)fp(.dp)" extensions in "-march" or "-mcpu" options, the FPU used for multilib selection was still the default one for given architecture or CPU.
1 parent 202de4a commit b3c4f64

File tree

4 files changed

+83
-15
lines changed

4 files changed

+83
-15
lines changed

clang/lib/Driver/ToolChains/Arch/ARM.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,11 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
627627
if (!llvm::ARM::getFPUFeatures(FPUKind, Features))
628628
D.Diag(clang::diag::err_drv_clang_unsupported)
629629
<< std::string("-mfpu=") + AndroidFPU;
630+
} else if (ArchArgFPUKind != llvm::ARM::FK_INVALID ||
631+
CPUArgFPUKind != llvm::ARM::FK_INVALID) {
632+
FPUKind =
633+
CPUArgFPUKind != llvm::ARM::FK_INVALID ? CPUArgFPUKind : ArchArgFPUKind;
634+
(void)llvm::ARM::getFPUFeatures(FPUKind, Features);
630635
} else {
631636
if (!ForAS) {
632637
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);

clang/test/Driver/print-multi-selection-flags.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@
3535
// CHECK-MVENOFP-NOT: -march=thumbv8.1m.main{{.*}}+mve.fp{{.*}}
3636
// CHECK-MVENOFP: -mfpu=none
3737

38+
// 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
39+
// CHECK-V8_1_FP_DP: -march=thumbv8.1m.main{{.*}}
40+
// CHECK-V8_1_FP_DP: -mfloat-abi=hard
41+
// CHECK-V8_1_FP_DP: -mfpu=fp-armv8-fullfp16-d16
42+
43+
// 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
44+
// CHECK-V8_1_NO_FP_DP: -march=thumbv8.1m.main{{.*}}
45+
// CHECK-V8_1_NO_FP_DP: -mfloat-abi=hard
46+
// CHECK-V8_1_NO_FP_DP: -mfpu=fp-armv8-fullfp16-sp-d16
47+
48+
// RUN: %clang -print-multi-flags-experimental --target=arm-none-eabihf -mcpu=cortex-m85+nofp.dp | FileCheck --check-prefix=CHECK-M85_NO_FP_DP %s
49+
// CHECK-M85_NO_FP_DP: -march=thumbv8.1m.main{{.*}}
50+
// CHECK-M85_NO_FP_DP: -mfloat-abi=hard
51+
// CHECK-M85_NO_FP_DP: -mfpu=fp-armv8-fullfp16-sp-d16
52+
3853
// RUN: %clang -print-multi-flags-experimental --target=aarch64-none-elf -march=armv8-a+lse | FileCheck --check-prefix=CHECK-LSE %s
3954
// CHECK-LSE: -march=aarch64{{.*}}+lse{{.*}}
4055

llvm/include/llvm/TargetParser/ARMTargetParser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ enum class FPURestriction {
143143
SP_D16 ///< Only single-precision instructions, with 16 D registers
144144
};
145145

146+
inline bool isDoublePrecision(const FPURestriction restriction) {
147+
return restriction != FPURestriction::SP_D16;
148+
}
149+
150+
inline bool has32Regs(const FPURestriction restriction) {
151+
return restriction == FPURestriction::None;
152+
}
153+
146154
// An FPU name implies one of three levels of Neon support:
147155
enum class NeonSupportLevel {
148156
None = 0, ///< No Neon

llvm/lib/TargetParser/ARMTargetParser.cpp

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -366,26 +366,51 @@ StringRef ARM::getArchExtFeature(StringRef ArchExt) {
366366
}
367367

368368
static ARM::FPUKind findDoublePrecisionFPU(ARM::FPUKind InputFPUKind) {
369+
if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE)
370+
return ARM::FK_INVALID;
371+
369372
const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
370373

371374
// If the input FPU already supports double-precision, then there
372375
// isn't any different FPU we can return here.
373-
//
374-
// The current available FPURestriction values are None (no
375-
// restriction), D16 (only 16 d-regs) and SP_D16 (16 d-regs
376-
// and single precision only); there's no value representing
377-
// SP restriction without D16. So this test just means 'is it
378-
// SP only?'.
379-
if (InputFPU.Restriction != ARM::FPURestriction::SP_D16)
376+
if (ARM::isDoublePrecision(InputFPU.Restriction))
377+
return InputFPUKind;
378+
379+
// Otherwise, look for an FPU entry with all the same fields, except
380+
// that it supports double precision.
381+
for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
382+
if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
383+
CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
384+
ARM::has32Regs(CandidateFPU.Restriction) ==
385+
ARM::has32Regs(InputFPU.Restriction) &&
386+
ARM::isDoublePrecision(CandidateFPU.Restriction)) {
387+
return CandidateFPU.ID;
388+
}
389+
}
390+
391+
// nothing found
392+
return ARM::FK_INVALID;
393+
}
394+
395+
static ARM::FPUKind findSinglePrecisionFPU(ARM::FPUKind InputFPUKind) {
396+
if (InputFPUKind == ARM::FK_INVALID || InputFPUKind == ARM::FK_NONE)
380397
return ARM::FK_INVALID;
381398

399+
const ARM::FPUName &InputFPU = ARM::FPUNames[InputFPUKind];
400+
401+
// If the input FPU already is single-precision only, then there
402+
// isn't any different FPU we can return here.
403+
if (!ARM::isDoublePrecision(InputFPU.Restriction))
404+
return InputFPUKind;
405+
382406
// Otherwise, look for an FPU entry with all the same fields, except
383-
// that SP_D16 has been replaced with just D16, representing adding
384-
// double precision and not changing anything else.
407+
// that it does not support double precision.
385408
for (const ARM::FPUName &CandidateFPU : ARM::FPUNames) {
386409
if (CandidateFPU.FPUVer == InputFPU.FPUVer &&
387410
CandidateFPU.NeonSupport == InputFPU.NeonSupport &&
388-
CandidateFPU.Restriction == ARM::FPURestriction::D16) {
411+
ARM::has32Regs(CandidateFPU.Restriction) ==
412+
ARM::has32Regs(InputFPU.Restriction) &&
413+
!ARM::isDoublePrecision(CandidateFPU.Restriction)) {
389414
return CandidateFPU.ID;
390415
}
391416
}
@@ -420,20 +445,35 @@ bool ARM::appendArchExtFeatures(StringRef CPU, ARM::ArchKind AK,
420445
CPU = "generic";
421446

422447
if (ArchExt == "fp" || ArchExt == "fp.dp") {
448+
const ARM::FPUKind DefaultFPU = getDefaultFPU(CPU, AK);
423449
ARM::FPUKind FPUKind;
424450
if (ArchExt == "fp.dp") {
451+
const bool IsDP = ArgFPUKind != ARM::FK_INVALID &&
452+
ArgFPUKind != ARM::FK_NONE &&
453+
isDoublePrecision(getFPURestriction(ArgFPUKind));
425454
if (Negated) {
426-
Features.push_back("-fp64");
427-
return true;
455+
/* If there is no FPU selected yet, we still need to set ArgFPUKind, as
456+
* leaving it as FK_INVALID, would cause default FPU to be selected
457+
* later and that could be double precision one. */
458+
if (ArgFPUKind != ARM::FK_INVALID && !IsDP)
459+
return true;
460+
FPUKind = findSinglePrecisionFPU(DefaultFPU);
461+
if (FPUKind == ARM::FK_INVALID)
462+
FPUKind = ARM::FK_NONE;
463+
} else {
464+
if (IsDP)
465+
return true;
466+
FPUKind = findDoublePrecisionFPU(DefaultFPU);
467+
if (FPUKind == ARM::FK_INVALID)
468+
return false;
428469
}
429-
FPUKind = findDoublePrecisionFPU(getDefaultFPU(CPU, AK));
430470
} else if (Negated) {
431471
FPUKind = ARM::FK_NONE;
432472
} else {
433-
FPUKind = getDefaultFPU(CPU, AK);
473+
FPUKind = DefaultFPU;
434474
}
435475
ArgFPUKind = FPUKind;
436-
return ARM::getFPUFeatures(FPUKind, Features);
476+
return true;
437477
}
438478
return StartingNumFeatures != Features.size();
439479
}

0 commit comments

Comments
 (0)