[clang] [ARM] fix "+fp.dp" in multilib selection (PR #67412)

Dominik Wójt via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 26 02:59:47 PDT 2023


https://github.com/domin144 created https://github.com/llvm/llvm-project/pull/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.

>From 4cc2328982cc8260263aa803f2b02bff7d7b4a85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20W=C3=B3jt?= <dominik.wojt at arm.com>
Date: Wed, 20 Sep 2023 16:39:27 +0200
Subject: [PATCH] [ARM] fix "+fp.dp" in multilib selection

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.
---
 clang/lib/Driver/ToolChains/Arch/ARM.cpp      |  5 ++
 .../test/Driver/print-multi-selection-flags.c | 10 +++
 .../llvm/TargetParser/ARMTargetParser.h       |  8 +++
 llvm/lib/TargetParser/ARMTargetParser.cpp     | 69 +++++++++++++++----
 4 files changed, 77 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index bb66db5feae8c3b..9a042d351bda0b6 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -626,6 +626,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);
diff --git a/clang/test/Driver/print-multi-selection-flags.c b/clang/test/Driver/print-multi-selection-flags.c
index 819ff242ced0026..f020a22ea128aac 100644
--- a/clang/test/Driver/print-multi-selection-flags.c
+++ b/clang/test/Driver/print-multi-selection-flags.c
@@ -35,6 +35,16 @@
 // 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 -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{{.*}}
 
diff --git a/llvm/include/llvm/TargetParser/ARMTargetParser.h b/llvm/include/llvm/TargetParser/ARMTargetParser.h
index b893eab1902f81b..c42d66f048fccc0 100644
--- a/llvm/include/llvm/TargetParser/ARMTargetParser.h
+++ b/llvm/include/llvm/TargetParser/ARMTargetParser.h
@@ -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
diff --git a/llvm/lib/TargetParser/ARMTargetParser.cpp b/llvm/lib/TargetParser/ARMTargetParser.cpp
index c84928eeb07b140..524bb4e0fd0db22 100644
--- a/llvm/lib/TargetParser/ARMTargetParser.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParser.cpp
@@ -366,26 +366,50 @@ 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 (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 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)
-    return ARM::FK_INVALID;
+  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;
     }
   }
@@ -420,20 +444,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();
 }



More information about the cfe-commits mailing list