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

Reply via email to