https://github.com/cjacek created https://github.com/llvm/llvm-project/pull/207612
When -marm64x is used during the assembly phase, construct jobs for both native and EC targets and merge their outputs using llvm-objcopy. Allow passing ArchName to computeTargetTriple on non-Darwin targets to enable BindArchAction on other platforms. Additionally, allow passing multiple inputs to ObjcopyJobAction and use this capability to construct ARM64X merge jobs. >From c4e059d4038f245d97f3a3a514f997d3e6a95656 Mon Sep 17 00:00:00 2001 From: Jacek Caban <[email protected]> Date: Wed, 1 Apr 2026 16:18:07 +0200 Subject: [PATCH] [clang][ARM64X] Support compiling both native and EC objects with -marm64x When -marm64x is used during the assembly phase, construct jobs for both native and EC targets and merge their outputs using llvm-objcopy. Allow passing ArchName to computeTargetTriple on non-Darwin targets to enable BindArchAction on other platforms. Additionally, allow passing multiple inputs to ObjcopyJobAction and use this capability to construct ARM64X merge jobs. --- clang/include/clang/Driver/Action.h | 2 +- clang/include/clang/Options/Options.td | 2 +- clang/lib/Driver/Action.cpp | 4 +-- clang/lib/Driver/Driver.cpp | 37 +++++++++++++++++++------- clang/lib/Driver/ToolChain.cpp | 4 ++- clang/lib/Driver/ToolChains/MSVC.cpp | 36 +++++++++++++++++++++++++ clang/lib/Driver/ToolChains/MSVC.h | 16 +++++++++++ clang/lib/Driver/ToolChains/MinGW.cpp | 4 +++ clang/lib/Driver/ToolChains/MinGW.h | 2 ++ clang/test/Driver/arm64x.c | 6 +++++ clang/test/Driver/msvc-link.c | 4 +-- 11 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 clang/test/Driver/arm64x.c diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h index bbd6f03dd30da..306db1be15910 100644 --- a/clang/include/clang/Driver/Action.h +++ b/clang/include/clang/Driver/Action.h @@ -695,7 +695,7 @@ class ObjcopyJobAction : public JobAction { void anchor() override; public: - ObjcopyJobAction(Action *Input, types::ID Type); + ObjcopyJobAction(ActionList &Inputs, types::ID Type); static bool classof(const Action *A) { return A->getKind() == ObjcopyJobClass; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 35b0390bd2fc0..d577c09a65f51 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5467,7 +5467,7 @@ def municode : Joined<["-"], "municode">, Group<m_Group>; def mthreads : Joined<["-"], "mthreads">, Group<m_Group>; def marm64x : Joined<["-"], "marm64x">, Group<m_Group>, Visibility<[ClangOption, CLOption]>, - HelpText<"Link as a hybrid ARM64X image">; + HelpText<"Build as a hybrid ARM64X image">; def mguard_EQ : Joined<["-"], "mguard=">, Group<m_Group>, HelpText<"Enable or disable Control Flow Guard checks and guard tables emission">, Values<"none,cf,cf-nochecks">; diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp index c0b84ffcc95be..b74ae925e922c 100644 --- a/clang/lib/Driver/Action.cpp +++ b/clang/lib/Driver/Action.cpp @@ -470,5 +470,5 @@ BinaryTranslatorJobAction::BinaryTranslatorJobAction(Action *Input, void ObjcopyJobAction::anchor() {} -ObjcopyJobAction::ObjcopyJobAction(Action *Input, types::ID Type) - : JobAction(ObjcopyJobClass, Input, Type) {} +ObjcopyJobAction::ObjcopyJobAction(ActionList &Inputs, types::ID Type) + : JobAction(ObjcopyJobClass, Inputs, Type) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 1a91b353a27e4..7adc60ed9f97f 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -616,10 +616,9 @@ static void setZosTargetVersion(const Driver &D, llvm::Triple &Target, /// /// This routine provides the logic to compute a target triple from various /// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(const Driver &D, - StringRef TargetTriple, +static llvm::Triple computeTargetTriple(const Driver &D, StringRef TargetTriple, const ArgList &Args, - StringRef DarwinArchName = "") { + StringRef ArchName = "") { // FIXME: Already done in Compilation *Driver::BuildCompilation if (const Arg *A = Args.getLastArg(options::OPT_target)) TargetTriple = A->getValue(); @@ -635,9 +634,8 @@ static llvm::Triple computeTargetTriple(const Driver &D, // Handle Apple-specific options available here. if (Target.isOSBinFormatMachO()) { // If an explicit Darwin arch name is given, that trumps all. - if (!DarwinArchName.empty()) { - tools::darwin::setTripleTypeForMachOArchName(Target, DarwinArchName, - Args); + if (!ArchName.empty()) { + tools::darwin::setTripleTypeForMachOArchName(Target, ArchName, Args); return llvm::Triple(Target.normalize()); } @@ -646,6 +644,9 @@ static llvm::Triple computeTargetTriple(const Driver &D, StringRef ArchName = A->getValue(); tools::darwin::setTripleTypeForMachOArchName(Target, ArchName, Args); } + } else if (!ArchName.empty()) { + Target.setArchName(ArchName); + return Target; } // Handle pseudo-target flags '-mlittle-endian'/'-EL' and @@ -703,6 +704,11 @@ static llvm::Triple computeTargetTriple(const Driver &D, D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << Target.str(); + // The `-marm64x` flag is only valid for Windows targets. + if (Args.hasArgNoClaim(options::OPT_marm64x) && !Target.isOSWindows()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << "-marm64x" << Target.str(); + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, options::OPT_m32, options::OPT_m16, @@ -4807,9 +4813,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (TC.requiresObjcopy(Args)) { Action *LastAction = Actions.back(); // llvm-objcopy expects an unvalidated DXIL container (TY_OBJECT). - if (LastAction->getType() == types::TY_Object) + if (LastAction->getType() == types::TY_Object) { + ActionList ObjcopyActions({LastAction}); Actions.push_back( - C.MakeAction<ObjcopyJobAction>(LastAction, types::TY_Object)); + C.MakeAction<ObjcopyJobAction>(ObjcopyActions, types::TY_Object)); + } } // Call validator when -Vd not in Args. @@ -5401,6 +5409,16 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm); } case phases::Assemble: + // When -marm64x is used, construct jobs for the EC and native targets and + // merge them into an archive with llvm-objcopy. + if (Args.hasArg(options::OPT_marm64x)) { + Action *Act = + C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object); + ActionList Inputs; + Inputs.push_back(C.MakeAction<BindArchAction>(Act, BoundArch("arm64ec"))); + Inputs.push_back(C.MakeAction<BindArchAction>(Act, BoundArch("aarch64"))); + return C.MakeAction<ObjcopyJobAction>(Inputs, types::TY_Object); + } return C.MakeAction<AssembleJobAction>(std::move(Input), types::TY_Object); } @@ -5495,7 +5513,8 @@ void Driver::BuildJobs(Compilation &C) const { BuildJobsForAction(C, A, &C.getDefaultToolChain(), /*BA=*/{}, /*AtTopLevel*/ true, - /*MultipleArchs*/ ArchNames.size() > 1, + /*MultipleArchs*/ ArchNames.size() > 1 || + C.getArgs().hasArgNoClaim(options::OPT_marm64x), /*LinkingOutput*/ LinkingOutput, CachedResults, /*TargetDeviceOffloadKind*/ Action::OFK_None); } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 21d2fbef59fc6..9230e4dae548f 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -801,9 +801,11 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::VerifyDebugInfoJobClass: case Action::BinaryAnalyzeJobClass: case Action::BinaryTranslatorJobClass: - case Action::ObjcopyJobClass: llvm_unreachable("Invalid tool kind."); + case Action::ObjcopyJobClass: + return nullptr; + case Action::CompileJobClass: case Action::PrecompileJobClass: case Action::PreprocessJobClass: diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index eb81f1b4e142c..d826b81f0dd3b 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -498,6 +498,31 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::move(LinkCmd)); } +void tools::ARM64XObjcopy::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + // Assume llvm-objcopy is only used for hybrid ARM64X object files. + if (Inputs.size() != 2) + return; + + std::string ObjcopyPath = getToolChain().GetProgramPath("llvm-objcopy"); + const char *Exec = Args.MakeArgString(ObjcopyPath); + + // Embed the hybrid object in the .obj.arm64ec section. + ArgStringList CmdArgs; + CmdArgs.push_back(Args.MakeArgString("--add-section=.obj.arm64ec=" + + Twine(Inputs[0].getFilename()))); + // Mark the .obj.arm64ec section as discardable. + CmdArgs.push_back("--set-section-flags=.obj.arm64ec=debug"); + CmdArgs.push_back(Inputs[1].getFilename()); + CmdArgs.push_back(Output.getFilename()); + + C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs, Output)); +} + MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), @@ -531,6 +556,17 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, loadMultilibsFromYAML(Args, D); } +Tool *MSVCToolChain::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::ObjcopyJobClass: + if (!Objcopy) + Objcopy.reset(new tools::ARM64XObjcopy(*this)); + return Objcopy.get(); + default: + return ToolChain::getTool(AC); + } +} + Tool *MSVCToolChain::buildLinker() const { return new tools::visualstudio::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 0ec73fb59b921..6878d6a195d78 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -39,6 +39,19 @@ class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { }; } // end namespace visualstudio +class LLVM_LIBRARY_VISIBILITY ARM64XObjcopy : public Tool { +public: + ARM64XObjcopy(const ToolChain &TC) + : Tool("ARM64XObjcopy", "llvm-objcopy", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + } // end namespace tools namespace toolchains { @@ -137,8 +150,10 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { const Twine &subfolder2 = "", const Twine &subfolder3 = "") const; + Tool *getTool(Action::ActionClass AC) const override; Tool *buildLinker() const override; Tool *buildAssembler() const override; + private: std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot; std::string VCToolChainPath; @@ -146,6 +161,7 @@ class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { LazyDetector<CudaInstallationDetector> CudaInstallation; LazyDetector<RocmInstallationDetector> RocmInstallation; LazyDetector<SYCLInstallationDetector> SYCLInstallation; + mutable std::unique_ptr<tools::ARM64XObjcopy> Objcopy; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 4237a6906be3b..7fe5be92012ee 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -575,6 +575,10 @@ Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { if (!Compiler) Compiler.reset(new tools::gcc::Compiler(*this)); return Compiler.get(); + case Action::ObjcopyJobClass: + if (!Objcopy) + Objcopy.reset(new tools::ARM64XObjcopy(*this)); + return Objcopy.get(); default: return ToolChain::getTool(AC); } diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index 36ab7b6c6e295..c8b7a73af0a2d 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -11,6 +11,7 @@ #include "Cuda.h" #include "Gnu.h" +#include "MSVC.h" #include "clang/Driver/CudaInstallationDetector.h" #include "clang/Driver/LazyDetector.h" #include "clang/Driver/RocmInstallationDetector.h" @@ -117,6 +118,7 @@ class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { std::string TripleDirName; mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; mutable std::unique_ptr<tools::gcc::Compiler> Compiler; + mutable std::unique_ptr<tools::ARM64XObjcopy> Objcopy; void findGccLibDir(const llvm::Triple &LiteralTriple); bool NativeLLVMSupport; diff --git a/clang/test/Driver/arm64x.c b/clang/test/Driver/arm64x.c new file mode 100644 index 0000000000000..34b50d9133d14 --- /dev/null +++ b/clang/test/Driver/arm64x.c @@ -0,0 +1,6 @@ +// RUN: %clang -c -marm64x --target=arm64ec-pc-windows-msvc -### %s 2>&1 | FileCheck %s +// RUN: %clang -c -marm64x --target=arm64ec-pc-windows-gnu -### %s 2>&1 | FileCheck %s + +// CHECK: "-cc1" "-triple" "arm64ec-pc-windows-{{.*}}" "-emit-obj" +// CHECK-NEXT: "-cc1" "-triple" "aarch64-pc-windows-{{.*}}" "-emit-obj" +// CHECK-NEXT: llvm-objcopy" "--add-section=.obj.arm64ec={{.*}}arm64x-arm64ec-{{.*}}.o" "--set-section-flags=.obj.arm64ec=debug" "{{.*}}arm64x-aarch64-{{.*}}.o" "arm64x.o" diff --git a/clang/test/Driver/msvc-link.c b/clang/test/Driver/msvc-link.c index 5cb1653bf4db9..19027ff3e80ff 100644 --- a/clang/test/Driver/msvc-link.c +++ b/clang/test/Driver/msvc-link.c @@ -46,9 +46,9 @@ // ARM64X: "-machine:arm64x" // RUN: not %clang --target=x86_64-linux-gnu -marm64x -### %s 2>&1 | FileCheck --check-prefix=HYBRID-ERR %s -// HYBRID-ERR: error: unsupported option '-marm64x' for target 'x86_64-linux-gnu' +// HYBRID-ERR: error: unsupported option '-marm64x' for target 'x86_64-unknown-linux-gnu' -// RUN: %clang -c -marm64x --target=arm64ec-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | \ +// RUN: %clang -S -marm64x --target=arm64ec-pc-windows-msvc -fuse-ld=link -### %s 2>&1 | \ // RUN: FileCheck --check-prefix=HYBRID-WARN %s // HYBRID-WARN: warning: argument unused during compilation: '-marm64x' [-Wunused-command-line-argument] _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
