Skip to content

Can't pass or return half or fp128 on arm64ec #94434

Description

@beetrees

Trying to compile the following IR for arm64ec-pc-windows-msvc (compiler explorer)

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: 139

Activity

  1. llvmbot commented on Jun 5, 2024

    @llvmbot
    Member

    @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 &lt;source&gt;
    1.	Running pass 'AArch64Arm64ECCallLowering' on module '&lt;source&gt;'.
     #<!-- -->0 0x00000000036ffd18 llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, 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&amp;, llvm::Type*&amp;, llvm::Type*&amp;) (.constprop.0) AArch64Arm64ECCallLowering.cpp:0:0
     #<!-- -->9 0x0000000000a7887f (anonymous namespace)::AArch64Arm64ECCallLowering::getThunkType(llvm::FunctionType*, llvm::AttributeList, llvm::COFF::Arm64ECThunkType, llvm::raw_ostream&amp;, llvm::FunctionType*&amp;, llvm::FunctionType*&amp;) AArch64Arm64ECCallLowering.cpp:0:0
    #<!-- -->10 0x0000000000a7fd73 (anonymous namespace)::AArch64Arm64ECCallLowering::buildEntryThunk(llvm::Function*) AArch64Arm64ECCallLowering.cpp:0:0
    #<!-- -->11 0x0000000000a83dea (anonymous namespace)::AArch64Arm64ECCallLowering::runOnModule(llvm::Module&amp;) (.part.0) AArch64Arm64ECCallLowering.cpp:0:0
    #<!-- -->12 0x0000000002d44ac0 llvm::legacy::PassManagerImpl::run(llvm::Module&amp;) (/opt/compiler-explorer/clang-trunk/bin/llc+0x2d44ac0)
    #<!-- -->13 0x00000000008483f4 compileModule(char**, llvm::LLVMContext&amp;) 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: 139
    
  2. self-assigned this
    on Oct 8, 2024
  3. tgross35 commented on Aug 9, 2025

    @tgross35
    Contributor

    Duplicating my thoughts from another thread: I know very little about the inner workings of arm64ec, but I think f16 should "just work". It effectively uses the same calling convention as f32 or f64, 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).

  4. added theissue type on Aug 9, 2025
  5. tgross35 commented on Aug 9, 2025

    @tgross35
    Contributor

    Indeed, it looks like the calling convention has already been handled for f16

    // 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>>

  6. added a commit that references this issue on Aug 9, 2026
  7. added 2 commits that reference this issue on Aug 9, 2026
  8. added a commit that references this issue on Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

backend:AArch64crashPrefer [crash-on-valid] or [crash-on-invalid]

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions