Repository navigation
Can't pass or return half or fp128 on arm64ec #94434
Description
Activity
- addedcrashPrefer [crash-on-valid] or [crash-on-invalid]Prefer [crash-on-valid] or [crash-on-invalid]and removed
on Jun 5, 2024 @llvm/issue-subscribers-backend-aarch64
Author: None (beetrees)
Details
Trying to compile the following IR for `arm64ec-pc-windows-msvc` ([compiler explorer](https://godbolt.org/z/sqrn8Mnxo))define half @<!-- -->half(half) { ret half %0 } define fp128 @<!-- -->fp128(fp128) { ret fp128 %0 }
will fail with the following error:
LLVM ERROR: Only 32 and 64 bit floating points are supported for ARM64EC thunks PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace. Stack dump: 0. Program arguments: /opt/compiler-explorer/clang-trunk/bin/llc -o /app/output.s -mtriple=arm64ec-pc-windows-msvc <source> 1. Running pass 'AArch64Arm64ECCallLowering' on module '<source>'. #<!-- -->0 0x00000000036ffd18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-trunk/bin/llc+0x36ffd18) #<!-- -->1 0x00000000036fd68c SignalHandler(int) Signals.cpp:0:0 #<!-- -->2 0x0000760bd1842520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520) #<!-- -->3 0x0000760bd18969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc) #<!-- -->4 0x0000760bd1842476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476) #<!-- -->5 0x0000760bd18287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3) #<!-- -->6 0x000000000072f886 llvm::UniqueStringSaver::save(llvm::StringRef) (.cold) StringSaver.cpp:0:0 #<!-- -->7 0x000000000364f7d8 (/opt/compiler-explorer/clang-trunk/bin/llc+0x364f7d8) #<!-- -->8 0x0000000000a7732c (anonymous namespace)::AArch64Arm64ECCallLowering::canonicalizeThunkType(llvm::Type*, llvm::Align, bool, unsigned long, llvm::raw_ostream&, llvm::Type*&, llvm::Type*&) (.constprop.0) AArch64Arm64ECCallLowering.cpp:0:0 #<!-- -->9 0x0000000000a7887f (anonymous namespace)::AArch64Arm64ECCallLowering::getThunkType(llvm::FunctionType*, llvm::AttributeList, llvm::COFF::Arm64ECThunkType, llvm::raw_ostream&, llvm::FunctionType*&, llvm::FunctionType*&) AArch64Arm64ECCallLowering.cpp:0:0 #<!-- -->10 0x0000000000a7fd73 (anonymous namespace)::AArch64Arm64ECCallLowering::buildEntryThunk(llvm::Function*) AArch64Arm64ECCallLowering.cpp:0:0 #<!-- -->11 0x0000000000a83dea (anonymous namespace)::AArch64Arm64ECCallLowering::runOnModule(llvm::Module&) (.part.0) AArch64Arm64ECCallLowering.cpp:0:0 #<!-- -->12 0x0000000002d44ac0 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/opt/compiler-explorer/clang-trunk/bin/llc+0x2d44ac0) #<!-- -->13 0x00000000008483f4 compileModule(char**, llvm::LLVMContext&) llc.cpp:0:0 #<!-- -->14 0x0000000000741b86 main (/opt/compiler-explorer/clang-trunk/bin/llc+0x741b86) #<!-- -->15 0x0000760bd1829d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90) #<!-- -->16 0x0000760bd1829e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40) #<!-- -->17 0x000000000084002e _start (/opt/compiler-explorer/clang-trunk/bin/llc+0x84002e) Program terminated with signal: SIGSEGV Compiler returned: 139Duplicating my thoughts from another thread: I know very little about the inner workings of arm64ec, but I think
f16should "just work". It effectively uses the same calling convention asf32orf64, passed and returned in vector registers on both x86-64 and on aarch64. The only difference is how it gets lowered on either side.f128 is less straightforward because on Windows x86-64, it is passed in memory, but returned in xmm0, but for aarch64 it is both passed and returned in registers. If my understanding of http://www.emulators.com/docs/abc_arm64ec_explained.htm is correct (and that is still up to date) then this needs an entry thunk to handle this difference. LLVM and GCC use the same ABI for i128 and f128 on Windows though and i128 seems to be supported, so I'm guessing that bit could be reused.
ABI demo: https://llvm.godbolt.org/z/qqWxjcEhn
(Arguably f128 and i128 should be both passed and returned in memory on x86-64 (aiui it can't be in xmm because of varargs). But without official guidance from Microsoft I doubt there is strong enough motivation to drive updates to both GCC and Clang when the status quo works).
Indeed, it looks like the calling convention has already been handled for f16
llvm-project/llvm/lib/Target/AArch64/AArch64CallingConvention.td
Lines 264 to 288 in 92164fa
// The first 4 FP/Vector arguments are passed in XMM registers. CCIfType<[f16], CCAssignToRegWithShadow<[H0, H1, H2, H3], [X0, X1, X2, X3]>>, CCIfType<[f32], CCAssignToRegWithShadow<[S0, S1, S2, S3], [X0, X1, X2, X3]>>, CCIfType<[f64], CCAssignToRegWithShadow<[D0, D1, D2, D3], [X0, X1, X2, X3]>>, // The first 4 integer arguments are passed in integer registers. CCIfType<[i32], CCAssignToRegWithShadow<[W0, W1, W2, W3], [Q0, Q1, Q2, Q3]>>, // Arm64EC thunks: the first argument is always a pointer to the destination // address, stored in x9. CCIfType<[i64], CCAssignToReg<[X9]>>, CCIfType<[i64], CCAssignToRegWithShadow<[X0, X1, X2, X3], [Q0, Q1, Q2, Q3]>>, // Integer/FP values get stored in stack slots that are 8 bytes in size and // 8-byte aligned if there are no more registers to hold them. CCIfType<[i8, i16, i32, i64, f16, f32, f64], CCAssignToStack<8, 8>> - added a commit that references this issue
on Aug 12, 2025 - added a commit that references this issue
on Aug 12, 2025 - added a commit that references this issue
on Jun 14, 2026 - added a commit that references this issue
on Jul 2, 2026 - added a commit that references this issue
on Jul 2, 2026 - added a commit that references this issue
on Jul 2, 2026 - added a commit that references this issue
on Jul 2, 2026
Trying to compile the following IR for
arm64ec-pc-windows-msvc(compiler explorer)will fail with the following error: