XilinxのVitits-HLSのフロントエンドがオープンソースとして公開された。正直Vitis-HLSはその存在も目的も全く知らなかったのだが、フロントエンドがLLVMで、その実装が公開されたと知り、LLVM探検隊団員として調査しないわけにはいかないだろうということで調査することにしてみた。
試行にはVitis-HLS 2020.2が必要ということでダウンロードしてインストールした。まったくなんでこんなにディスク容量を消費するんだ...外部SSDがXilinxのディレクトリでどんどん消費されていく。
Vitis-HLS LLVM 2020.2のリポジトリをダウンロードする。
git clone https://github.com/Xilinx/HLS.git
Vitis-HLSの構成図だが、C言語のソースコードをコンパイルしてBitCodeを出力するところまでがオープンソースで公開されているらしい。というか、この部分は極めて一般的なC言語のコンパイル部分だろうがこれをopt
を使ってPASSで最適化していくところがXilinxオリジナルの部分ということだろうか。ちょっと調査対象がフロントエンド側すぎるな。
とりあえずHLSリポジトリでビルドを実行する。デフォルトで全CPUを使うようなスクリプトになっているが、これだけで非常に時間がかかってしまう。やはりLLVMのビルドでノートPCを使うのは厳しいなあ...
$ cd HLS/llvm
$ ./build.sh
ビルドが完了すると、hls-build
ディレクトリができる。これがVitis-HLSにフロントエンドのディレクトリとして直接指定されているようだ。
次にサンプルプログラムのディレクトリに移動して、override_llvm_flow_demo
を実行してみる。
$ cd ../vitis_hls_examples/override_llvm_flow_demo
$ vitis_hls run_hls.tcl
とりあえず実行してみると、以下のようなエラーメッセージが出て終了してしまった。
INFO: [SIM 211-2] *************** CSIM start *************** INFO: [SIM 211-4] CSIM will launch GCC as the compiler. Compiling ../../../../hls_example.cpp in debug mode In file included from /usr/include/bits/errno.h:26:0, from /usr/include/errno.h:28, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/cerrno:42, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/ext/string_conversions.h:44, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/bits/basic_string.h:5402, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/string:52, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/bits/locale_classes.h:40, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/bits/ios_base.h:41, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/ios:42, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/ostream:38, from /home/msyksphinz/work3/Xilinx/Vitis_HLS/2020.2/tps/lnx64/gcc-6.2.0/include/c++/6.2.0/iostream:39, from ../../../../hls_example.cpp:21: /usr/include/linux/errno.h:1:23: fatal error: asm/errno.h: No such file or directory #include <asm/errno.h> ^ compilation terminated. make: *** [csim.mk:72: obj/hls_example.o] Error 1 ERROR: [SIM 211-100] 'csim_design' failed: compilation error(s). INFO: [SIM 211-3] *************** CSIM finish *************** INFO: [HLS 200-111] Finished Command csim_design CPU user time: 0.05 seconds. CPU system time: 17.56 seconds. Elapsed time: 19.15 seconds; current allocated memory: 206.277 MB. 4 while executing "source run_hls.tcl" invoked from within "hls::main run_hls.tcl" ("uplevel" body line 1) invoked from within "uplevel 1 hls::main {*}$newargs" (procedure "hls_proc" line 16) invoked from within "hls_proc [info nameofexecutable] $argv"
以下のウェブサイトを参考にすると、どうも以下の環境変数を設定しなければならないらしい。
$ export CPATH=/usr/include/x86_64-linux-gnu
もう一度実行する。今度は上手く行った。
source xsim.dir/example/xsim_script.tcl # xsim {example} -autoloadwcfg -tclbatch {example.tcl} Vivado Simulator 2020.2 Time resolution is 1 ps source example.tcl ## run all //////////////////////////////////////////////////////////////////////////////////// // Inter-Transaction Progress: Completed Transaction / Total Transaction // Intra-Transaction Progress: Measured Latency / Latency Estimation * 100% // // RTL Simulation : "Inter-Transaction Progress" ["Intra-Transaction Progress"] @ "Simulation Time" //////////////////////////////////////////////////////////////////////////////////// // RTL Simulation : 0 / 1 [0.00%] @ "109000" // RTL Simulation : 1 / 1 [100.00%] @ "359000" //////////////////////////////////////////////////////////////////////////////////// $finish called at time : 372410 ps : File "/home/msyksphinz/work3/work/llvm/HLS/vitis_hls_examples/override_llvm_flow_demo/proj/solution1/sim/verilog/example.autotb.v" Line 462 ## quit INFO: [Common 17-206] Exiting xsim at Sun Mar 14 23:33:41 2021...
さて、成果物を確認しよう。
./syn/verilog/example.v
// ============================================================== // RTL generated by Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2020.2 (64-bit) // Version: 2020.2 // Copyright (C) Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. // // =========================================================== `timescale 1 ns / 1 ps (* CORE_GENERATION_INFO="example_example,hls_ip_2020_2,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7v585t-ffg1761-2,HLS_INPUT_CLOCK=3.333000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=2.433090,HLS_SYN_LAT=64,HLS_SYN_TPT=none,HLS_SYN_MEM=4,HLS_SYN_DS P=0,HLS_SYN_FF=1176,HLS_SYN_LUT=1398,HLS_VERSION=2020_2}" *) module example ( ap_clk, ap_rst_n, ap_start, ap_done, ap_idle, ...
もう一つはBitCodeだ。ディスアセンブルしてどのようになっているの確認する。
./proj/solution1/.autopilot/db/hls_example.g.bc
$ llvm-dis-7 proj/solution1/.autopilot/db/hls_example.g.bc -o -
define void @_Z7examplePiS_(i32* "fpga.address.interface"="m_axi.0" "fpga.data.footprint.hint"="50" "fpga.decayed.dim.hint"="50" %a, i32* "fpga.address.interface"="m_axi.0" "fpga.data.footprint.hint"="50" "fpga.decayed.dim.hint"="50" %b) #4 !dbg !2243 { entry: %a.addr = alloca i32*, align 8 %b.addr = alloca i32*, align 8 %buff = alloca [50 x i32], align 4 %i = alloca i64, align 8 store i32* %a, i32** %a.addr, align 8 call void @llvm.dbg.declare(metadata i32** %a.addr, metadata !2247, metadata !DIExpression()), !dbg !2248 store i32* %b, i32** %b.addr, align 8 call void @llvm.dbg.declare(metadata i32** %b.addr, metadata !2249, metadata !DIExpression()), !dbg !2250 %0 = load i32*, i32** %a.addr, align 8, !dbg !2251 call void (...) @_Z22_ssdm_SpecArrayDimSizez(i32* %0, i32 50) #3, !dbg !2252 %1 = load i32*, i32** %b.addr, align 8, !dbg !2253 call void (...) @_Z22_ssdm_SpecArrayDimSizez(i32* %1, i32 50) #3, !dbg !2254 call void @llvm.dbg.declare(metadata [50 x i32]* %buff, metadata !2255, metadata !DIExpression()), !dbg !2259 br label %VITIS_LOOP_31_1, !dbg !2260 VITIS_LOOP_31_1: ; preds = %entry call void @llvm.dbg.declare(metadata i64* %i, metadata !2261, metadata !DIExpression()), !dbg !2263 store i64 0, i64* %i, align 8, !dbg !2263 br label %for.cond, !dbg !2264 for.cond: ; preds = %for.inc, %VITIS_LOOP_31_1 %2 = load i64, i64* %i, align 8, !dbg !2265 %cmp = icmp ult i64 %2, 50, !dbg !2267 br i1 %cmp, label %for.body, label %for.end, !dbg !2268 for.body: ; preds = %for.cond
ふーむ、これだけでは良く分からない。一般的なLLVM IRだ。もう少し生成フローを確認していこう。