We (Reason Studios) make some use of “generic” LLVM IR code.
We have been using LLVM 7.0.0 for Mac and Windows/x64 since 2019, and are now updating to a current version. (The update was motivated by gaining support for arm64 on macOS, but also 7.0.0 is old now.)
After this update, some of our test cases don’t work on Windows/x64.
I have narrowed it down to “passing a small type as an argument using byval” which only seems to work properly for the first four arguments.
The details should be clear in this archive of files, which can be used to repeat the issue (see details below).
I tested a number of LLVM stable releases found the last version where this works is LLVM 10.0.0.
Starting from LLVM 11.0.0 (all the way to 16.0.5), arguments five and later do not arrive intact.
So this type of test case stopped working at some point between LLVM 10.0.0 and 11.0.0.
The fact that the first four arguments work makes me think the x64 calling convention is somehow involved (as it treats the first four args differently).
A few observations:
- If I enable optimizations (-O1 or higher), no code is generated. As if it assumes the external function can not be called (=the checks can’t fail from the perspective of the IR or so).
- If I compile the equivalent C++ code for Windows and ask clang to emit the IR, it does not use byval like this. So I guess mainstream use cases with LLVM as a C++ compiler for Windows/x64 will never go via such IR code. Unfortunately we are stuck with quite a bit of it…
- The same test works fine on macOS/x64.
Trying to find an answer to these questions:
- Is this IR code bad / unsupported somehow (at least on Windows), and why?
- What might have changed that made this no longer work in LLVM 11 and later (some time after LLVM 10.0.0)?
- Does anyone know a practical way to make it work?
Any other comments are also welcome.
File list:
- Test.ll: LLVM IR test code.
- build.py: Script to build a native executable for Windows.
- testglue/glue1.cpp: Minimal test environment, to let the test code report if things are wrong.
- src/Test.cpp: Equivalent C++ source for reference.
- readme.txt: This text.
How to build and run the test:
- Install MSVC / MS build C++ tools for Desktop/x64 on a Windows system.
- Start a command prompt with that compiler environment activated for targeting x64 (shortcut such as “x64 Native Tools Command Prompt for …”)
- Run the script using python 3.x:
python -u build.py --clang="C:\Program Files\LLVM\bin\clang.exe" --run-test
python3 -u build.py --clang="C:\Program Files\LLVM\bin\clang.exe" --run-test
py -3 -u build.py --clang="C:\Program Files\LLVM\bin\clang.exe" --run-test
The results vary when passing different versions of clang.exe as the --clang argument:
Test result if successful (LLVM 10.0.0 and earlier): No output, returns zero.
Test result if non-successful (LLVM 11.0.0 and later - could not find a Windows installer for 10.0.1): Logs and returns non-zero.
Observed log to stdio on failure (LLVM-11.0.0 and later):
CC2023_FailAssertLog(): i5.f_ptr == np
Assertion failed: false, file testglue/glue1.cpp, line 6
...python traceback omitted...
subprocess.CalledProcessError: Command '['Test.exe']' returned non-zero exit status 3221226505.
Edit: Log snippet differs slightly in readme.txt - the test code was tweaked to be shorter, but is equivalent.