[clang] [llvm] [clang][Driver] Pass -machine argument to the linker explicitly for ARM64EC targets. (PR #86835)

via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 27 10:15:23 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-driver

Author: Jacek Caban (cjacek)

<details>
<summary>Changes</summary>

Currently, Clang doesn't explicitly pass the `-machine` argument to the linker, relying on the linker to infer it from the input. However, MSVC's link.exe requires `-machine` to be specified explicitly for ARM64EC/ARM64X targets. Although lld-link allows inferring the target from ARM64EC object files, this detection isn't entirely reliable as AMD64 object files are also valid input for ARM64EC target.

Handling of `-machine:arm64ec` is straightforward. For ARM64X, this PR extends the ARM64EC target triple to accept the "arm64x" subarch string, which serves as an alias to "arm64ec" in most cases. However, during linker invocation, "arm64x" distinguishes between `-machine:arm64ec` and `-machine:arm64x`.

The only analogue to MSVC's behavior is `cl.exe -arm64EC`, which is handled by `-machine:arm64ec` part of this PR. As far as I can tell, linking ARM64X images with MSVC requires a direct link.exe invocation. In cases like lib.exe (#<!-- -->85972) or some
aspects of link.exe, `-machine:arm64x` serves as an alias to `-machine:arm64ec` too.

(BTW, meantime, I worked around it with `-Wl,-machine:...`).
CC @<!-- -->bylaws 

---
Full diff: https://github.com/llvm/llvm-project/pull/86835.diff


6 Files Affected:

- (modified) clang/lib/Driver/Driver.cpp (+1-2) 
- (modified) clang/lib/Driver/ToolChains/MSVC.cpp (+7) 
- (modified) clang/test/Driver/msvc-link.c (+6) 
- (modified) llvm/include/llvm/TargetParser/Triple.h (+3-1) 
- (modified) llvm/lib/TargetParser/Triple.cpp (+5-4) 
- (modified) llvm/unittests/TargetParser/TripleTest.cpp (+25) 


``````````diff
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 7a53764364ce4d..328ea93b679293 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1458,8 +1458,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
   }
 
   // Report warning when arm64EC option is overridden by specified target
-  if ((TC.getTriple().getArch() != llvm::Triple::aarch64 ||
-       TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) &&
+  if (!TC.getTriple().isWindowsArm64EC() &&
       UArgs->hasArg(options::OPT__SLASH_arm64EC)) {
     getDiags().Report(clang::diag::warn_target_override_arm64ec)
         << TC.getTriple().str();
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index dc534a33e6d0ef..edf81ce7e425be 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -79,6 +79,13 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back(
         Args.MakeArgString(std::string("-out:") + Output.getFilename()));
 
+  if (TC.getTriple().isWindowsArm64EC()) {
+    if (TC.getTriple().getSubArch() == llvm::Triple::AArch64SubArch_arm64x)
+      CmdArgs.push_back("-machine:arm64x");
+    else
+      CmdArgs.push_back("-machine:arm64ec");
+  }
+
   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
       !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
     CmdArgs.push_back("-defaultlib:libcmt");
diff --git a/clang/test/Driver/msvc-link.c b/clang/test/Driver/msvc-link.c
index 64e099ea63042f..03ba3cd5805188 100644
--- a/clang/test/Driver/msvc-link.c
+++ b/clang/test/Driver/msvc-link.c
@@ -36,3 +36,9 @@
 // VFSOVERLAY: "--vfsoverlay"
 // VFSOVERLAY: lld-link
 // VFSOVERLAY: "/vfsoverlay:{{.*}}" "{{.*}}.obj"
+
+// RUN: %clang -target arm64ec-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | FileCheck --check-prefix=ARM64EC %s
+// ARM64EC: "-machine:arm64ec"
+
+// RUN: %clang -target arm64x-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | FileCheck --check-prefix=ARM64X %s
+// ARM64X: "-machine:arm64x"
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index f256e2b205a889..fb55011d68c6bf 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -148,6 +148,7 @@ class Triple {
 
     AArch64SubArch_arm64e,
     AArch64SubArch_arm64ec,
+    AArch64SubArch_arm64x,
 
     KalimbaSubArch_v3,
     KalimbaSubArch_v4,
@@ -623,7 +624,8 @@ class Triple {
   // Checks if we're using the Windows Arm64EC ABI.
   bool isWindowsArm64EC() const {
     return getArch() == Triple::aarch64 &&
-           getSubArch() == Triple::AArch64SubArch_arm64ec;
+           (getSubArch() == Triple::AArch64SubArch_arm64ec ||
+            getSubArch() == Triple::AArch64SubArch_arm64x);
   }
 
   bool isWindowsCoreCLREnvironment() const {
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index 624679ff507a7f..29c634eec7866a 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -110,7 +110,7 @@ StringRef Triple::getArchName(ArchType Kind, SubArchType SubArch) {
       return "mipsisa64r6el";
     break;
   case Triple::aarch64:
-    if (SubArch == AArch64SubArch_arm64ec)
+    if (SubArch == AArch64SubArch_arm64ec || SubArch == AArch64SubArch_arm64x)
       return "arm64ec";
     if (SubArch == AArch64SubArch_arm64e)
       return "arm64e";
@@ -515,10 +515,8 @@ static Triple::ArchType parseArch(StringRef ArchName) {
     .Case("aarch64_be", Triple::aarch64_be)
     .Case("aarch64_32", Triple::aarch64_32)
     .Case("arc", Triple::arc)
-    .Case("arm64", Triple::aarch64)
+    .Cases("arm64", "arm64e", "arm64ec", "arm64x", Triple::aarch64)
     .Case("arm64_32", Triple::aarch64_32)
-    .Case("arm64e", Triple::aarch64)
-    .Case("arm64ec", Triple::aarch64)
     .Case("arm", Triple::arm)
     .Case("armeb", Triple::armeb)
     .Case("thumb", Triple::thumb)
@@ -729,6 +727,9 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {
   if (SubArchName == "arm64ec")
     return Triple::AArch64SubArch_arm64ec;
 
+  if (SubArchName == "arm64x")
+    return Triple::AArch64SubArch_arm64x;
+
   if (SubArchName.starts_with("spirv"))
     return StringSwitch<Triple::SubArchType>(SubArchName)
         .EndsWith("v1.0", Triple::SPIRVSubArch_v10)
diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp
index e1e1bbd76ecda6..76a22c5995c42b 100644
--- a/llvm/unittests/TargetParser/TripleTest.cpp
+++ b/llvm/unittests/TargetParser/TripleTest.cpp
@@ -2226,6 +2226,16 @@ TEST(TripleTest, ParseARMArch) {
     T.setArch(Triple::aarch64, Triple::AArch64SubArch_arm64ec);
     EXPECT_EQ("arm64ec", T.getArchName());
   }
+  {
+    Triple T = Triple("arm64x");
+    EXPECT_EQ(Triple::aarch64, T.getArch());
+    EXPECT_EQ(Triple::AArch64SubArch_arm64x, T.getSubArch());
+  }
+  {
+    Triple T;
+    T.setArch(Triple::aarch64, Triple::AArch64SubArch_arm64x);
+    EXPECT_EQ("arm64ec", T.getArchName());
+  }
 }
 
 TEST(TripleTest, isArmT32) {
@@ -2371,4 +2381,19 @@ TEST(TripleTest, isArmMClass) {
     EXPECT_TRUE(T.isArmMClass());
   }
 }
+
+TEST(TripleTest, isWindowsArm64EC) {
+  {
+    Triple T = Triple("arm64ec");
+    EXPECT_TRUE(T.isWindowsArm64EC());
+  }
+  {
+    Triple T = Triple("arm64x");
+    EXPECT_TRUE(T.isWindowsArm64EC());
+  }
+  {
+    Triple T = Triple("aarch64");
+    EXPECT_FALSE(T.isWindowsArm64EC());
+  }
+}
 } // end anonymous namespace

``````````

</details>


https://github.com/llvm/llvm-project/pull/86835


More information about the cfe-commits mailing list