Эльбрус/llvm
LLVM
В современных версиях ОС Эльбрус имеется LLVM 9, который может собирать код не только для платформ AMDGPU и, с недавнего времени, NVPTX (nVidia), но и для e2k. К примеру, для ОС Эльбрус 6.0.1:
molchan_i@yukari ~ $ head -n1 /etc/mcst_version 6.0.1 molchan_i@yukari ~ $ llvm-config --version 9.0.1 molchan_i@yukari ~ $ llvm-config --targets-built Elbrus AMDGPU NVPTX
clang
В состав ОС Эльбрус также входит clang как альтернатива lcc, который также умеет собирать ПО под Эльбрус.
Для примера - сборка архиватора plzip:
1. Выкачиваем исходники и распаковываем их:
wget http://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-1.12.tar.gz wget http://download.savannah.gnu.org/releases/lzip/plzip/plzip-1.9.tar.gz tar xf plzip-1.9.tar.gz tar xf lzlib-1.12.tar.gz
2. Создаём тестовый файл (заполненный рандомными значениями)
dd if=/dev/urandom of=testfile count=1k bs=1k
3. Сборка:
cd lzlib-1.12 ./configure CC=clang make -j4 cd ../plzip-1.9 ./configure CXX=clang++ CXXFLAGS=-I../lzlib-1.12 LDFLAGS=-L../lzlib-1.12 make -j8
4. Запуск:
molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile ../testfile: 0.987:1, 101.37% ratio, -1.37% saved, 1048576 in, 1062911 out. real 0m2,287s user 0m2,280s sys 0m0,010s
Для сравнения, тот же plzip, но собранный без указания CC=clang и CXX=clang++ (то есть, штатным lcc):
molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile ../testfile: 0.987:1, 101.37% ratio, -1.37% saved, 1048576 in, 1062911 out. real 0m0,823s user 0m0,800s sys 0m0,030s
Видно, что из коробки без настроек lcc даёт код, работающий быстрее в 2,5-3 раза, но когда что-то не собирается lcc (но при этом собирается clang-ом) - это хотя бы даёт возможность собрать и запустить что-то, что хочется запустить на эльбрусе.
llvm-cbe
Была попытка для сравнения использовать C-backend для LLVM - llvm-cbe.
Суть в том, что если штатный компилятор не может собрать исходный код (например, он ломается на этом коде, либо вообще нет компилятора для этого языка), мы преобразовываем исходный код в LLVM-IR, его с помощью llvm-cbe - в С-код (который сгенерён из LLVM-представления), а потом получившийся код собираем уже штатным С-компилятором.
Это выглядит примерно так:
clang -S -emit-llvm -g входной_файл.c -o файл_llvm_представления.ll # Здесь может быть любой компилятор, генерирующий LLVM-IR-выхлоп (.ll-файл) llvm-cbe файл_llvm_представления.ll # Из *.ll будет создан *.cbe.c gcc -c -o выходной_объектный_файл.o файл_llvm_представления.cbe.c
На Intel-машине выяснено, что нынешний вариант умеет собираться только под LLVM 8, 9, 10 и 11 (6 и 7 слишком старые). Изначально он умел только в LLVM 10 и 11, но после принятия PR #131 LLVM 8-9 также починились. К счастью, на Эльбрусе есть LLVM 9.0.1, так что нам этого достаточно.
1. Выкачиваем исходники:
git clone https://github.com/JuliaComputing/llvm-cbe cd llvm-cbe
2. Собираем для каждого из возможных LLVM и прогоняем unit-тесты
for i in 8 9 10 11 do echo -e "\n\e[1;33m************** $i ***************\n\e[0m" mkdir -p build-$i pushd build-$i cmake .. -DLLVM_DIR=/usr/lib/llvm-$i/cmake -DLLVM_INCLUDE_TESTS=1 && make -j16 llvm-cbe CBEUnitTests pushd unittests ./CWriterTest popd popd done
3. Пробуем собрать и выполнить один из примеров (в ./main.cbe нужно будет ввести количество элементов и собственно сами элементы для сортировки):
for i in 8 9 10 11 do echo -e "\n\e[1;33m************** $i ***************\n\e[0m" pushd build-$i clang-$i -S -emit-llvm -g ../test/selectionsort/main.c tools/llvm-cbe/llvm-cbe main.ll gcc-10 -Wno-builtin-declaration-mismatch -o main.cbe main.cbe.c ./main.cbe rm -f main.ll main.cbe main.cbe.c popd done
4. Попытка собрать lzlib и plzip
for i in 8 9 10 11 do echo -e "\n\e[1;33m************** $i ***************\n\e[0m" pushd build-$i # Собираем объектник lzlib: clang-$i -S -emit-llvm -g ../lzlib-1.12/lzlib.c -I../lzlib-1.12 -o lzlib.ll tools/llvm-cbe/llvm-cbe lzlib.ll gcc-10 -Wno-builtin-declaration-mismatch -c -o lzlib.o lzlib.cbe.c # Собираем plzip (вручную): for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main do # Увы, из-за issue-в, указанных ниже, собрать через llvm-cbe нельзя - собираем с помощью gcc # clang++-$i -S -emit-llvm -g -I../plzip-1.9 -I../lzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -o $src.ll ../plzip-1.9/$src.cc # tools/llvm-cbe/llvm-cbe $src.ll # gcc-10 -Wno-builtin-declaration-mismatch -Wno-address-of-packed-member -c -o $src.o $src.cbe.c gcc -I./plzip-1.9 -I../lzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o ../plzip-1.9/$src.cc done # Линкуемся с в том числе lzlib.o: g++ arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip ./plzip -kv ../testfile -o testfile-$i.lz ./plzip -tv testfile-$i.lz popd done
Из за нескольких проблем (issue 132, 133, 134, 138) llvm-cbe не может собрать всё целиком, поэтому для исходников plzip приходится использовать обычный gcc.
Видим, что все собранные plzip-ы отработали нормально.
4. И наконец, с учётом полученной информации, собираем под эльбрус. LCC не понимает комментария препроцессора "line 0", поэтому в CBE-выхлопе его надо заменять:
git clone https://github.com/JuliaComputing/llvm-cbe cd llvm-cbe mkdir -p build cd build cmake .. && make -j16 llvm-cbe wget http://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-1.12.tar.gz wget http://download.savannah.gnu.org/releases/lzip/plzip/plzip-1.9.tar.gz tar xf plzip-1.9.tar.gz tar xf lzlib-1.12.tar.gz dd if=/dev/urandom of=testfile count=1k bs=1k clang -S -emit-llvm -g lzlib-1.12/lzlib.c -Ilzlib-1.12 -o lzlib.ll tools/llvm-cbe/llvm-cbe lzlib.ll sed -i 's/#line 0/#line 1/' lzlib.cbe.c lcc -c -o lzlib.o lzlib.cbe.c for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main do l++ -Iplzip-1.9 -Ilzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o plzip-1.9/$src.cc done l++ arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip time ./plzip -fvk9 testfile
Результаты:
molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile testfile: 0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062838 out. real 0m8,134s user 0m8,080s sys 0m0,060s
Что ж, в 10 раз медленнее lcc, но иногда другого выхода нет.