Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error: symbol memset missing .functype when compiling .c to .s and then to wasm32 .o #53712

Closed
TerrorJack opened this issue Feb 10, 2022 · 9 comments

Comments

@TerrorJack
Copy link

When using wasi-sdk to compile a C file to .s and then to wasm32 .o, the second step would fail with an error message like this (compiling it to .o directly seems to be fine):

/tmp/ghc_1.s:630:2: error: symbol memset missing .functype
        call    memset
        ^

The command line to reproduce is:

clang -x c rts/Weak.c -o /tmp/ghc_1.s -fno-PIC -Wimplicit -S -O -include rts/include/ghcversion.h -Irts/include -I_build/stage1/rts/build -I_build/stage1/rts/build/include -Irts/include -I_build/stage1/rts/build -Irts -I_build/stage1/rts/build -Xpreprocessor -include -Xpreprocessor _build/stage1/rts/build/autogen/cabal_macros.h -Xpreprocessor -Wno-nonportable-include-path -Xpreprocessor '-DRtsWay="rts_v"' -Xpreprocessor '-DFS_NAMESPACE=rts' -Xpreprocessor -DCOMPILING_RTS -Xpreprocessor -DNOSMP -Xpreprocessor -DNOSMP -DUSE_MINIINTERPRETER -DNO_REGS '--target=wasm32-unknown-wasi' '--target=wasm32-unknown-wasi' '--target=wasm32-unknown-wasi' -Irts/include -I_build/stage1/rts/build -I_build/stage1/rts/build/include -Irts/include -Wno-unknown-pragmas -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Winline -Wpointer-arith -Wmissing-noreturn -Wnested-externs -Wredundant-decls -Wundef -fno-strict-aliasing -fomit-frame-pointer -O2 -g -Irts -I_build/stage1/rts/build -DNOSMP

clang '--target=wasm32-unknown-wasi' -DNO_REGS -DUSE_MINIINTERPRETER -Irts/include -I_build/stage1/rts/build -I_build/stage1/rts/build/include -Irts/include -I_build/stage1/rts/build -Irts -I_build/stage1/rts/build -fno-PIC -Qunused-arguments -x assembler -c /tmp/ghc_1.s -o _build/stage1/rts/build/c/Weak.o.tmp

We tried 13.0.0, 13.0.1 and 14.0.0-rc1 llvm revisions in the wasi-sdk build, the error persists. Since this only involves codegen and not linking with sysroot, I believe the repro can also work with a vanilla clang installation.

The commands can be run in the directory packaged in this tarball: https://drive.google.com/file/d/1ur9O8rQ0xYYLi8tmOlg79h7H0SXHPmw9/view?usp=sharing. We're still trying to come up with a minimal self-contained repro, meanwhile this is the best we have so far.

@TerrorJack
Copy link
Author

Here is the minified C source code that produces the same error:

typedef struct {
  int a;
  int b[]
} c;
d() {
  c *a;
  int e, f;
  e = g();
  a = f = 0;
  for (; f < e; f++)
    a->b[f] = 0;
}

@llvmbot
Copy link
Collaborator

llvmbot commented Feb 20, 2022

@llvm/issue-subscribers-backend-webassembly

@dschuff
Copy link
Member

dschuff commented Feb 22, 2022

/cc @sbc100 @aardappel
When outputting assembly, the MC layer (or maybe WebAssemblyMCInstLower?) will usually output .functype declarations for declared but not defined functions. My guess is that this is happening because the call to memset is not in the source, but is generated by the compiler backend.

@aardappel
Copy link
Collaborator

I think you mean the opposite, defined but not declared?

I do remember a few functions like memcpy having special status in our toolchain, wouldn't be surprised if that was the case for memset too.

@aardappel
Copy link
Collaborator

Can repro locally with clang --target=wasm32-unknown-wasi -O test.c -S

@aardappel
Copy link
Collaborator

In WebAssemblyAsmPrinter::emitExternalDecls we call emitFunctionType for all symbols that are isDeclarationForLinker and not isIntrinsic.. so it seems we'd need to remove the test for isIntrinsic. Will see if that is possible without further side effects.

@aardappel
Copy link
Collaborator

Removing the isIntrinsic check now additionally emits .functype llvm.memset.p0i8.i32 (i32, i32, i32, i32) -> () in the asm, which is neither the right name nor the right signature (it's being called with 3 args like you expect).. ideas the ideal fix for this?

@dschuff
Copy link
Member

dschuff commented Feb 22, 2022

No, I actually did mean declared but not defined. If you have

#include <stddef.h>
void *mumset(void *s, int c, size_t n);

void foo(void* s, size_t n) {
  mumset(s, 0, n);
}

and compile to asm, you get

.functype       mumset (i32, i32, i32) -> (i32)
...
call mumset

in the output.
But I just discovered that if you call it memset instead, you get the call to memset, but no declaration (even thought the call is explicit and not generated by the backend). So I'd guess that it's maybe the same problem, and it's not whether the call is generated by the backend, but whether it's recognized as an intrinsic?

@aardappel
Copy link
Collaborator

Possible fix here: https://reviews.llvm.org/D120365

mem-frob pushed a commit to draperlaboratory/hope-llvm-project that referenced this issue Oct 7, 2022
Intrinsics like `memset` were not emitted as `.functype` because
WebAssemblyAsmPrinter::emitExternalDecls explicitly skips symbols
that are isIntrinsic. Removing that check doesn't work, since the symbol
from the module refers to a 4-argument `llvm.memset.p0i8.i32` rather
than the 3-argument `memset` symbol referenced in the call.
Our `WebAssemblyMCLowerPrePass` however does collect the
`memset` symbol, so the current solution is as simple as emitting
`.functype` for those.

Fixes: llvm/llvm-project#53712

Differential Revision: https://reviews.llvm.org/D120365
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants