nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.57k stars 1.47k forks source link

nim compiler flag `--asm` fails on arm64 macs #17139

Open ShadowElf37 opened 3 years ago

ShadowElf37 commented 3 years ago

Full error

user@user Nim % nim c --asm --nimcache:. test.nim
Hint: used config file '/usr/local/bin/Nim/config/nim.cfg' [Conf]
Hint: used config file '/usr/local/bin/Nim/config/config.nims' [Conf]
....
Hint: Produced assembler here: /Users/.../Nim/stdlib_io.nim.c.asm
Hint: Produced assembler here: /Users/.../Nim/stdlib_system.nim.c.asm
Hint: Produced assembler here: /Users/.../Nim/@mtest.nim.c.asm
CC: stdlib_io.nim
CC: stdlib_system.nim
CC: test.nim
clang: error: unsupported argument '-acdl=/Users/.../Nim/@mtest.nim.c.asm' to option 'Wa,'

Error: execution of an external compiler program 'clang -Wa,-acdl=/Users/.../Nim/@mtest.nim.c.asm -g -fverbose-asm -masm=intel -c  -w -ferror-limit=3   -I/usr/local/bin/Nim/lib -I/Users/.../Nim -o /Users/.../Nim/@mtest.nim.c.o /Users/.../Nim/@mtest.nim.c' failed with exit code: 1

It didn't actually affect anything when I changed or removed the value during testing, but -masm=intel is an odd flag to have on arm64. Not sure if that's intentional.

I confirmed --asm works on Windows. I don't have an Intel Mac to test this on but I think it's safe to say this is an arm64 issue Confirmed broken on x86 as well, although there may be deeper issues on arm64 (see comments).

Possible solution

I am by no means qualified to say whether this is the correct solution, but I played around a bit with the command and got this working:

clang  -g -fverbose-asm -c  -w -ferror-limit=3   -I/usr/local/bin/Nim/lib -I/Users/.../Nim -o /Users/.../Nim/@mtest.nim.c.asm -S /Users/.../Nim/@mtest.nim.c

Unfortunately this doesn't also produce the .o file, which I believe is the intended behavior. Although, if you're passing --asm, it's probably because you don't care about the .o file that much.

$ nim -v
Nim Compiler Version 1.5.1 [MacOSX: arm64]
Compiled at 2021-01-31
alaviss commented 3 years ago

I don't have an Intel Mac to test this on but I think it's safe to say this is an arm64 issue.

I think it is more likely that this is a clang issue. Can you try --passC:-fno-integrated-as to see if it solves the issue?

LLVM bug for reference: https://bugs.llvm.org/show_bug.cgi?id=16647

ShadowElf37 commented 3 years ago
/Library/Developer/CommandLineTools/usr/bin/as: can't specifiy -Q with -arch arm64
clang: error: assembler command failed with exit code 1 (use -v to see invocation)
Error: execution of an external compiler program 'clang -Wa,-acdl=/Users/.../Nim/@mtemplate_test.nim.c.asm -g -fverbose-asm -masm=intel -c  -w -ferror-limit=3 -fno-integrated-as   -I/usr/local/bin/Nim/lib -I/Users/.../Nim -o /Users/.../Nim/@mtemplate_test.nim.c.o /Users/.../Nim/@mtemplate_test.nim.c' failed with exit code: 1

I guess there are multiple issues here.

qaziquza commented 3 years ago

It is also happening on my Intel Mac.

demotomohiro commented 2 years ago

When GCC or Clang is used as backend compiler with --asm option, Nim always call it with "-Wa,-acdl=$asmfile -g -fverbose-asm -masm=intel" flags. (Search produceAsm or optProduceAsm in compiler/extccomp.nim)

-Wa,-acdl=$asmfile passes -acdl=$asmfile to the assembler used by GCC or Clang. If your clag uses integrated assembler or an assembler other than binutils, -acdl option can cause error as they doesn't support it. It seems GCC calls as in binutils in most of system. Clang uses LLVM’s integrated assembler on all targets where it is supported. And it uses the system assembler instead of it with -fno-integrated-as option. https://clang.llvm.org/docs/Toolchain.html#assembler

Producing assembler code with -S option might be easier because it works regardless of the assembler GCC/Clang uses. But, -S option stop compilation without calling assembler. So if you want --asm produces both assembler code and an executable, Nim has to call backend compiler twice, for producing an assembler code and for producing an object file.

I cannot find any options in LLVM's integrated assembler that can produce both an assembler code and an object file like -acdl option in binutil's as.

There is another problem when LTO is enabled. When LTO is enabled, the flag to produce a assembly code needs to be set at link time. https://stackoverflow.com/questions/58635734/getting-assember-output-from-gcc-clang-in-lto-mode

demotomohiro commented 2 years ago

I wrote workarounds using --passC and --passL options: https://internet-of-tomohiro.netlify.app/nim/faq.en.html#nim-compiler-how-to-produce-assembler-codeqmark

Possible solutions:

  1. --asm option produces assembler code but doesn't produce an executable

    • Run GCC or Clag with -S option to produce assembler code so that we can get it without knowing which assembler is used
    • Less additional code to compiler/extccomp.nim
  2. --asm option must produces both assembler code and an executable

    • Run GCC or Clang twice for producing an assembler code and for producing an object file

    • More additional code to compiler/extccomp.nim

    • Or ask Clang developers to add options that can produce both an assembler code and an executable

I think 1 is better. I don't think --asm option doesn't need to produce an executable.