Launchpad has imported 13 comments from the remote bug at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121784.
If you reply to an imported comment from within Launchpad, your comment will be sent to the remote bug automatically. Read more about Launchpad's inter-bugtracker facilities at https://documentation.ubuntu.com/launchpad/user/reference/bugs/multi-project-bugs/about-multi-project-bugs/#bugs-in-external-trackers. ------------------------------------------------------------------------ On 2025-09-04T07:35:01+00:00 Heinrich Schuchardt wrote: Created attachment 62299 relevant *.ii, command line, gcc output, gcc configuration When compiling upstream WebKit on risc64 on an rva23s64 VM multiple messages "error: cannot tail-call: argument must be passed by copying" are displayed leading to a build failure. The message seems to be an indication of an internal GCC problem. Operating system: Ubuntu 25.10 Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/0 ------------------------------------------------------------------------ On 2025-09-05T01:19:11+00:00 Pinskia wrote: Created attachment 62309 Kinda of reduced I am suspecting there are just too many arguments. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/3 ------------------------------------------------------------------------ On 2025-09-05T01:22:56+00:00 Pinskia wrote: Created attachment 62310 Even more reduced Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/4 ------------------------------------------------------------------------ On 2025-09-05T01:25:13+00:00 Pinskia wrote: The options passed to GCC: `-march=rv64imafdcbv` Note clang ICEs on the same thing: ``` fatal error: error in backend: failed to perform tail call elimination on a call site marked musttail PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script. Stack dump: 0. Program arguments: /opt/compiler-explorer/clang-trunk/bin/clang++ -g -o /app/output.s -fverbose-asm -S -target riscv64-unknown-linux-gnu -march=rv64gc -mabi=lp64d --gcc-toolchain=/opt/compiler-explorer/riscv64/gcc-14.2.0/riscv64-unknown-linux-gnu --sysroot=/opt/compiler-explorer/riscv64/gcc-14.2.0/riscv64-unknown-linux-gnu/riscv64-unknown-linux-gnu/sysroot -fcolor-diagnostics -fno-crash-diagnostics -xc++ -g0 -march=rv64imafdcbv <source> 1. <eof> parser at end of file 2. Code generation 3. Running pass 'Function Pass Manager' on module '<source>'. 4. Running pass 'RISC-V DAG->DAG Pattern Instruction Selection' on function '@_Z1m9StageListiiDv4_fS0_S0_' #0 0x0000000003cbde88 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3cbde88) #1 0x0000000003cbb85c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3cbb85c) #2 0x0000000003c0bc43 llvm::CrashRecoveryContext::HandleExit(int) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3c0bc43) #3 0x0000000003cb30ae llvm::sys::Process::Exit(int, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3cb30ae) #4 0x0000000000dbedfb LLVMErrorHandler(void*, char const*, bool) cc1_main.cpp:0:0 #5 0x0000000003c159b3 llvm::report_fatal_error(llvm::Twine const&, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3c159b3) #6 0x0000000003c15b49 (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3c15b49) #7 0x00000000022d2613 (/opt/compiler-explorer/clang-trunk/bin/clang+++0x22d2613) #8 0x0000000005153120 llvm::TargetLowering::LowerCallTo(llvm::TargetLowering::CallLoweringInfo&) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5153120) #9 0x000000000515514d llvm::SelectionDAGBuilder::lowerInvokable(llvm::TargetLowering::CallLoweringInfo&, llvm::BasicBlock const*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x515514d) #10 0x000000000516fe64 llvm::SelectionDAGBuilder::LowerCallTo(llvm::CallBase const&, llvm::SDValue, bool, bool, llvm::BasicBlock const*, llvm::TargetLowering::PtrAuthInfo const*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x516fe64) #11 0x0000000005188018 llvm::SelectionDAGBuilder::visitCall(llvm::CallInst const&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x5188018) #12 0x000000000519ca7c llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x519ca7c) #13 0x000000000521c9f4 llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator_w_bits<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void, true, llvm::BasicBlock>, false, true>, llvm::ilist_iterator_w_bits<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void, true, llvm::BasicBlock>, false, true>, bool&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x521c9f4) #14 0x000000000521dd2a llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x521dd2a) #15 0x000000000521fcde llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x521fcde) #16 0x000000000520eb81 llvm::SelectionDAGISelLegacy::runOnMachineFunction(llvm::MachineFunction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x520eb81) #17 0x00000000030b0e6d llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x30b0e6d) #18 0x0000000003612202 llvm::FPPassManager::runOnFunction(llvm::Function&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3612202) #19 0x0000000003612491 llvm::FPPassManager::runOnModule(llvm::Module&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3612491) #20 0x0000000003613d67 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3613d67) #21 0x0000000003f5fa7d clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3f5fa7d) #22 0x000000000459698c clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x459698c) #23 0x00000000061fc99c clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x61fc99c) #24 0x000000000459717d clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x459717d) #25 0x00000000048a2caa clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-trunk/bin/clang+++0x48a2caa) #26 0x000000000481d19b clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x481d19b) #27 0x0000000004997263 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x4997263) #28 0x0000000000dc0e55 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-trunk/bin/clang+++0xdc0e55) #29 0x0000000000db8dfd ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0 #30 0x0000000004609e99 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0 #31 0x0000000003c0bb43 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x3c0bb43) #32 0x000000000460a0b9 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0 #33 0x00000000045cd01d clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x45cd01d) #34 0x00000000045cdfd1 clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+++0x45cdfd1) #35 0x00000000045d792c clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0x45d792c) #36 0x0000000000dbd661 clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-trunk/bin/clang+++0xdbd661) #37 0x0000000000c6ccd4 main (/opt/compiler-explorer/clang-trunk/bin/clang+++0xc6ccd4) #38 0x000077e4cf029d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90) #39 0x000077e4cf029e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40) #40 0x0000000000db8895 _start (/opt/compiler-explorer/clang-trunk/bin/clang+++0xdb8895) clang++: error: clang frontend command failed with exit code 70 (use -v to see invocation) Compiler returned: 70 ``` So you might want to report this bug there too. OR even better report upstream to WebKit that musttail is broken and maybe should not be used. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/5 ------------------------------------------------------------------------ On 2025-09-08T23:44:31+00:00 Heinrich Schuchardt wrote: Hello Andrew, Thank you for your analysis. I experimented a bit with the type of F in your reduced example. These fail: using F = __attribute__((vector_size(16))) double; using F = __attribute__((vector_size(16))) float; using F = __attribute__((vector_size(16))) short; using F = struct {float x0; float x1; float x2; float x3;}; using F = struct {float x0; float x1; float x2;}; These succeed: using F = __attribute__((vector_size(8))) double; using F = __attribute__((vector_size(8))) float; using F = __attribute__((vector_size(8))) short; using F = struct {float x0; float x1;}; I then tried with a higher count of arguments: using StageFn = void (*)(StageList list, int src, int dst, F r, F g, F b, F v, F w, F x, F y, F z); These fail: using F = __attribute__((vector_size(8))) double; using F = __attribute__((vector_size(8))) float; using F = __attribute__((vector_size(8))) short; using F = struct {double a; double b;}; These succeed: using F = double; using F = struct {float a; float b;}; It is weird that `__attribute__((vector_size(8))) double` differently than `double` and `__attribute__((vector_size(8))) float` differently than `struct {float a; float b;};`. With a lower count of arguments: using StageFn = void (*)(StageList list, F a); These fail: using F = __attribute__((vector_size(32))) double; using F = __attribute__((vector_size(32))) float; These succeed: using F = __attribute__((vector_size(16))) double; using F = __attribute__((vector_size(16))) float; Is the number of tail call arguments limited by available registers? According to the documentation in https://gcc.gnu.org/onlinedocs/gcc-15.2.0/gcc/Statement-Attributes.html the only differentiation should be between trivially destructible and non-trivially destructible arguments. If the arguments are passed by value, it should not matter if they are in registers or on the stack. Best regards Heinrich Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/6 ------------------------------------------------------------------------ On 2025-09-10T09:01:51+00:00 Heinrich Schuchardt wrote: LLVM issue: https://github.com/llvm/llvm-project/issues/157814 Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/7 ------------------------------------------------------------------------ On 2025-09-10T09:22:05+00:00 Heinrich Schuchardt wrote: WebKit uses Skia as third party library. I have now created Skia issue https://issues.skia.org/issues/444048022 Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/8 ------------------------------------------------------------------------ On 2025-09-10T09:55:01+00:00 Jakub-gcc wrote: The RISCV ABIs apparently pass some of the vector arguments by invisible reference (dunno if it is only if there are no vector registers reserved for argument passing left or if it depends solely on the exact vector types, question to the RISCV maintainers). Anyway, that is a thing that generally prevents tail calls, you can't tail call if you need to create a temporary in the caller on the stack and pass to the tail called function address of that temporary, because tail call will make the caller frame disappear. I guess the only exception that could be handled is if the passed value is unmodified value from one of the parameters of the function (same type, no conversions, no possibility of modification) and most importantly that it is passed by invisible reference in the caller as well. In that case the compiler could look up in what register/memory the address of the argument has been passed and propagate it to the tail call. In the GCC IL, that means only handle it for cases like in the #c2 testcase where the optimized dump has something like _2 (list, src_4(D), dst_5(D), r_6(D), g_7(D), b_8(D)); [tail call] [must tail call] i.e. the values of the arguments are unmodified values of the parameters, and it can prove they are passed by invisible reference in the caller too (in this case in a3/a4/a5 registers it passes the addresses of r, g and b arguments). This is somewhat similar to the optimization I did for s390x in PR119873, there the ABI also prevents tailcalls if a certain register must be used for argument passing, but as a special optimization it can be done if only the original parameter value from the same argument is passed through. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/9 ------------------------------------------------------------------------ On 2025-09-10T10:22:46+00:00 Jakub-gcc wrote: To explain better what is happening under the hood, using StageFn = void (*)(StageList list, int src, int dst, F r, F g, F b); void m(StageList list, int src, int dst, F r, F g, F b) { return (*list.fn)(list, src, dst, r, g, b); } is actually handled under the hood for these RISCV ABIs (for GCC starting with expansion to RTL) as C++ using StageFn = void (*)(StageList list, int src, int dst, const F &, const F &, const F &); void m(StageList list, int src, int dst, const F &r_, const F &g_, const F &b_) { F r = r_, g = g_, b = b_; return (*list.fn)(list, src, dst, r, g, b); } Now, if the r, g, b arguments are or could be modified, that is the only way how it can be handled given the weird ABIs and it is simply not tail callable. But if the arguments are unmodified, one could handle it as void m(StageList list, int src, int dst, const F &r_, const F &g_, const F &b_) { return (*list.fn)(list, src, dst, r_, g_, b_); } instead and thus make it tail callable. Compare that to e.g. ia32 without SSE (or x86_64 for later arguments after all argument registers are used for other arguments), F in that case is passed on the stack, not by invisible reference, so tail call is possible if callee doesn't need fewer argument stack slots than the caller, before the tail call the code can simply copy over (or if lucky just expect it to be there already) the data into the right stack slot. Anyway, using musttail attribute carelessly without actually thinking about the different ABIs and their limitations/consequences is a sure way to get compiler errors (or with clang sometimes silent not honoring of the attribute, as happens e.g. on the s390x case). Some ABIs can't tail call anything, others have very large limitations. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/10 ------------------------------------------------------------------------ On 2025-09-10T11:49:01+00:00 Heinrich Schuchardt wrote: Thanks Jakub for you detailed explanation that should help to improve the Skia code. As some of the tail functions modify the passed parameters (vectors r, g, b) and then pass them to the next tail function unfortunately your workaround is not applicable. This is one of the functions that may be used in the tail function chain: STAGE(matrix_3x3, const skcms_Matrix3x3* matrix) { const float* m = &matrix->vals[0][0]; F R = m[0]*r + m[1]*g + m[2]*b, G = m[3]*r + m[4]*g + m[5]*b, B = m[6]*r + m[7]*g + m[8]*b; r = R; g = G; b = B; } Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/11 ------------------------------------------------------------------------ On 2025-09-10T11:53:25+00:00 Jakub-gcc wrote: (In reply to Heinrich Schuchardt from comment #9) > Thanks Jakub for you detailed explanation that should help to improve the > Skia code. > > As some of the tail functions modify the passed parameters (vectors r, g, b) > and then pass them to the next tail function unfortunately your workaround > is not applicable. > > This is one of the functions that may be used in the tail function chain: > > STAGE(matrix_3x3, const skcms_Matrix3x3* matrix) { > const float* m = &matrix->vals[0][0]; > > F R = m[0]*r + m[1]*g + m[2]*b, > G = m[3]*r + m[4]*g + m[5]*b, > B = m[6]*r + m[7]*g + m[8]*b; > > r = R; > g = G; > b = B; > } If so, you can't use [[clang::musttail]] nor [[gnu::musttail]] attributes for those calls on targets with such ABIs (so ifdef it out for whatever RISCV ABIs do that or whatever others). musttail attribute is try hard to tail call this and if not possible, emit an error instead of doing a silent non-tail call. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/12 ------------------------------------------------------------------------ On 2026-04-06T14:13:27+00:00 Xry111-5 wrote: LoongArch and PowerPC fails at the same location. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/14 ------------------------------------------------------------------------ On 2026-04-06T22:01:27+00:00 Xry111-5 wrote: mips too. Reply at: https://bugs.launchpad.net/ubuntu/+source/gcc-15/+bug/2122013/comments/15 ** Changed in: gcc Status: Unknown => New ** Changed in: gcc Importance: Unknown => Medium ** Bug watch added: github.com/llvm/llvm-project/issues #157814 https://github.com/llvm/llvm-project/issues/157814 ** Bug watch added: issues.skia.org/issues #444048022 https://issues.skia.org/issues/444048022 -- You received this bug notification because you are a member of Ubuntu Bugs, which is subscribed to Ubuntu. https://bugs.launchpad.net/bugs/2122013 Title: error: cannot tail-call: argument must be passed by copying To manage notifications about this bug go to: https://bugs.launchpad.net/gcc/+bug/2122013/+subscriptions -- ubuntu-bugs mailing list [email protected] https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs
