How can I compile with LLVM/Clang to RISC-V target? - compilation

I want to compile a simple program "int main(){return 0;}" to RISC-V processor.
LLVM/Clang version is 9.0 and I want to run the compiled program with a RISC-V simulator like this https://github.com/riscv/riscv-tools
My problem is that I can't list the clang supported targets only the LLC-s whith these commands:
llc --version
llc -march=xxARCHTYPExx -mattr=help
And there is no any type of riscv processor listed.
So I tried to look the triple file: llvm-project\llvm\include\llvm\ADT\Triple.h
and try a command like: clang hello.c -target riscv32 -march=rv32imafd
But I get the following error:
error: unable to create target: 'No available targets are compatible
with triple "riscv32"'
Can somebody help me to how get a valid RISC-V target? I just simple can't compile the program but I know LLVM has a RISC-V support.

LLVM 9 release notes explicitly state that RISC-V support was promoted from experimental to official.
And indeed, on my Fedora 31 machine, the LLVM 9 Fedora package does support RISC-V:
$ llvm-objdump --version | grep riscv
riscv32 - 32-bit RISC-V
riscv64 - 64-bit RISC-V
Also, I can create RISC-V binary code with the LLVM toolchain:
$ clang --target=riscv64 -march=rv64gc rotate.s -c -o rotate.o
$ file rotate.o
rotate.o: ELF 64-bit LSB relocatable, UCB RISC-V, version 1 (SYSV), not stripped
Although it doesn't include a libc for RISC-V targets:
$ clang --target=riscv64 -march=rv64gc hello-world.c -o hello-world
hello-world.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
^~~~~~~~~
1 error generated.
However, you don't really need one - you could directly call syscalls for your hello world, e.g.:
$ clang --target=riscv64 -march=rv64gc hello.s -c -o hello.o
$ ld.lld hello.o -o hello
$ spike --isa=RV64gc ~/local/riscv/pk/riscv64-unknown-elf/bin/pk ./hello
bbl loader
Hello World
I don't use clang for linking because it seems that I can't convince clang with -fuse-ld to use another linker besides /usr/bin/ld.

Related

Using Clang to compile for RISC-V

I am trying to build a hello world program using Clang (version 12.0.1) for RISC-V architecture. I have installed it with LLVM (version 12.0.1) with the following setup:
cmake -G "Unix Makefiles" \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lldb;compiler-rt;lld;polly;debuginfo-tests" \
-DCMAKE_BUILD_TYPE=Debug \
-DLLVM_ENABLE_ASSERTIONS=On \
../llvm
According to here, default LLVM_TARGETS_TO_BUILD is LLVM_ALL_TARGETS, which includes RISC-V.
So I try to compile it with clang --target=riscv64 -march=rv64gc hello_world.c -o hello_world and I am getting the error:
hello_world.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
^~~~~~~~~
1 error generated.
At the same time, /opt/risv/, where I have installed the riscv-gnu-toolchain, is in my path, and I can run riscv64-unknown-linux-gnu-gcc hello_world.c -o hello_world without issues.
I am trying on an Ubuntu machine with kernel 5.8.0-63-generic.
Any idea how can I solve this issue and be able to compile RISC-V programs through Clang?
Foreknowledge:
I had same delusion about this: "If llvm is targeting for all backends including riscv, we should be able to compile our codes just giving a clang flag like --target=riscv32, -target riscv64 etc. without doing extra operation" and I had similar question, but it is not like that. Although LLVM supports riscv target, you need to specify sysroot and gcc toolchain for using riscv headers and libraries, in the other words you need cross compilation. (because you are currently operating a system like x86-64 different from riscv and your default libraries are different) That's why you need to link your riscv-gnu-toolchain paths. Here I assume that you built your riscv-gnu-toolchain from github clone.
Note: Some people have problems with first option (1) and please try to use other options (2) (3) (4) firstly. (Look into comments.)
Solution:
1-) You can add these lines as your cmake configuration flags before building your llvm library:
For 32 bit riscv:
-DDEFAULT_SYSROOT="{your-riscv-gnu-toolchain-install-or-build-path}/riscv32-unknown-elf"
-DGCC_INSTALL_PREFIX="{your-riscv-gnu-toolchain-install-or-build-path}"
For 64 bit riscv:
-DDEFAULT_SYSROOT="{your-riscv-gnu-toolchain-install-or-build-path}/riscv64-unknown-elf"
-DGCC_INSTALL_PREFIX="{your-riscv-gnu-toolchain-install-or-build-path}"
and then build llvm library again. Probably as you know, in your llvm build directory:
cmake --build .
Here is an example in my case according to your cmake configuration for clearance:
cmake -G "Unix Makefiles" \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;libcxx;libcxxabi;libunwind;lldb;compiler-rt;lld;polly;debuginfo-tests" \
-DCMAKE_BUILD_TYPE=Debug \
-DLLVM_ENABLE_ASSERTIONS=On \
-DDEFAULT_SYSROOT="/home/shc/riscv/install/riscv64-unknown-elf" \
-DGCC_INSTALL_PREFIX="/home/shc/riscv/install" \
../llvm
cmake --build .
Also you can set default target triple as riscv with another cmake configuration flag:
For 32 bit riscv:
-DLLVM_DEFAULT_TARGET_TRIPLE="riscv32-unknown-elf"
For 64 bit riscv:
-DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-elf"
After this you should be able to compile your codes like these examples:
For C:
/home/shc/llvm/llvm-project/build/bin/clang -march=rv64gc hello_world.c -o hello_world
For C++:
/home/shc/llvm/llvm-project/build/bin/clang++ -march=rv64gc hello_world.cpp -o hello_world
If you didn't set default target triple with cmake flag, target option should remain:
For C:
/home/shc/llvm/llvm-project/build/bin/clang --target=riscv64 -march=rv64gc hello_world.c -o hello_world
For C++:
/home/shc/llvm/llvm-project/build/bin/clang++ --target=riscv64 -march=rv64gc hello_world.cpp -o hello_world
2-) You can pass sysroot and gcc toolchain as flags(as in cmake configurations above) while compiling your code without building your library again. However, if you will use this, you need to give these flags in every compilation:
For 32 bit riscv:
--sysroot="{your-riscv-gnu-toolchain-install-or-build-path}/riscv32-unknown-elf"
--gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"
For 64 bit riscv:
--sysroot="{your-riscv-gnu-toolchain-install-or-build-path}/riscv64-unknown-elf"
--gcc-toolchain="{your-riscv-gnu-toolchain-install-or-build-path}"
Usage of Flags For C:
/home/shc/llvm/llvm-project/build/bin/clang --sysroot=/home/shc/riscv/install/riscv64-unknown-elf --gcc-toolchain=/home/shc/riscv/install --target=riscv64 -march=rv64gc hello_world.c -o hello_world
Usage of Flags For C++:
/home/shc/llvm/llvm-project/build/bin/clang++ --sysroot=/home/shc/riscv/install/riscv64-unknown-elf --gcc-toolchain=/home/shc/riscv/install --target=riscv64 -march=rv64gc hello_world.cpp -o hello_world
3-) You can try to pass these flags while compiling (instead of your --target=riscv64 flag) although it is not more healthy than above options. (Attention: difference is only linux keyword, normally it was -target riscv32-unknown-elf):
For 32 bit riscv:
-target riscv32-unknown-linux-elf
For 64 bit riscv:
-target riscv64-unknown-linux-elf
4-) You can use riscv-llvm repo by following given instructions, although it is outdated.
Note: I adapted my file locations to your examples to better understanding.
Further information you can look here: https://github.com/lowRISC/riscv-llvm#how-can-i-build-upstream-llvmclang-and-use-it-to-cross-compile-for-a-riscv32-target
Finally i deal with that! i`m used next keys:
cmake -G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE="Release" \
-DBUILD_SHARED_LIBS=True \
-DCMAKE_INSTALL_PREFIX="/home/username/llvm-install" \
-DLLVM_OPTIMIZED_TABLEGEN=ON -DLLVM_BUILD_TESTS=False \
-DDEFAULT_SYSROOT="/home/username/esp-toolchain-install/riscv64-unknown-elf" \
-DGCC_INSTALL_PREFIX="/home/username/esp-toolchain-install" \
-DLLVM_ENABLE_PROJECTS="clang;lld" \
-DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-elf" \
-DLLVM_TARGETS_TO_BUILD="RISCV" ../llvm
and i copied content of esp-toolchain-install/* into llvm-install/*. And clang finally saw all of GCC files:
clang -v -print-search-dirs
clang version 12.0.1 (https://github.com/llvm/llvm-project.git fed41342a82f5a3a9201819a82bf7a48313e296b)
Target: riscv64-unknown-unknown-elf
Thread model: posix
InstalledDir: /home/username/llvm-install/bin
Found candidate GCC installation: /home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0
Selected GCC installation: /home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0
Candidate multilib: rv32i/ilp32;#march=rv32i#mabi=ilp32
Candidate multilib: rv32im/ilp32;#march=rv32im#mabi=ilp32
Candidate multilib: rv32iac/ilp32;#march=rv32iac#mabi=ilp32
Candidate multilib: rv32imac/ilp32;#march=rv32imac#mabi=ilp32
Candidate multilib: rv32imafc/ilp32f;#march=rv32imafc#mabi=ilp32f
Candidate multilib: rv64imac/lp64;#march=rv64imac#mabi=lp64
Candidate multilib: rv64imafdc/lp64d;#march=rv64imafdc#mabi=lp64d
Selected multilib: rv64imac/lp64;#march=rv64imac#mabi=lp64
programs: =/home/username/llvm-install/bin:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/bin:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../bin
libraries: =/home/username/llvm-install/lib/clang/12.0.1:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/rv64imac/lp64:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0/../../../../riscv64-unknown-elf/lib/rv64imac/lp64:/home/username/llvm-install/bin/../lib/gcc/riscv64-unknown-elf/9.2.0:/home/username/esp-toolchain-install/riscv64-unknown-elf/lib

How to use clang to create a windows binary

I have installed clang on my Windows 10 machine.
$ clang --version
clang version 6.0.1 (tags/RELEASE_601/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
With it, I can compile C and C++ sources and generate object files, and use lib.exe to create libraries of them.
When it's time to link it into a binary, to my surprise, clang is creating a lib/exp output, not an executable?
Why does clang think it should be creating a library, not an executable?
clang++ -oarmor XWin/main.o -lSDL2main -lpi -ldblunt -lsino -lbase -L. -L ../../src/sino -L MSWin/libs/SDL/lib ../../src/Chipmunk2D/build.release/x64/Release/chipmunk.lib MSWin/libs/OpenAL/lib/OpenAL32.lib -lSDL2 -lOpenGL32
Creating library armor.lib and object armor.exp
LINK : fatal error LNK1561: entry point must be defined
clang++.exe: error: linker command failed with exit code 1561 (use -v to see invocation)
In UNIX, clang will by default create binaries, not libraries?
Check this link -
https://metricpanda.com/rival-fortress-update-27-compiling-with-clang-on-windows
There are currently two flavors of Clang that work on Windows: vanilla LLVM Clang and Clang/C2 with Microsoft Codegen.

OpenMP not available on mac with gcc 4.9

The OpenMP website says: "GCC 4.9 supports OpenMP 4.0 for C/C++".
I'm using gcc 4.9.1 from brew, yet I see this error when I try to compile liblinear: omp.h file not found.
Specifically:
Compiling liblinear version 1.93
Source code page:
http://www.csie.ntu.edu.tw/~cjlin/liblinear/
external/liblinear-1.93_multicore/matlab/train.cpp:7:10: fatal error: 'omp.h' file not found
#include <omp.h>
^
1 error generated.
mex: compile of ' "external/liblinear-1.93_multicore/matlab/train.cpp"' failed.
Here's the matlab code used to compile liblinear, which contains a file that contains #include <omp.h>:
% Compile liblinear
if ~exist('liblinear_train')
fprintf('Compiling liblinear version 1.93\n');
fprintf('Source code page:\n');
fprintf(' http://www.csie.ntu.edu.tw/~cjlin/liblinear/\n');
mex -outdir bin ...
COMPFLAGS="$COMPFLAGS -fopenmp" -largeArrayDims ...
external/liblinear-1.93_multicore/matlab/train.cpp ...
external/liblinear-1.93_multicore/matlab/linear_model_matlab.cpp ...
external/liblinear-1.93_multicore/linear.cpp ...
external/liblinear-1.93_multicore/tron.cpp ...
"external/liblinear-1.93_multicore/blas/*.c" ...
-output liblinear_train;
end`
UPDATE
I changed the gcc version in mexopts.sh (side note: I copied it from /Applications/MATLAB_R2013a_Student.app/bin/mexopts.sh to ~/.matlab/R2013a). Specifically, I changed CC=xcrun -sdk macosx10.9 clang to CC='gcc-4.9'.
I think Matlab does indeed use this compiler, because when I run this code:
if ~exist('anigauss')
fprintf('Compiling the anisotropic gauss filtering of:\n');
fprintf(' J. Geusebroek, A. Smeulders, and J. van de Weijer\n');
fprintf(' Fast anisotropic gauss filtering\n');
fprintf(' IEEE Transactions on Image Processing, 2003\n');
fprintf('Source code/Project page:\n');
fprintf(' http://staff.science.uva.nl/~mark/downloads.html#anigauss\n\n');
mex -Dchar16_t=uint16_T -outdir bin ...
selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c ...
selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss.c ...
-output anigauss
end
Matlab prints:
dyld: Library not loaded: /usr/local/opt/mpfr2/lib/libmpfr.1.dylib
Referenced from: /usr/local/Cellar/gcc49/4.9.1/libexec/gcc/x86_64-apple-darwin14.0.0/4.9.1/cc1
Reason: Incompatible library version: cc1 requires version 4.0.0 or later, but libmpfr.1.dylib provides version 3.0.0
gcc-4.9: internal compiler error: Trace/BPT trap: 5 (program cc1)
/Applications/MATLAB_R2013a_Student.app/bin/mex: line 1343: 77128 Abort trap: 6 gcc-4.9 -c -I/Applications/MATLAB_R2013a_Student.app/extern/include -I/Applications/MATLAB_R2013a_Student.app/simulink/include -DMATLAB_MEX_FILE -fno-common -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -mmacosx-version-min=10.9 -fexceptions -Dchar16_t=uint16_T -DMX_COMPAT_32 -O2 -DNDEBUG "selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c" -o bin/anigauss_mex.o
mex: compile of ' "selective_search/SelectiveSearchCodeIJCV/Dependencies/anigaussm/anigauss_mex.c"' failed.
Yet when I try to compile liblinear, I get the very same error message as usual.
COMPFLAGS="$COMPFLAGS /openmp" -largeArrayDims ...
^^^^^^^
This was probably written for Microsoft Visual C/C++ or for Intel C/C++ Compiler on Windows. Unix systems, including OS X, traditionally use - to denote command line flags.
To enable OpenMP support in GCC you should change /openmp to -fopenmp in the compiler flags COMPFLAGS.
It appears that in addition to passing the wrong OpenMP flag, mex is using the wrong compiler. Compare the error outputs from GCC and Clang:
GCC
foo.c:1:25: fatal error: nonexistent.h: No such file or directory
#include <nonexistent.h>
^
compilation terminated.
Clang
foo.c:1:10: fatal error: 'nonexistent.h' file not found
#include <nonexistent.h>
^
1 error generated.
Clang, or at least the version that Apple ships with Xcode, does not support OpenMP. Consult the MATLAB documentation of the mex command on how to select a different compiler. Basically, you have to execute:
mex -setup
If MATLAB detects several usable compilers, it should present you with the ability to pick one of them. Unfortunately, according to this table, MATLAB might not support GCC on OS X (at least it is not listed in the table).

Should gcc builtins always be resolved during the compilation step, or the linker step?

In running gcc 3.4.3 on a Solaris 5.11 box I see that builtin functions are left undefined during compilation, but are resolved against libgcc.a when the Solaris linker links against libgcc.a.
On gcc 4.5.2 on another Solaris box, the same builtin functions are resolved during compilation of the .o, and the linker isn't concerned about them.
A boiled down example file compiled on gcc 3.4.3:
# cat ctzll.c
int func(unsigned long long x)
{
return __builtin_ctzll(x);
}
# cat main.c
int main(void)
{
return func(0xc0ffee);
}
First compile ctzll.c, and check the symbols:
# nm ctzll.o
U __ctzdi2
0000000000000000 T func
Now compile main.c, and link the objects:
# gcc -m64 main.c -c
# gcc -m64 ctzll.o main.o -v
Reading specs from /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/specs
Configured with: /build/i386/components/gcc3/gcc-3.4.3/configure --prefix=/usr/sfw --mandir=/usr/sfw/share/man --infodir=/usr/sfw/share/info --without-gnu-ld --with-ld=/usr/bin/ld --enable-languages=c,c++,f77,objc --enable-shared --with-gnu-as --with-as=/usr/gnu/bin/as
Thread model: posix
gcc version 3.4.3 (csl-sol210-3_4-20050802)
/usr/sfw/libexec/gcc/i386-pc-solaris2.11/3.4.3/collect2 -V -Y P,/lib/64:/usr/lib/64:/usr/sfw/lib/64 -R /lib/64:/usr/lib/64:/usr/sfw/lib/64 -Qy /usr/lib/amd64/crt1.o /usr/lib/amd64/crti.o /usr/lib/amd64/values-Xa.o /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/crtbegin.o -L/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64 -L/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/../../../amd64 -L/lib/amd64 -L/usr/lib/amd64 ctzll.o main.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/crtend.o /usr/lib/amd64/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.11-1.2276
# nm a.out | grep ctz
0000000000400fd0 T __ctzdi2
So, if I understand correctly, the Solaris linker resolved __ctzdi2 (the internal representation of __builtin_ctzll).
Now, compile with gcc 4.5.2 on the other Solaris machine:
#gcc -m64 ctzll.c -c
# nm ctzll.o
0000000000000000 T func
The symbol has been resolved fine in the object file, and it has been inlined into the .o assembly as:
8: 48 0f bc 45 f8 bsf -0x8(%rbp),%rax
Is the 3.4.3 compiler behaving correctly? I'd have expected the actual compilation to handle the builtins, like 4.5.2, by referencing the 64 bit version of libgcc.a. The lack of uniformity across the compilers is causing upstream problems in my project as the builtin remains undefined and the linker isn't resolving the symbols as I'm not linking against the OS specific 64 bit libraries (libgcc.a). I'm not sure if the 3.4.3 compiler is misconfigured causing the .o files to have undefined builtin functions caught by linking, or if the newer compilers are just smarter and I need to add the 64 bit libraries to the linker to handler the older compiler.
The 3.4.3 seems to show a valid libgcc.a which contains the definition of _ctzdi2:
# gcc -m64 -print-libgcc-file-name
/usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/libgcc.a
# nm /usr/sfw/lib/gcc/i386-pc-solaris2.11/3.4.3/amd64/libgcc.a | grep ctzdi2
0000000000000000 T __ctzdi2
_ctzdi2.o:
The whole point of libgcc.a is to implement builtin operations that gcc can't emit code for (which includes not only __builtin_ functions, but also things like 'long long' math operations on some 32-bit platforms).
Obviously the newer gcc got smarter about emitting code.

Compiling gcc with AVR options

I want to generate the assembly file of my code oriented to the AVR architecture, I am using gcc version 4.7.2 with the following arguments:
g++ -O3 -Wall -S -Wp,-mmcu=atmega8 -o "src\Compression.o" "..\src\Compression.cpp"
but I am getting the following error:
cc1plus.exe: error: unrecognized command line option '-mmcu=atmega8'
But I got the command options from the gcc website:
http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/AVR-Options.html#AVR-Options
There should be something that I am missing, could you help me with this please!
If gcc does not accept -mmcu, you are probably not using a gcc with support for the AVR architecture.
It's normally used like this:
avr-gcc -mmcu=atmega328p
because it's not only the preprocessor, it's actually other tools as well which require this setting (linker, assembler).
Normally the architecture gcc is compiled for is indicated by a prefix, in this case it's avr- by convention.
So the solution is to get a toolchain with AVR support. You can download it from Atmel's web site, even for Linux.
Update
If you like to check the configuration of your gcc, you can use -dumpmachine to check for the target processor
$ gcc -dumpmachine
i486-linux-gnu
$ arm-none-eabi-gcc -dumpmachine
arm-none-eabi
$ avr-gcc -dumpmachine
avr
If you look at the target specific options using --target-help
$ gcc --target-help | grep march
-march= Generate code for given CPU
you can see that the Linux gcc does accept -march as well. It probably fails later.
gcc is a very complex piece of software, because it just supports so many different architectures. From that perspective it works amazingly well.
Another interesting option is -v
$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8'
[...]
to see how that gcc has been built.
And there could be another trap down the road (multi-libs), as you can see here

Resources