This is an archive of the discontinued LLVM Phabricator instance.

[ARM64EC 8/?] Implement ARM64EC "thunk" calling conventions
Needs ReviewPublic

Authored by efriedma on Jun 1 2022, 12:39 PM.

Details

Summary

Part of initial Arm64EC patchset.

A key part of Arm64EC is the presence of "thunks"; bits of code that translate between the x64 calling convention, and the ARM64 calling convention. To lower these, we need to emit calls in a unique way.

This patch adds two calling conventions: one for each side of a thunk. The native side of the thunk just uses the ARM64 calling convention, with the called function stored in x9. The x64 side uses the x64 calling convention with the registers renamed. (See https://docs.microsoft.com/en-us/cpp/build/arm64ec-windows-abi-conventions for the complete register mapping.)

Note that this doesn't deal with variadic functions; we need to do something a bit different for that. (I'm currently thinking we won't actually represent the thunks as "variadic"; we don't need to access any arguments via sp, so we can just treat x0-x5 as the arguments.)

Diff Detail

Event Timeline

efriedma created this revision.Jun 1 2022, 12:39 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 1 2022, 12:39 PM
efriedma requested review of this revision.Jun 1 2022, 12:39 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 1 2022, 12:39 PM
dpaoliello added inline comments.
llvm/lib/Target/AArch64/AArch64CallingConvention.td
247–252

I'm not sure that this is correct: x64 doesn't have a way to read half- or single-precision floating point numbers, and (as I understand it) AArch64 half/single-precision floating point register writes don't modify the upper-bits. What happens on x64 when you write an f16/f32 to an XMM register? I assume that it gets sign-extended...

263

I'll get some clarification on this...

dpaoliello added inline comments.Jun 1 2022, 4:16 PM
llvm/include/llvm/IR/CallingConv.h
241

When adding a calling convention, does it not also need to be added to the IR AsmWriter/AsmPrinter?

efriedma added inline comments.Jun 1 2022, 4:23 PM
llvm/lib/Target/AArch64/AArch64CallingConvention.td
247–252

AArch64 half/single float register writes do zero the high bits. x86 is the one that's a bit inconsistent (the behavior of movss depends on whether the source is a register or memory).

In any case, I think the high bits of a floating-point register are undefined in both conventions.

263

I copy-pasted the X86_ThisCall thing from the x86 code. It might be a red herring, though; I just looked at this in clang, and it looks like clang doesn't actually use the X86_ThisCall on x64 Windows, so this doesn't actually do anything, even in the original? I'm sort of confused how it ended up that way. Maybe can just delete it, though.

I probably do need some handling for C++ methods, though, which I haven't implemented yet. (In particular, I need to ensure we emit the arguments for exit thunks for C++ methods in the correct order.)

efriedma added inline comments.Jun 1 2022, 4:26 PM
llvm/include/llvm/IR/CallingConv.h
241

If you don't add it to the asmparser/writer, there's some default handling that just uses the number, I think. But it might be better to give them proper names in IR.

Alternatively, I was thinking about marking the calls using an attribute instead of a calling convention. Which is basically equivalent to using a calling convention, but doesn't consume calling convention numbers. Probably doesn't matter much in practice.

mstorsjo added inline comments.
llvm/lib/Target/AArch64/AArch64CallingConvention.td
263

thiscall (similarly to stdcall, fastcall and vectorcall) are all no-ops on x86_64, they're only a thing on x86_32 windows.

dpaoliello added inline comments.Jun 2 2022, 11:48 AM
llvm/include/llvm/IR/CallingConv.h
241

I think using a calling convention makes more sense, and should avoid these functions being accidentally treated like a normal function.

llvm/lib/Target/AArch64/AArch64CallingConvention.td
263

vectorcall still exists for x64, however Arm64EC currently only supports standard x64 calling convention.

For now, I think we can drop the thiscall special case, but I will double check if it is required (we can always add it back later if so).

dpaoliello added inline comments.Jun 2 2022, 11:50 AM
llvm/lib/Target/AArch64/AArch64CallingConvention.td
215

For comments like these that reference the x64 register, can you please add a note of what the equivalent AArch64 register is?

efriedma updated this revision to Diff 458053.Sep 5 2022, 1:32 PM
efriedma edited the summary of this revision. (Show Details)

Address review comments.

bcl5980 added inline comments.Sep 6 2022, 2:27 AM
llvm/lib/Target/AArch64/AArch64CallingConvention.td
209

Do we need to add CSR for the callingconv also in this change?
D6, D7 should be non-volatile on x64.

efriedma added inline comments.Sep 6 2022, 4:33 PM
llvm/lib/Target/AArch64/AArch64CallingConvention.td
209

CSRs are listed elsewhere... but yes, we do need to mess with AArch64RegisterInfo::getCalleeSavedRegs to make entry thunks correctly save the registers.

bcl5980 added inline comments.Sep 6 2022, 11:21 PM
llvm/lib/Target/AArch64/AArch64CallingConvention.td
209

If we consider entry thunk, we need to save q6-q15 instead of d8-d15. Even through MS still hasn't documented the unwind code save_qregp, we may need to add (sequence "Q%u", 6, 15) into something like CSR_AArch64_Arm64EC_Thunk.