This is an archive of the discontinued LLVM Phabricator instance.

[ARM64EC 2/?] Add target triple, and allow targeting it.
ClosedPublic

Authored by efriedma on May 11 2022, 1:29 PM.

Details

Summary

Part of patchset to add initial support for ARM64EC.

Per discussion on review, using the triple arm64ec-pc-windows-msvc. The parsing works the same way as Apple's alternate Arm ABI "arm64e".

Diff Detail

Event Timeline

efriedma created this revision.May 11 2022, 1:29 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 11 2022, 1:29 PM
efriedma requested review of this revision.May 11 2022, 1:30 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 11 2022, 1:30 PM

For lack of any better idea, I'm using the triple aarch64-pc-windows-msvc_arm64ec. Suggestions for a better name welcome... or if you think I should use some other mechanism to distinguish.

I'm not 100% sold on using msvc_arm64ec like this... If we'd want to use this ABI mode for mingw targets too (not quite sure right now if it's doable and something that one wants to do at some point, or if it ties in to too many other MSVC specifics), I guess that would have to be another separate target like ...-gnu_arm64ec - using up yet another entry in enum EnvironmentType for it.

Another potential option could be to use subarches, like is done in apple toolchains, for selecting different ABIs within the same architecture, like armv7k and arm64e there. I presume that blocks using that field for finer details, like armv8.5a though (not sure how common that is).

There is one reference in llvm to arm64-pc-windows-msvc (llvm/test/tools/llvm-lib/Inputs/arm64.ll) so I assume there is some mapping between arm64 -> aarch64 naming. So perhaps "arm64ec-pc-windows" like Apple has "arm64e-apple-darwin"? Internally converted to aarch64ec-pc-windows-msvc. Is there a big reason to put the EC bit on the end?

(I am fuzzy on the rules, if any for tripples/quadruples)

Another potential option could be to use subarches, like is done in apple toolchains, for selecting different ABIs within the same architecture, like armv7k and arm64e there. I presume that blocks using that field for finer details, like armv8.5a though (not sure how common that is).

Finer details I'd expect to be specified by -march or -mcpu. Though we do handle things like "thumbv7" vs "thumbv8" which is a similar kind of detail (you could -mthumb -march=armv(7|8)-a instead).

If we'd want to use this ABI mode for mingw targets too [...], I guess that would have to be another separate target like ...-gnu_arm64ec - using up yet another entry in enum EnvironmentType for it.

Yes, you'd have to do something like that.

We could do something like arm64ec-pc-windows-msvc, I guess. That sort of goes against the spirit of target triples: the first part is usually used to describe the instruction set, and the fourth part is usually used to describe alternate ABI/environment/etc. It's not like "arm64ec" makes sense anywhere other than Windows, anyway.

Of course, everything related to triples is a bit fuzzy; if we want to use AArch64SubArch_arm64ec, there isn't really anything stopping us.

(not quite sure right now if it's doable and something that one wants to do at some point, or if it ties in to too many other MSVC specifics),

Not sure if I'm going to end up hooking up ARM64EC support in lld. And I'm not sure if any of the runtime libraries need to be linked in statically. Otherwise, I don't see any reason you couldn't add support to mingw.

I presume that blocks using that field for finer details, like armv8.5a though (not sure how common that is).

We don't really do that sort of thing on aarch64, only 32-bit ARM. See also parseSubArch() in Triple.cpp.

We could do something like arm64ec-pc-windows-msvc, I guess. That sort of goes against the spirit of target triples: the first part is usually used to describe the instruction set, and the fourth part is usually used to describe alternate ABI/environment/etc. It's not like "arm64ec" makes sense anywhere other than Windows, anyway.

Of course, everything related to triples is a bit fuzzy; if we want to use AArch64SubArch_arm64ec, there isn't really anything stopping us.

I would prefer it if we used a different first part to indicate that Arm64EC is a different "architecture" than AArch64.

From a theoretical perspective, Arm64EC is a mix of AArch64 and x86_64: one can think of it as a weird processor that can run both AArch64 code (with some caveats, like the restricted registers) and x86_64 code, even if LLVM is only ever emitting AArch64 (which may not be true in the future if support for x86_64 assembly is added).

From a practical perspective, MSVC uses a distinct set of architecture-specific preprocessor macros for Arm64EC vs AArch64: https://techcommunity.microsoft.com/t5/windows-kernel-internals-blog/getting-to-know-arm64ec-defines-and-intrinsic-functions/ba-p/2957235. Other languages should follow this pattern (i.e., disabling code that is targeted to AArch64 and instead enabling Arm64EC-specific code - whether x86_64 code is also enabled is debatable), and having a different "architecture" part to the target-triple is an excellent way to signal this.

We could do something like arm64ec-pc-windows-msvc, I guess. That sort of goes against the spirit of target triples: the first part is usually used to describe the instruction set, and the fourth part is usually used to describe alternate ABI/environment/etc. It's not like "arm64ec" makes sense anywhere other than Windows, anyway.

Of course, everything related to triples is a bit fuzzy; if we want to use AArch64SubArch_arm64ec, there isn't really anything stopping us.

I would prefer it if we used a different first part to indicate that Arm64EC is a different "architecture" than AArch64.

From a theoretical perspective, Arm64EC is a mix of AArch64 and x86_64: one can think of it as a weird processor that can run both AArch64 code (with some caveats, like the restricted registers) and x86_64 code, even if LLVM is only ever emitting AArch64 (which may not be true in the future if support for x86_64 assembly is added).

From a practical perspective, MSVC uses a distinct set of architecture-specific preprocessor macros for Arm64EC vs AArch64: https://techcommunity.microsoft.com/t5/windows-kernel-internals-blog/getting-to-know-arm64ec-defines-and-intrinsic-functions/ba-p/2957235. Other languages should follow this pattern (i.e., disabling code that is targeted to AArch64 and instead enabling Arm64EC-specific code - whether x86_64 code is also enabled is debatable), and having a different "architecture" part to the target-triple is an excellent way to signal this.

Veering slightly offtopic here, but - I'm curious - is it possible to link in regular aarch64 object files in an arm64ec executable (for functions where the calling convention doesn't differ from regular aarch64)? Those object files would only ever be called from arm64ec code (not from x86_64), so I wonder if it would work without all the thunks that are present in arm64ec object files. (In particular, the case I have in mind is cases with handwritten aarch64 assembly.) Would it be possible to mark such functions with a calling convention attribute on the C level, to let the compiler generate code for calling regular aarch64 functions?

Veering slightly offtopic here, but - I'm curious - is it possible to link in regular aarch64 object files in an arm64ec executable (for functions where the calling convention doesn't differ from regular aarch64)? Those object files would only ever be called from arm64ec code (not from x86_64), so I wonder if it would work without all the thunks that are present in arm64ec object files. (In particular, the case I have in mind is cases with handwritten aarch64 assembly.) Would it be possible to mark such functions with a calling convention attribute on the C level, to let the compiler generate code for calling regular aarch64 functions?

Caveat: I'm not an expert in this area, but this is my understanding of the docs: https://docs.microsoft.com/en-us/windows/arm/arm64ec-abi.

It's not a good idea to mix Arm64EC and normal AArch64:

But, if you're hand-coding assembly, you could avoid the cases above (i.e., restrict the registers you use, avoid variadic functions, avoid indirect calls, avoid stack checks and avoid security cookie checks) to create assembly code that is usable in both Arm64EC and normal AArch64 contexts.

As for the thunks:

  • You only require Exit Thunks for code that *might* be calling to x86_64 code. If you statically know that all of the functions that your code calls are AArch64, then Exit Thunks are not required.
  • Same goes for the Entry Thunks: if you statically know that the only functions that call your code are AArch64, then Entry Thunks are not required.

It's not a good idea to mix Arm64EC and normal AArch64:

Thanks - this is probably the most tricky limitation, if registers outside of that set can be lost essentially at any time, asynchronously. I take it that they’re not clobbered on e.g. regular OS context switches, but mainly when the OS interacts with the running thread (e.g. if executing an APC).

efriedma updated this revision to Diff 457451.Sep 1 2022, 5:32 PM
efriedma edited the summary of this revision. (Show Details)
efriedma added reviewers: mstorsjo, rnk.

Switched triple to arm64ec-pc-windows-msvc

We may need to add arm64ec into llvm\utils\UpdateTestChecks\asm.py to make update_*_test_checks.py work.

       'arm64': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
       'arm64e': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
+      'arm64ec': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_RE),
       'arm64-apple-ios': (scrub_asm_arm_eabi, ASM_FUNCTION_AARCH64_DARWIN_RE),
This revision is now accepted and ready to land.Sep 2 2022, 12:23 AM
bcl5980 added inline comments.Sep 4 2022, 8:46 PM
llvm/test/MC/AArch64/arm64ec.s
2

arm64ec-pc-windows-msvc or arm64ec-pc-windows-msvc_arm64ec here?

mstorsjo added inline comments.Sep 5 2022, 12:46 AM
llvm/test/MC/AArch64/arm64ec.s
2

Oh, good catch, thanks - indeed this should be changed to arm64ec-pc-windows-msvc.

This revision was landed with ongoing or failed builds.Sep 5 2022, 12:54 PM
This revision was automatically updated to reflect the committed changes.