FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Vitis-HLSのLLVMフロントエンドを試す

XilinxのVitits-HLSのフロントエンドがオープンソースとして公開された。正直Vitis-HLSはその存在も目的も全く知らなかったのだが、フロントエンドがLLVMで、その実装が公開されたと知り、LLVM探検隊団員として調査しないわけにはいかないだろうということで調査することにしてみた。

試行にはVitis-HLS 2020.2が必要ということでダウンロードしてインストールした。まったくなんでこんなにディスク容量を消費するんだ...外部SSDXilinxディレクトリでどんどん消費されていく。

Vitis-HLS LLVM 2020.2のリポジトリをダウンロードする。

github.com

git clone https://github.com/Xilinx/HLS.git

Vitis-HLSの構成図だが、C言語ソースコードコンパイルしてBitCodeを出力するところまでがオープンソースで公開されているらしい。というか、この部分は極めて一般的なC言語コンパイル部分だろうがこれをoptを使ってPASSで最適化していくところがXilinxオリジナルの部分ということだろうか。ちょっと調査対象がフロントエンド側すぎるな。

high-level-inject-flow.png

とりあえず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"

以下のウェブサイトを参考にすると、どうも以下の環境変数を設定しなければならないらしい。

japan.xilinx.com

$ 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だ。もう少し生成フローを確認していこう。