掌桥专利:专业的专利平台
掌桥专利
首页

一种数据流图生成方法及装置

文献发布时间:2023-06-19 16:06:26



技术领域

本发明涉及面向异构处理器的编译领域,特别是涉及针对循环加速的代码编译时生成数据流图的方法及装置。

背景技术

数据流图(data flow graph 简称dfg)是描述软件系统中数据处理过程的一种有力的图形工具。 数据流图从数据传递和加工的角度出发, 刻画数据流从输入到输出的移动和变换过程。 由于它能够清晰地反映程序代码的执行过程, 所以它经常作为异构处理器的编译器的重要组成部分。

目前已有一些能够自动生成代码的数据流图的软件(如autoflowchart),但这些软件都是为程序员分析或展现代码逻辑用的,是业务逻辑的体现,仅分析代码级的字面意义,不考虑硬件环境,或是多考虑数据流图呈现给用于的界面效果(如布局、布线),而不关心其应用背景。由于缺少操作符、操作数等细节,不能被编译器所使用。

发明内容

本发明的目的是提供一种数据流图生成方法,该方法利用到llvm前端、中间表示(IR)及其已有的部分分析流程。llvm是一个开源的编译器框架,方便用户针对自己处理器的体系结构添加或修改编译流程(pass)。用于可重构编译器的前端,但不限于可重构编译器。任何需要并行执行指令的体系结构都可以使用。

本发明第一个方面,提供了一种数据流图生成方法,包括:在代码块中存在父循环代码的情景下,分析所述代码块中子代码块之间的依赖信息;遍历所述代码块中各个过程块,生成所述各个过程块对应的块数据流图;对所述各个过程块对应的数据流图添加所述依赖信息,生成所述代码块对应的代码数据流图;消除所述代码数据流图中的重复变量,建立所述各个过程块之间的连接关系,生成第一数据流图图文件,以使通过所述第一数据流图图文件展示所述代码块的数据流图。

可选的,所述消除所述代码数据流图中的重复变量,简化所述过程块并建立所述各个过程块之间的连接关系,生成第一数据流图图文件,以使通过所述第一数据流程图图文件展示所述代码块的数据流图之后,所述方法还包括:统计所述代码块中各个过程块连接关系;提取满足预设条件的过程块,并简化所述代码块中的过程块;获取所述各个过程块之间的关联或嵌套关系;补全所述各个过程块中的数据之间依赖距离,生成第二数据流图图文件,其中,所述依赖距离表示内存中的数据在所述代码块被多次访问,多次访问之间间隔的循环次数。

可选的,所述补全所述各个过程块中的数据之间依赖距离,生成第二数据流图图文件之后,所述方法还包括:生成所述代码块加载信息。

可选的,所述依赖关系包括先后顺序和/或包含关系。

可选的,所述获取所述各个过程块之间的关联或嵌套关系之后,所述方法还包括:将所述各个过程块中无用的过程块删除或转换为循环信息。

可选的,所述遍历所述代码块中各个过程块,生成所述各个过程块对应的块数据流图,包括:所述各个过程块以平铺的结构呈现在中间表示IR中,逐条解析IR语句,将每条IR的操作符和操作数填入对应的数据结构,生成所述各个过程块对应的块数据流图。

可选的,所述在代码块中存在父循环代码的情景下,分析所述代码块中子代码块之间的依赖信息之前,所述方法还包括;不同格式的代码块文件转换为所述中间表示IR格式文件。

本发明的第二个方面,提供了一种数据流图生成装置,所述装置包括:分析单元,用于在代码块中存在父循环代码的情景下,分析所述代码块中子代码块之间的依赖信息;第一生成单元,用于遍历所述代码块中各个过程块,生成所述各个过程块对应的块数据流图;第二生成单元,用于对所述各个过程块对应的数据流图添加所述依赖信息,生成所述代码块对应的代码数据流图;第三生成单元,用于消除所述代码数据流图中的重复变量,建立所述各个过程块之间的连接关系,生成第一数据流图图文件,以使通过所述第一数据流图图文件展示所述代码块的数据流图。

可选的,所述所述装置还包括;统计单元,用于消除所述代码数据流图中的重复变量,建立所述各个过程块之间的连接关系,得到数据流图图文件,以使通过所述第一数据流图图文件展示所述代码块的数据流图之后,统计所述代码块中各个过程块连接关系;简化单元,用于提取满足预设条件的过程块,并简化所述代码块中的过程块;获取单元,用于获取所述各个过程块之间的关联或嵌套关系;第四生成单元,用于补全所述各个过程块中的数据之间依赖距离,生成第二数据流图图文件,其中,所述依赖距离表示内存在所述代码块被多次访问,多次访问之间间隔的循环次数。

可选的,所述装置还包括:第五生成单元,用于所述补全所述各个过程块中的数据之间依赖距离,生成第二数据流图图文件之后,生成所述代码块加载信息。

可选的,所述依赖关系包括先后顺序和/或包含关系。

可选的,所述装置还包括:删除转换单元,用于所述获取所述各个过程块之间的关联或嵌套关系之后,将所述各个过程块中无用的过程块删除或转换为循环信息。

可选的,所述第一生成单元,包括:生成模块,用于所述各个过程块以平铺的结构呈现在中间表示IR中,逐条解析IR语句,将每条IR的操作符和操作数填入对应的数据结构,生成所述各个过程块对应的块数据流图。

可选的,所述装置还包括;转换单元,用于所述在代码块中存在父循环代码的情景下,分析所述代码块中子代码块之间的依赖信息之前,不同格式的代码块文件转换为所述中间表示IR格式文件。

下文将以明确易懂的方式,结合附图对一种数据流图生成方法及系统的特性、技术特征、优点及其实现方式予以进一步说明。

附图说明

图1是用于说明在本发明一种实施方式中的数据流图生成方法的流程示意图;

图2是用于说明在本发明一种实施方式中的数据流图总体流程图;

图3是用于说明在本发明另一种实施方式中的数据结构关系示意图;

图4是用于说明在本发明另一种实施方式中的for循环结构图(一);

图5是用于说明在本发明一种实施方式中的while循环结构图;

图6是用于说明在本发明另一种实施方式中的依赖距离计算示意图;

图7是用于说明在本发明另一种实施方式中的层级计算流程图;

图8是用于说明在本发明另一种实施方式中的简化后的for循环结构;

图9是用于说明在本发明另一种实施方式中的带分支的循环结构图;

图10是用于说明在本发明一种实施方式中的加载信息数据结构示意图;

图11是用于说明在本发明另一种实施方式中的dot图示例;

图12是用于说明在本发明另一种实施方式中的批量显示效果示意图;

图13是用于说明在本发明另一种实施方式中的数据流图生成装置的示意图。

具体实施方式

为了使本技术领域的人员更好地理解本发明方案,下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分的实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都应当属于本发明保护的范围。

需要说明的是,本发明的说明书和权利要求书及上述附图中的术语“第一”、“第二”等是用于区别类似的对象,而不必用于描述特定的顺序或先后次序。应该理解这样使用的数据在适当情况下可以互换,以便这里描述的本发明的实施例能够以除了在这里图示或描述的那些以外的顺序实施。此外,术语“包括”和“具有”以及他们的任何变形,意图在于覆盖不排他的包含,例如,包含了一序列步骤或单元的过程、方法、系统、产品或设备不必限于清楚地列出的那些步骤或单元,而是可包括没有清楚地列出的或对于这些过程、方法、产品或设备固有的其它步骤或单元。

数据流图(data flow graph 简称dfg)是描述软件系统中数据处理过程的一种有力的图形工具。 数据流图从数据传递和加工的角度出发, 刻画数据流从输入到输出的移动和变换过程。 由于它能够清晰地反映程序代码的执行过程, 所以它经常作为异构处理器的编译器的重要组成部分。

编译器的任务是需要将代码逻辑翻译成对应体系结构的指令,对于传统(顺序执行指令)的体系结构,编译器经过对代码进行词法分析、语法分析、语义分析后,生成中间表示(IR)就可以一一对应到其指令集上,翻译成指令后,运行时只要进行顺序加载和执行即可。但随着时代的发展,人们对处理器的性能、功耗要求越来越高,IR有时不能满足并行计算的体系结构的要求(因为不是顺序加载和执行),所以需要更宏观的逻辑表示方法,而数据流图恰好可以表现并行计算的情况。显然,数据流图的组成越面向体系结构越有利于翻译成机器指令。

本发明的一个方面提供了一种数据流图生成方法,如图1所示,数据流图生成方法其包括:

步骤S101,在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息。

步骤S103,遍历代码块中各个过程块,生成各个过程块对应的块数据流图。

步骤S105,对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图。

步骤S107,消除代码数据流图中的重复变量,简化过程块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。

在本实施例中,继承循环级别的流程runOnLoop(这样只有在代码中有循环的情况下才进入本流程),得到循环中的过程块名称和父循环。进行标准(已有)的循环范围分析、循环信息分析和依赖分析。然后将IR逐条解析并将信息记录到对应的数据结构(操作符和操作数)中,并建立这些数据结构之间的关联。之后将这些数据结构归属到当前的过程块中,就得到该块的数据流程图dfg结构。然后再根据之前的依赖分析,将依赖关系添加到对应的操作符之间(完善dfg)。当得到所有的过程块后,建立过程块之间的逻辑关联(先后顺序或包含关系),同时消除多块共有的(重复的)数据变量,形成整体的dfg。此时可以将dfg数据结构保存为原始dfg文件,以便与优化后的dfg比较、查错。

之后是对过程块的简化,去掉编译器不关心的部分,只留下循环体本身和必要的逻辑块。步骤包括简化访存计算;根据过程块的连接,推理关系(顺序或嵌套);将无用的过程块删除或转换为循环信息;补全依赖距离等信息;生成简化的dfg;最后生成数据加载信息。

通过本申请提供的实施例,在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息;遍历代码块中各个过程块,生成各个过程块对应的块数据流图;对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图;消除代码数据流图中的重复变量,简化代码块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。上述方法利用到llvm前端、中间表示(IR)及其已有的部分分析步骤。llvm是一个开源的编译器框架,方便用户针对自己处理器的体系结构添加编译步骤(pass)或修改编译流程。用于可重构编译器的前端,但不限于可重构编译器。

可选的,消除代码数据流图中的重复变量,建立各个过程块之间的连接关系,得到数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图之后,上述方法还可以包括:统计代码块中各个过程块连接关系;提取满足预设条件的过程块,并简化循环代码中的过程块;获取各个过程块之间的关联或嵌套关系;补全各个过程块中的数据之间依赖距离,生成第二数据流图图文件,其中,依赖距离表示内存中的数据在代码块被多次访问,多次访问之间间隔的循环次数。

可选的,补全各个过程块中的数据之间依赖距离,生成第二数据流图图文件之后,上述方法还可以包括:生成代码块加载信息。

在本实施例中,代码块加载信息包括但不限于包括需要加载的数据量、将要生成的数据量,需要用到的计算单元数量、该计算单元的计算顺序层级和是否有未知的类型的算子(见图10 Demand)。

可选的,依赖关系包括先后顺序和/或包含关系。

可选的,获取各个过程块之间的关联或嵌套关系之后,上述方法还可以包括:将各个过程块中无用的过程块删除或转换为循环信息。

在本实施例中,循环信息包括但不限于包括循环起始值、终止值、循环步长、循环方向、循环变量名、本循环的嵌套深度、本循环名、父循环名,子循环名和初始化列表<变量名:值>(见图10 Scalar)。

可选的,遍历代码块中各个过程块,生成各个过程块对应的块数据流图,包括:各个过程块以平铺的结构呈现在中间表示IR中,逐条解析IR语句,将每条IR的操作符和操作数填入对应的数据结构,生成各个过程块对应的块数据流图。

可选的,在代码块中存在父循环代码的情景下,分析代码块中子代码块之间的依赖信息之前,上述方法还可以包括;不同格式的代码块文件转换为中间表示IR格式文件。

作为一种可选的实施例,本申请还提供了一种面向循环代码加速的,为编译器自动生成数据流图方法。如图2所示,编译器自动生成数据流图方法的流程图。具体过程如下。

1、将C、C++代码用clang/clang++命令转换为.ll(中间表示IR)格式文件。

如clang xxx.c -emit-llvm -g -c -S -o xxx.ll -Xclang -disable-O0-optnone

其中xxx.c是要进行循环代码优化的C代码文件;xxx.ll是IR格式文件;其它是必要的编译选项。

2、继承循环级别的流程runOnLoop(这样只有在代码中有循环的情况下才进入本流程),得到循环中的过程块名称和父循环。进行标准(已有)的循环范围分析、循环信息分析和依赖分析。然后将IR逐条解析并将信息记录到对应的数据结构(操作符和操作数)中,并建立这些数据结构之间的关联。之后将这些数据结构归属到当前的过程块中,就得到该块的dfg结构。然后再根据之前的依赖分析,将依赖关系添加到对应的操作符之间(完善dfg)。当得到所有的过程块后,建立过程块之间的逻辑关联(先后顺序或包含关系),同时消除多块共有的(重复的)数据变量,形成整体的dfg。此时可以将dfg数据结构保存为原始dfg文件,以便与优化后的dfg比较、查错。

之后是对过程块的简化,去掉编译器不关心的部分,只留下循环体本身和必要的逻辑块。步骤包括简化访存计算;根据过程块的连接,推理关系(顺序或嵌套);将无用的过程块删除或转换为循环信息;补全依赖距离等信息;生成简化的dfg;最后生成数据加载信息。

在本实施例中,定义数据结构,包括操作符节点OpNode、数据节点VarNode、过程块ProcBlock、依赖信息DepInfo、分支信息BranchEdge等,如图3所示,数据结构关系示意图。

其中,其中Node是OpNode、Var Node和ProcBlock的基类,包含基本的名称、ID等信息。操作数VarNode包括数据的类型、大小,作为哪些操作符的输入或输出等信息;操作符OpNode包括输入、输出(操作数),计算层级、前项、后项分支和依赖关系信息;过程块ProcBlock包括块中包含的所有操作符、操作数,以及与其它过程块的关联信息(包括具体的操作符节点)。

在本实施例中,构建循环内的各块,将它们对应到ProcBlock上去。一个循环由多个块组成,也可以包括子循环。在llvm的loop pass 的runOnloop中,在有循环嵌套时,循环块是以先子后父的顺序出现的。如果有多个同级循环,则同级循环按顺序出现。复杂循环时,按深度优先遍历。一个 for循环包含4个部分, cond, body, inc和end。如下图,循环中可以有分支块(if.then, if.else)介于for.body和for.inc之间。

父循环出现时同时会带有之前出现过的子循环,所以为节省时间,只需分析一次最外层循环。如图4所示,for循环结构图(一)。

For(i=0; i<10;++i) //for.cond + for.inc

{

… //for_body 可以没有计算,只有跳转

For(j=0; j<20; j+=2) // for.cond1 + for.inc1

{

A[i][j] = …; // for.body1

}

… //for.end

}

while循环时没有inc模块,其他一样。

如图5所示, while循环结构图。所有的块(包括分支、标号)都是以平铺的结构呈现在IR中,块的转换用br指令实现,类似汇编风格。

在本实施例中,遍历每个循环块,即逐条解析IR语句,将每条IR的操作符和操作数填入对应的数据结构。IR的形式如下:

for.cond: ; preds = %for.inc,%entry

%0 = load i32, i32* %i, align 4

%cmp = icmp slt i32 %0, 10

br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond

%1 = load i32, i32* %i, align 4

%2 = load i32, i32* %i, align 4

%mul = mul nsw i32 %1, %2

%3 = load i32, i32* %i, align 4

其中for.cond、 for.body等冒号之前的表示循环块名;%开头的是变量名或块名;“=”后面紧接的是操作符;……由于llvm有保证变量名唯一的机制,不用担心歧义问题。这样很容易将IR对应到自定义的数据结构上去。

在本实施例中,为操作符添加依赖信息。

利用之前执行的llvm自带的依赖分析流程,我们可以得到内存访问依赖,这些依赖信息提示编译器,某个操作符(load、store等)操作的内存的读、写顺序不能打乱。该流程大部分很正确,但我后来发现计算依赖距离时会有错误。

依赖距离简单地说就是某个内存在循环中被多次访问,之间间隔的循环次数。

依赖信息在两个OpNode之间,表示这两个操作的先后顺序不能打乱,也不能并行。一定是被依赖的操作先执行,依赖的操作后执行。

例如

for(i=10; i<100; ++i)

{

a[i] = a[i-2];

}

a[i]会在两轮之后被再次访问。

但是寻址计算可能会很复杂,除了线性(四则)运算外,还可能有二维或多维运算。

假设不关心下标的具体计算,写成A[f(i)] = A[g(i)]的形式(多维的每次只关心其中一维),依赖什么时候出现就在于f(i)什么时候等于g(i)。其中i是循环自变量,f(i),g(i)是下标。自变量以循环上、下限[b,t]为定义域(离散)。假设f和g都单调,则f(i),g(i)有各自值域,且极值出现在自变量的边界。如[f(b), f(t)]和[g(b), g(t)](在二者都单调递增的情况下)。如图6所示,依赖距离计算示意图。

假设用[fmin,fmax]表示f的值域,gmin,gmax表示g的值域。显然,当

fmin

例如,在图6所示的情况下,首次出现依赖是当g(d) = f(b)时。其中d是依赖距离。

具体方法:

编写能够计算表达式的值的函数,用该函数计算寻址的值(用于以下计算)。

把下标表达式f、g的自变量i分别替换为上、下限b和t,得到fmin, fmax; gmin,gmax和f,g的单调性。

根据值域关系①判断依赖性和首次依赖值是f(b)还是f(t)。假设是f1.

用二分法计算得到距离。

例如先令d=(t-b)/2,得到g(d)的值,假设是g2。

If((g2>f1 && g递增) || (g2

g3=g(d/2)

else if ((g2>f1 && g递减) || (g2

g3=g(d*3/2)

else if (g2==f1)

return d;

可以进行递归计算。

在本实施例中,计算操作符层级,以便实现并行计算。由于并行计算希望同时得到所 有(或尽可能多)的中间结果,我们需要知道那些步骤需要同时执行。有了操作符层级,就可以获得该信息。例如:

x=a

我们希望将a、b、c 3个数各自的平方运算放在第1级,将t=a

操作符节点的层级计算的方法,如图7所示,层级计算流程图。

一个操作符节点,如果它没有输入或只有纯输入(及输入不来自于其它操作符的输出),将该节点层级赋为0值;如果它有的输入来自于上一层操作的输出,则递归计算上一层的层级后,加1作为本操作符节点层级。

在此过程中顺带计算了该操作符节点的上层节点的层级。但同时要考虑到上层节点是否与被计算节点在同一或包含它的过程块中,不是这种情况的就停止向上递归计算。

在本实施例中,简化单一过程块中节点的方法如下:

将有相同输入参数的同样的操作只保留一个。因为同样的变量会出现在多个块中,而我们希望一个变量只占一次内存,不应有重复分配内存。

删去sext(符号位扩展), zext(0类型扩展), bitcast(类型转换)等体系结构中不关心的操作。

删除debug相关指令。

利用表达式计算,将多维数组的多次load简化为一次(为了加载信息的提取)。例如在原始IR中存在getelementptr时表示寻址操作,它又3个参数,即变量起始地址,变量偏移地址和结构成员编译地址。例如

%tmp6 = getelementptr %struct.munger_struct* %P, i32 2, i32 1

表示struct.munger的第2号数组索引的第1号成员(号都从0开始)。有时数组索引和成员编号也是计算出来的值,因此还需要将计算展开。最后在图中表现为一个寻址表达式的形式,并记录在一个自定义的.pre文件中。例如:

ID: Datum618, detail: vla1[k.2*10*reg2][j.0*reg2][(i.0-1)]: pointerinteger, size: 4, addr: 16, writen: 0;

它的格式是ID: [id名],detail: 变量寻址表达式(包含计算),指针类型,数组中每个数据的长度,偏移地址,是否是输出。

释放因简化而消失的依赖。

推理、建立块与块之间的连接

一个 for循环包含4个部分, cond, body, inc和end。如下图,展示的是一个嵌套循环的结构。

如图4所示,for循环结构示意图。其中,cond有一个或多可phi(分支选项)节点,给一个或多个变量赋初值或增量(或累计值),然后有比较和由比较结果决定的分支跳转(br)。

inc有add和br。

body可以有运算,也可以只有一个br(跳到其它的循环)。如果有子循环的话,有以下几种情况:

1、只有子循环:父循环只有br,跳转到子循环cond。

2、子循环前有普通计算: 普通计算作为父循环的body的内容,然后br跳转到子循环。

3、子循环后有普通计算:父循环body只有br,跳转到子循环cond,子循环执行后跳到 for.end(属于子循环)执行子循环后的计算,之后执行父循环的for.inc。

4、父循环中有多个人子循环:父循环的body只有一个br跳转到第一个子循环的cond,在一个子循环结束后,跳转到下一个子循环的cond。如果两个循环之间有非循环,该非循环被认为是上一个子循环的for.end。执行顺序如3。

end可以有计算(非完美循环时),也可以没有。与body不同的是,end只执行一次,且在子循环的尾部执行,属于子循环。

在简化时,将cond和inc这种没有过多计算的简化为仅含附加信息加br的子图,将end部分的计算作为另一子图(如果有计算的话)。如图8所示,简化后的for循环结构。

其中,cond+inc被简化为循环信息的形式附加在body图中,而不再是图形连接。循环信息格式如下:

循环信息名称(同body名)、 循环变量名(如i)、循环起始值、循环结束值、循环增量值、增量方向(+、-)、本循环被嵌套深度、父循环名称。

while循环时没有inc模块,因此无需简化为循环信息。

当有if分支时,如图9所示,带分支的循环结构的全景图。

if_then或if_else与if_end之间的部分为嵌套,前后的为顺序。

需要做的改造:

1、除cond和inc的分支都保留。

2、cond、inc转化为br(原cond的跳转节点)。

3、将子循环的跳转形式转变为嵌套形式。

4、符号表也要加入end部分的变量。

在本实施例中,生成加载信息。生成dfg的目的除了生成可视化的图结构外,更重要的是将解析代码的信息尽可能多地传递给编译器的后端,使其实现更方便。故生成此加载信息。

如图10所示,加载信息数据结构图。其中FlowElems表示一个过程块的加载信息整体,和传统的进程结构相似,它包括3个段:未初始化数据段bss、初始化数据段data和代码段code(代码段内容留给后端编译器填写),每个段都包含起始地址和大小信息;symbols是符号表,由一系列SymbolInfo结构组成,每个是SymbolInfo表明一个变量的名称、偏移地址、长度、是否是输出等信息;demand表示该过程块需要占用的资源,包括操作符数量(PE_num),需要同时加载内存的bank数量load_num,需要同时存储内存的bank数量store_num,最大层级数levels和是否有为止操作符hasUnknownOp;Scalar表示循环信息,与之前介绍的对应,只不过还多了子循环名subLoop和初始值表initTable。

为了记录生成的图,以便后期人工检查或再次使用数据结构,将图转换为利用标准格式的.dot文件。有了前面的数据结构,生成.dot文件就是顺理成章的事。如图11所示,dot图示例图。

其中,dfg文件遵循dot格式标准。元素包括运算符、数据、块、循环信息以及它们之间的连接。

黑色矩形框表示数据,4个格中分别表示数据名称、类型、类型大小和数据个数。

椭圆代表运算符,里面包括运算符名称和优先级(用:分隔)。优先级是根据图的结构计算的,但目前没有考虑依赖关系。

一个运算符可能有输入和一个输出,它们通过边相连接,输出又可能成为另一个运算符的输入。通过这样的连接就自然形成了图。输入边有一个数字表示该输入数据作为该操作符的参数序号。

箭头线a的边表示内存依赖,指向被依赖指令(运算符)。内存依赖有3个被空格分隔的参数,第一个表示节点类型,可以是's'(SingleInstruction),'m'(MultiInstruction),'pi'(PiBlock),'r'(Root) and 'u'(unknown)。第2个参数表示约束类型,可以是'c'(confuse),'f'(flow),'o'(output),'a'(anti) and 'i'(input). 第个参数表示依赖距离,可以是一个数或一个向量,其中的每个数顺序地对应一维下标。

包含数据和操作的大框c和大框d表示块的边界。如循环、分支等。

连接不同块或运算符的箭头虚线b是为了让我们知道下一个要执行的是哪个(因为同级的块应该有顺序,有些运算符没有输入或输出)。嵌套的块根据父循环的循环信息中子循环的顺序执行。

循环条件和循环增量块被一组循环信息所取代。循环信息包括循环变量名,起始、终止、步长值,增量方向,该循环的深度和子循环名称。

在本实施例中,利用llvm的优化命令opt调用本发明的流程(pass),生成.dot(图描述)文件。

如opt -load dfg.so -scalar-evolution -dfg -analyze pathTo/xxx.ll

其中-load dfg.so是调用本流程的命令选项;-dfg是执行本流程的选项;pathTo/xxx.ll是之前生成IR文件的路径。

生成html文件(方便批量检查)。

在确认整个工程正确性时,需要大量的检查、校验工作,一个文件一个文件地对比耗费大量时间。故发明了此方法,方便批量检查。方法是将所有要检查的dot文件放在同一个路径下,遍历该路径下所有的.dot文件并用xdot工具将.dot文件转化成png或jpg可使文件。写一个生成html文件的脚本,脚本的每段包含一个要检查的记录,包含的信息包括文件名称、C/C++源码(链接)、IR代码(链接)、简化前的dfg图(png链接),简化后的dfg图(png格式)。如图12所示,批量显示效果示意图。

在本实施例中,可以将llvm的IR转换为自定义的dfg数据结构。将上述dfg数据结构的循环条件和循环结尾从图中去掉,转换为循环信息。将多步寻址计算简化为一步寻址操作。根据体系结构指令集和约束条件判断代码的可编译性。在已有的依赖分析流程基础上重新计算内存依赖距离。将自定义的dfg数据结构保存成.dot格式文件。将.dot文件转为图形文件并批量用浏览器显示,便于查错。

在本实施例中,利用llvm前端、中间表示(IR)其已有的部分分析流程,为编译器自动生成数据流图,其中,该编译器自动生成数据流图的流程生成以关系图为核心的数据结构,既可以人工查看,又可以为编译器后续的自动指令集映射(mapping)和数据部署(banking)提供指导,是可重构编译器中重要的组成部分。

其中,本实施例可以用于可重构编译器的前端,但不限于可重构编译器。任何需要并行执行指令的体系结构都可以使用。

通过以上的实施方式的描述,本领域的技术人员可以清楚地了解到根据上述实施例的方法可借助软件加必需的通用硬件平台的方式来实现,当然也可以通过硬件,但很多情况下前者是更佳的实施方式。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质(如ROM/RAM、磁碟、光盘)中,包括若干指令用以使得一台终端设备(可以是手机,计算机,服务器,或者网络设备等)执行本发明各个实施例所述的方法。

在本实施例中还提供了一种数据流图生成装置,该装置用于实现上述实施例及优选实施方式,已经进行过说明的不再赘述。如以下所使用的,术语“模块”可以实现预定功能的软件和/或硬件的组合。尽管以下实施例所描述的装置较佳地以软件来实现,但是硬件,或者软件和硬件的组合的实现也是可能并被构想的。

图13是根据本发明实施例的数据流图生成装置的结构框图,如图13所示,该数据流图生成装置包括:

分析单元1401,用于在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息。

第一生成单元1403,用于遍历代码块中各个过程块,生成各个过程块对应的块数据流图。

第二生成单元1405,用于对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图。

第三生成单元1407,用于消除代码数据流图中的重复变量,简化过程块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。

通过本申请提供的实施例,分析单元1401在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息;第一生成单元1403遍历代码块中各个过程块,生成各个过程块对应的块数据流图;第二生成单元1405对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图;第三生成单元1407消除代码数据流图中的重复变量,简化过程块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。上述方法利用到llvm前端、中间表示(IR)及其已有的部分分析步骤。llvm是一个开源的编译器框架,方便用户针对自己处理器的体系结构添加编译步骤(pass)或修改编译流程。用于可重构编译器的前端,但不限于可重构编译器。

可选的,上述装置还可以包括;统计单元,用于消除代码数据流图中的重复变量,建立各个过程块之间的连接关系,得到数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图之后,统计代码块中各个过程块连接关系;简化单元,用于提取满足预设条件的过程块,并简化代码块中的过程块;获取单元,用于获取各个过程块之间的关联或嵌套关系;第四生成单元,用于补全各个过程块中的数据之间依赖距离,生成第二数据流图图文件,其中,依赖距离表示内存中的数据在代码块被多次访问,多次访问之间间隔的循环次数。

可选的,上述装置还可以包括:第五生成单元,用于补全各个过程块中的数据之间依赖距离,生成第二数据流图图文件之后,生成代码块加载信息。

可选的,依赖关系包括先后顺序和/或包含关系。

可选的,上述装置还可以包括:删除转换单元,用于获取各个过程块之间的关联或嵌套关系之后,将各个过程块中无用的过程块删除或转换为循环信息。

可选的,上述第一生成单元1403,可以包括:生成模块,用于各个过程块以平铺的结构呈现在中间表示IR中,逐条解析IR语句,将每条IR的操作符和操作数填入对应的数据结构,生成各个过程块对应的块数据流图。

可选的,上述装置还可以包括;转换单元,用于在代码块中存在父循环代码的情景下,分析代码块中子代码块之间的依赖信息之前,不同格式的代码块文件转换为中间表示IR格式文件。

需要说明的是,上述各个模块是可以通过软件或硬件来实现的,对于后者,可以通过以下方式实现,但不限于此:上述模块均位于同一处理器中;或者,上述各个模块以任意组合的形式分别位于不同的处理器中。

本发明的实施例还提供了一种存储介质,该存储介质中存储有计算机程序,其中,该计算机程序被设置为运行时执行上述任一项方法实施例中的步骤。

可选地,在本实施例中,上述存储介质可以被设置为存储用于执行以下步骤的计算机程序:

S1,在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息;

S2,遍历代码块中各个过程块,生成各个过程块对应的块数据流图;

S3,对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图;

S4,消除代码数据流图中的重复变量,简化过程块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。

可选地,在本实施例中,上述存储介质可以包括但不限于:U盘、只读存储器(Read-Only Memory,简称为ROM)、随机存取存储器(Random Access Memory,简称为RAM)、移动硬盘、磁碟或者光盘等各种可以存储计算机程序的介质。

本发明的实施例还提供了一种电子装置,包括存储器和处理器,该存储器中存储有计算机程序,该处理器被设置为运行计算机程序以执行上述任一项方法实施例中的步骤。

可选地,上述电子装置还可以包括传输设备以及输入输出设备,其中,该传输设备和上述处理器连接,该输入输出设备和上述处理器连接。

可选地,在本实施例中,上述处理器可以被设置为通过计算机程序执行以下步骤:

S1,在代码块中存在父循环代码的情景下,分析代码块中数据的依赖信息;

S2,遍历代码块中各个过程块,生成各个过程块对应的块数据流图;

S3,对各个过程块对应的数据流图分析并添加依赖信息,生成代码块对应的代码数据流图;

S4,消除代码数据流图中的重复变量,简化过程块并建立各个过程块之间的连接关系,生成第一数据流图图文件,以使通过第一数据流图图文件展示代码块的数据流图。

可选地,本实施例中的具体示例可以参考上述实施例及可选实施方式中所描述的示例,本实施例在此不再赘述。

显然,本领域的技术人员应该明白,上述的本发明的各模块或各步骤可以用通用的计算装置来实现,它们可以集中在单个的计算装置上,或者分布在多个计算装置所组成的网络上,可选地,它们可以用计算装置可执行的程序代码来实现,从而,可以将它们存储在存储装置中由计算装置来执行,并且在某些情况下,可以以不同于此处的顺序执行所示出或描述的步骤,或者将它们分别制作成各个集成电路模块,或者将它们中的多个模块或步骤制作成单个集成电路模块来实现。这样,本发明不限制于任何特定的硬件和软件结合。

以上所述仅为本发明的优选实施例而已,并不用于限制本发明,对于本领域的技术人员来说,本发明可以有各种更改和变化。凡在本发明的原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。

技术分类

06120114707814