CN103119561A - 用于对非叶代码进行基于编译器的矢量化的***和方法 - Google Patents
用于对非叶代码进行基于编译器的矢量化的***和方法 Download PDFInfo
- Publication number
- CN103119561A CN103119561A CN2011800455834A CN201180045583A CN103119561A CN 103119561 A CN103119561 A CN 103119561A CN 2011800455834 A CN2011800455834 A CN 2011800455834A CN 201180045583 A CN201180045583 A CN 201180045583A CN 103119561 A CN103119561 A CN 103119561A
- Authority
- CN
- China
- Prior art keywords
- function
- dependence
- vector
- compiler
- called
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/40—Transformation of program code
- G06F8/41—Compilation
- G06F8/43—Checking; Contextual analysis
- G06F8/433—Dependency analysis; Data or control flow analysis
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/40—Transformation of program code
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/40—Transformation of program code
- G06F8/41—Compilation
- G06F8/45—Exploiting coarse grain parallelism in compilation, i.e. parallelism between groups of instructions
- G06F8/456—Parallelism detection
Landscapes
- Engineering & Computer Science (AREA)
- General Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- Software Systems (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- Devices For Executing Special Programs (AREA)
Abstract
本发明描述了用于软件应用的矢量化的***和方法。在一些实施例中,源代码依赖关系可以按可以扩展编译器的能力以矢量化否则为标量的函数的方式来表达。例如,当编译被调用函数时,编译器可以识别被调用函数与除了传递至该被调用函数的参数以外的其它变量的依赖关系。该编译器可以记录这些依赖关系,例如,记录在依赖关系文件中。稍后,当编译调用该被调用函数的调用函数时,同一(或另一)编译器可以引用先前识别的依赖关系,并将它们用于确定是否和怎样矢量化调用函数。具体来说,这些技术可以辅助非叶循环的矢量化。因为非叶循环相对常见,所以在此描述的技术可以增加可以被应用至许多应用的矢量化的量。
Description
技术领域
本公开涉及计算机***,并且更具体地说,涉及用于使能软件应用的通用矢量化的***和方法。
背景技术
典型软件开发范例是公知的。计算机程序员采用高级编程语言(例如,Basic、C++等)来编写源代码。在某一点处,程序员使用编译器将源代码变换成目标代码。在变换成可执行代码之后(例如,在链接或其它编译时间或运行时间处理之后),接着,所得目标代码可以通过计算机或计算装置来执行。
计算机如今具有多个处理单元,并且能够并行地执行指令。利用这种架构的优点,现代编译器可以尝试“并行化”或“矢量化”特定软件功能,从而代替使单一处理单元顺序地一次执行一个指令,多个处理单元可以同时执行多个指令。
在编译处理期间,编译器分析软件功能以确定是否存在针对矢量化的任何障碍。一个这种障碍例如是存在真实数据依赖关系(dependency)。这在当前指令引用通过执行在前指令所获取的数据时发生。在该情况下,较后指令仅可以在较早指令之后执行,并由此两个指令不能并行执行。另一潜在障碍是存在函数调用。例如,如果要编译的函数对外部函数进行调用,则编译器不能够矢量化该调用函数。
发明内容
本公开提供了用于使能通用矢量化软件应用的***和方法。为此,在此公开的***和方法提供对扩展编译器的能力以矢量化函数的依赖关系和/或接口的表达。
在一非限制实施例中,编译器可以在其编译期间检查存储器和/或一函数(“被调用函数”)内的数据依赖关系,并且在依赖关系数据库(举例来说,如依赖关系文件)中表达那些依赖关系。一旦编译,被调用函数就可以例如变为库函数等。在稍后的时间点,可以创建另一函数(“调用函数”),以使其针对被调用函数进行调用。在编译调用函数期间,编译器可以访问与被调用函数相关联的依赖关系文件,并且可以识别其依赖关系。基于被调用函数的依赖关系,编译器可以进行有关是否矢量化调用函数的判定。
另外或另选的是,编译器可以判定仅矢量化调用函数的一部分。与其它可能方式相比,通过使用依赖关系文件而提供的可见性可以允许编译器矢量化更高百分比的函数。
例如,实现依赖关系文件允许矢量化包括非叶循环(non-leafloop)(即,对源代码不可见的外部函数进行调用的循环)的函数。因为现今大多数软件函数包括一个或多个非叶循环,所以这些***和方法可以增加可以被应用至任何应用的矢量化的量。
在另一非限制实施例中,编译器可以根据单一源代码描述生成函数的标量和矢量形式。函数的标量形式可以使用如由源代码最初指定的标量接口。同时,函数的矢量形式可以实现针对该函数的、用于接收矢量参数和生成矢量返回值的矢量接口。
例如,矢量接口可以在与函数相关联的依赖关系文件中暴露。这种另选矢量接口的存在例如允许编译器从矢量化循环内进行矢量函数调用,而非从矢量化循环内进行多个串行化标量函数调用。
在此公开的技术的各种组合还准许函数的矢量化不包含循环,其与公认知识相反,并且仍提供许多优点。特别地讲,这些技术可以增加软件应用中的总矢量化的量。
附图说明
图1是例示根据某些实施例的、可操作以实现用于使能实现软件应用的通用矢量化的技术的计算机***的框图。
图2是例示根据某些实施例的、在通过计算机***执行时可以生成可执行代码的编译器的框图。
图3示出了例示根据某些实施例的、表达依赖关系数据库中的依赖关系的方法的流程图。
图4示出了例示根据某些实施例的、矢量化函数的方法的流程图。
图5示出了例示根据某些实施例的、全函数矢量化方法的流程图。
图6示出了例示根据某些实施例的、利用所矢量化函数的方法的流程图。
虽然易受各种修改和另选形式,但在本说明书中讨论的具体实施例在附图中通过示例进行了示出,并且在此将进行详细描述。然而,应当明白,附图和详细描述不是旨在将本公开限制成所公开的特定形式,但与此相反,本发明要覆盖落入如所附权利要求书所限定的本公开的精神和范围内的所有修改例、等同物以及另选例。
具体实施方式
介绍
下面的说明书首先讨论例示计算机***或装置。本说明书还描述了例示编译器,其可以被配置成执行和/或生成用于计算机***的可执行代码。接着,本说明书提出了用于使能实现非叶循环和全函数矢量化的几种技术。
例示性计算机***
图1描绘了根据某些实施例的、可操作以实现用于使能实现软件应用的通用矢量化的技术的例示计算机***。在该非限制例中,计算机***100包括经由I/O接口130耦接至存储器120的一个或多个处理器110a-110n。计算机***100还包括耦接至I/O接口130的网络接口140和存储接口150。存储接口150将外部存储装置155连接至I/O接口130。而且,网络接口140可以将***100连接至网络(未示出)或者连接至另一计算机***(未示出)。
在一些实施例中,计算机***100可以是仅包括一个处理器110a的单一处理器***。在其它实施例中,计算机***100可以包括两个或更多个处理器110a-110n。处理器110a-110n可以包括能够执行指令的任何处理器。例如,处理器110a-110n可以是实现任何合适指令集架构(ISA)的通用或嵌入式处理器,举例来说,如x86、PowerPCTM、SPARCTM、或MIPSTMI SAs。在一实施例中,处理器110a-110n可以包括在美国专利No.7617496和美国专利No.7395419中描述的Macroscalar处理器的各种特征。
***存储器120可以被配置成存储可通过处理器110a-110n访问的指令和数据。例如,***存储器120可以是静态随机访问存储器(SRAM)、同步动态RAM(SDRAM)、非易失性/闪速型存储器、或者任何其它任何合适类型的存储器技术。实现下面详细描述的希望功能或应用的程序指令和/或数据的一部分可以被示出存储在***存储器120内。另外或另选的是,那些程序指令和/或数据的一部分可以被存储在存储装置155、一个或多个处理器110a-110n内的高速缓冲存储器中、或者可以经由网络接口140从网络抵达。
I/O接口130可操作以管理处理器110a-110n、***存储器120以及该***中的或接合至其的任何装置(包括网络接口140、存储接口150或其它***接口)之间的数据通信。例如,I/O接口130可以将来自一个组件的数据或控制信号转换成适于供另一组件使用的格式。在一些实施例中,I/O接口130可以包括对通过各种类型***总线接合的装置的支持,举例来说,如***组件互连(PCI)总线或通用串行总线(USB)。而且,在一些实施例中,I/O接口130的一些或全部功能可以并入处理器110a-110n。
网络接口140被配置成允许数据在计算机***100与接合至网络的其它装置(举例来说,如其它计算机***)之间交换。例如,网络接口140可以支持经由有线或无线通用数据网络、电信/电话网络、诸如Fibre Channel SAN等的存储区域网络等的通信。
存储接口150被配置成允许计算机***100与诸如存储装置155的存储装置接口连接。存储接口150可以支持以下标准存储接口:如高级技术附加数据包接口(ATAPI)标准(其还可以被称为集成驱动电子设备(IDE))的一个或多个合适版本、小型计算机***接口(SCSI)标准、IEEE 1394“Firewire”标准、USB标准、或者适于互连海量存储装置与计算机***100的另一标准或专有接口。例如,存储装置155可以包括可以固定或可去除的磁性、光学或固态介质。存储装置155还可以对应于硬盘驱动器或驱动器阵列、CD或DVD驱动器、或者基于非易失性存储器(例如,闪速存储器)的装置。
***存储器120和存储装置155表示被配置成存储程序指令和数据的计算机可访问或计算机可读存储介质的例示性实施例。在其它实施例中,程序指令和/或数据可以在不同类型的计算机可访问介质上接收、发送或存储。一般来说,计算机可访问介质或存储介质可以包括任何类型的海量存储介质或存储器介质,如磁性介质或光学介质。计算机可访问介质或存储介质还可以包括任何易失性或非易失性介质,如RAM(例如,SDRAM、DDR SDRAM、RDRAM、SRAM等)、ROM等,无论作为***存储器120还是另一类型存储器包括在计算机***100中。经由计算机可访问介质存储的程序指令和数据可以通过传输介质或诸如电信号、电磁信号或数字信号的信号传输,其可以经由诸如网络和/或无线链路的通信介质来输送,如可以经由网络接口140实现。
典型地讲,计算机***100可以采取台式或膝上型计算机的形式。然而,如根据本公开将容易理解,计算机***100可以是能够执行软件的任何合适装置。例如,计算机***100可以是平板计算机、电话等。
例示性编译器
一般而言,编译器可以对应于被配置成将源代码翻译或变换成目标代码的软件应用(例如,计算机可执行指令中的一个或多个模块),该源代码可以采用诸如C、C++或任何其它合适编程语言的高级编程语言来表示。表达源代码的语言可以被称为源代码语言或简称为源语言。典型地讲,目标代码可以采用适于供目标计算架构处理的指令和数据的形式来表示,尽管在一些实施例中,可以针对所生成的目标代码执行附加处理((例如,链接),以将目标代码变换成机器可执行代码。在各种实施例中,这种附加处理可以通过编译器或者通过分离应用来执行。
目标代码可以采用机器可读形式(例如,二进制形式)、采用可需要附加处理以生成机器可读代码的人可读形式(例如,汇编语言),或者采用人可读形式和机器可读形式的组合来表示。针对目标代码的目标架构可以和通过处理器110a-11n所实现的、其上编译器被配置成执行的ISA相同。然而,在某些情况下,编译器可以被配置成生成针对其上编译器执行(“交叉编译器”)的ISA相比不同的ISA的目标代码。
图2描绘了根据某些实施例的、在通过计算机***100或另一合适计算机***执行时可以生成可执行代码的例示性编译器。编译器200包括前端220和后端230,其又可以包括优化器240和代码生成器250。如上所示,前端220接收源代码210,而后端230生成目标代码,举例来说,如标量目标代码260、矢量化目标代码270或其组合。编译器200还可以生成与目标代码260和/或270中的一个或多个相关联的依赖关系数据库280。
虽然源代码210通常采用高级编程语言编写,但源代码210可以另选地对应于诸如汇编语言的机器级语言。例如,编译器200可以被配置成应用其最优化技术,以汇编除了采用高级编程语言编写的代码以外的语言代码。而且,编译器200可以包括前端220的许多不同实例,其皆被配置成处理采用不同相应语言编写的源代码210,并且生成供后端230处理的类似中间表示。在这种实施例中,编译器200可以有效地充任多语言编译器。
在一实施例中,前端220可以被配置成执行源代码210的初步处理,以确定源在词汇上和/或语法上是否正确,并且执行适于准备源代码210以供后端230进一步处理的任何变换。例如,前端220可以被配置成处理存在于源代码210内的任何编译器指令,如可以导致源代码210的某些部分被包括在编译处理中而其它部分不包括在其中的条件编译指令。前端220还可以不同地被配置成将源代码210转换成记号(tokens)(例如,根据由源语言定义的空白和/或其它分隔符),确定源代码210是否包括禁止为源语言的任何字符或记号,以及确定所得记号流是否服从按源语言定义的合式表达的语法规则。在不同情形下,前端220可以被配置成执行这些处理活动的不同组合,可以省略上述特定动作,或者可以包括不同动作,根据前端220的实现和前端220的目标源语言,例如,如果源语言未提供用于定义编译器指令的语法,则前端220可以省略包括扫描用于编译器指令的源代码210的处理动作。
如果前端220在处理源代码210期间遭遇错误,则其可以异常中止处理并且报告错误(例如,通过将错误信息写入至日志文件或者显示器)。否则,在充分分析源代码210的语法和语义内容时,前端220可以向后端230提供源代码210的中间表示。一般而言,该中间表示可以包括表示源代码210的结构和语义内容的一个或多个数据结构,如语法树、图表、符号表或其它合适数据结构。该中间表示可以被配置成保存识别源代码210的语法和语义特征的信息,并且还可以包括通过剖析和分析源代码210而生成的附加注释信息。例如,该中间表示可以包括明确地识别源代码210的不同块或段之间的控制关系的控制流程图。这种控制流程信息可以被后端230采用,以例如确定,可以怎样重新布置(例如,通过优化器240)源代码210的功能部分,以在保存源代码210内的必需执行顺序关系的同时改进性能。
后端230通常可以被配置成将中间表示变换成标量代码260、矢量化代码270、或两者的组合中的一个或多个。具体来说,在所示实施例中,优化器240可以被配置成试图变换中间表示,以改进所得标量代码260或矢量化代码270的某一方面。例如,优化器240可以被配置成分析中间表示以识别存储器或数据依赖关系。在一些实施例中,优化器240可以被配置成执行各种其它类型的代码优化,如,矢量化、循环优化(例如,循环融合、循环展开等)、数据流优化(例如,共同子表达式消除、常量折叠等),或任何其它合适的优化技术。优化器240还可以被配置成生成依赖关系数据库280。如下更详细描述的,依赖关系数据库280可以表达对存储器和/或源代码210内的数据依赖关系的指示。另外或另选的是,连同源代码210的矢量化,依赖关系数据库280可以暴露与矢量化目标代码270相关联的矢量接口。
代码生成器250可以被配置成处理如通过优化器206变换的中间表示,以便生成标量代码260、矢量化代码270、或者两类代码的组合。例如,代码生成器250可以被配置成生成由目标架构的ISA定义的矢量化机器指令,以使得由实现目标架构的处理器(例如,处理器110a-110n之一,或者不同处理器)执行所生成指令可以实现由源代码210指定的功能行为。在一实施例中,代码生成器250还可以被配置成生成与可能不是源代码210中所固有的操作相对应的指令,但其在优化处理期间可以由优化器240添加。
在其它实施例中,编译器200可以被分区成与所示那些组件相比更多、更少或不同的组件。例如,编译器200可以包括链接器(未示出),其被配置成采取一个或多个目标文件或库作为输入,并且组合它们以生成单一(通常可执行的)文件。另选的是,该链接器可以是与编译器200分离的实体。如上所述,编译器200的组件中的任一个,以及所执行的由此包括下面参照图3-6描述的那些的方法或技术中的任一种,可以部分地或者整体地被实现为存储在合适计算机可访问存储介质内的软件代码。
源代码210例如可以表示软件功能或算法。所得目标代码260和/或270例如可以是可以被其它函数调用的库或外部函数。下面,对在操作期间(并且具体地说,在其矢量化操作期间)由编译器200采用的例示性技术进行更详细讨论。
非叶循环的矢量化
许多现代计算机具有通过并发地执行两个或更多个不同操作来执行计算工作量的某一类型并行处理的能力。例如,超标量处理器可以允许计算机尝试一次执行多个独立指令。通称为“矢量计算”(其可以被视为并行计算的特定情况)的另一技术允许计算机尝试执行一次对多个数据项操作的单一指令。矢量计算的各种示例可以在该单一指令、现今在各种处理器中可用的多个数据(SIMD)指令集中找到,例如,包括用于PowerPCTM处理器的IBM的AltiVecTM和SPETM指令集扩展,和Intel的MMXTM和SSETM指令集扩展的变型。这种SIMD指令是可以被矢量化编译器作为目标的矢量指令的示例,尽管其它类型的矢量指令或运算(包括可变长度矢量运算、预测(predicated)矢量运算、对矢量和标量/立即(immediates)的组合操作的矢量运算)也是可能并且可以设想的。
一般而言,将源代码变换成矢量化目标代码的处理可以被称为“矢量化”。当利用编译器执行时(例如,与手工矢量化源代码相反),可以将矢量化称为“编译器自动矢量化”。自动矢量化的一个特定类型是循环自动矢量化。循环自动矢量化可以将在多个数据项上迭代的过程循环转换成能够在分离处理单元(例如,图1中的计算机***100的处理器110a-110n,或者处理器内的分离功能单元)内并发地处理多个数据项的代码。例如,为将两个数字阵列A[]和B[]相加在一起,过程循环可以通过这些阵列迭代,在每一个迭代期间将一对阵列组元相加。当编译这种循环时,矢量化编译器可以利用目标处理器实现能够并发地处理数量固定或可变的矢量组元的矢量运算的事实。例如,编译器可以自动矢量化阵列相加循环,以使得在每一个迭代,并发地相加阵列A[]和B[]的多个组元,缩减为完成该相加所需的迭代数。典型程序在这种循环内花费其显著量的执行时间。这样,自动矢量化循环可以产生性能改进而不需要程序员干涉。
在一些实施例中,编译器自动矢量化受限于叶循环,即,不对其它函数进行调用的循环。非叶循环的矢量化(即,对其它函数进行调用的那些)因外部函数调用的副作用通常不清楚(opaque)而通常非常困难,尤其是在它们的源代码不可用于过程间分析时候,举例来说,如利用库的情况。出于例示的目的,考虑下面的循环:
为矢量化该循环,编译器200可以确定函数foo()是否与阵列A[]交互(例如,读取或写入)。这里,存在三种可能性:(1)函数foo()与A[]不交互;(2)函数foo()与A[]不交互;或者(3)函数foo()可能与A[]交互(例如,根据编译时间或运行时间条件,foo()可以与A[]交互或者可以不交互)。其中函数foo()可能与A[]交互的情况存在和其中函数foo()事实上的确与A[]交互的情况相似的问题。在foo()与A[]不交互的情况下,那么下面的可矢量化代码等效于上面的循环:
该示例示出了,在矢量化非叶循环的处理中,编译器200受益于获知函数所访问的存储器和/或该存储器是否被读取和/或写入。因为主要循环通常包含它们之内的函数调用,所以非叶循环和由它们调用的函数的矢量化被优选用于高程度的矢量化。为使能实现该级别的矢量化,在此描述的技术和***的各种实施例增加了跨先前已经编译的库和模块的依赖关系和潜在依赖关系的编译时间可见性。例如,该信息在编译调用函数时可以是可用的,与初始地编译该库或模块的时间(或位置)无关。因此,在此描述的某些技术建立例示性编译器基础结构,以创建该可见性并探索通过其使能实现的矢量化的类型。
依赖关系数据库
当编译调用外部函数的代码时,可以希望的是,确定外部函数的接口(例如,外部函数采取的参数的数量和/或类型,和/或其返回的结果的数量和/或类型)。例如,这种接口信息可以在确定调用代码是否已经正确地实现该外部函数时有用。外部可调用函数通常可以在首部文件中暴露它们的接口定义。然而,这种首部文件可以不暴露不是外部函数的用于调用函数的接口的一部分的变量的细节,但其仍然可以影响代码矢量化。例如,在上面例示的循环中,for循环的矢量化可以取决于函数foo()与阵列A[]怎样交互。然而,因为foo()不采取A[]作为一参数,所以与foo()相对应的首部文件可能不足以指示针对编译器200的这种依赖关系。
在此还可以被称为“永久依赖关系数据库”的依赖关系数据库可以在库中描述外部可调用函数的依赖关系。即,依赖关系数据库可以向调用函数暴露单独从被调用函数的接口不一定明显的被调用函数的各种依赖关系。该数据库在编译调用库的函数时可以被访问。一般而言,依赖关系数据库可以永久地存储对可调用代码的依赖关系的指示,以使依赖关系跨编译器调用可见。例如,在一些实施例中,依赖关系数据库可以被实现为包括指示各种依赖关系的人可读和/或机器可读内容的依赖关系文件(与首部文件类似)。在其它实施例中,依赖关系数据库可以利用其它技术来实现,如利用基于表的关系数据库、半结构化数据(例如,利用可扩展标记语言(XML)格式化),或者任何其它合适的技术。为简化说明,下面的讨论引用采用依赖关系文件的实施例。然而,应注意到,这仅是依赖关系数据库的一非限制例。
在一实施例中,编译器200在包含对应首部文件(例如,stdlib.h)时自动访问依赖关系文件(若存在的话)。这种机制可以允许矢量化编译器,举例来说,如用于在具有获知外部库的依赖关系的优点的同时编译现有代码而不需要修改的Macroscalar编译器。接着,编译器200可以在编译库时自动地生成依赖关系文件。
包含在依赖关系文件中的信息可以形成应用编译器接口(ACI),其提供编译器200可以用于理解函数的约束条件的信息。具体来说,依赖关系文件可以表达有关通常不在调用函数的范围内的变量的信息。例如,依赖关系文件中表达的变量可以包括不是被调用函数的参数的数据项(即,这种变量可能不由被调用函数的编程接口定义为该被调用函数的参数)。通过使用依赖关系文件,调用函数例如可以变为获知被调用函数是读取还是写入函数静态或文件静态变量。依赖关系文件还可以允许编译器200在共享同一名称但具有不同范围的变量之间区分。
作为一非限制例,当编译库stdlib时,编译器通常仅生成目标文件stdlib.o。利用在此描述的技术,编译器200还可以例如在编译时间生成依赖关系文件stdlib.d。依赖关系文件stdlib.d暴露与stdlib.h中定义的公用函数相关联的存储器依赖关系。包括来自其源代码的stdlib.h的其它程序可以触发编译器200搜索对应位置中的关联的依赖关系文件stdlib.d。该依赖关系文件可以与stdlib.h和stdlib.o一起分布和安装。在一个实现中,不存在依赖关系文件将意指,没有可用的有关库的附加信息,其可能是针对传统库的默认状态,并且不会导致任何编译错误。
依赖关系数据库可以使能通过按在编译调用库函数的代码时可见于编译器200的方式暴露先前编译的库函数(或程序中的任何函数)的数据依赖关系特征来矢量化非叶循环。该信息可以被使得在不需要展现针对该库的源代码的情况下可用。
在一些实施例中,依赖关系信息可以按库的编译时间生成。例如,针对编译的每一个函数,编译器200可以注释针对传递到被编译函数中的函数静态变量、文件静态变量、全局变量、以及/或指针的访问类型。接着,编译器200可以记录哪些符号被读取或写入,并且采用可以按引用库的其它代码的编译时间访问和使用依赖关系文件的形式来输出该信息。
作为另一非限制例,如果函数foo()在文件foo.c中定义,并且其接口在首部文件foo.h中定义,则在foo.c的编译时间,函数foo()的存储器依赖关系特征可以被存储到依赖关系文件foo.hd中(应注意到,可以采用用于依赖关系文件的任何合适命名约定)。使用函数foo()的调用函数可以包括首部文件foo.h,但可以不必访问文件foo.c。在在编译调用函数期间引用foo.h时,编译器200可以自动地搜索依赖关系文件foo.hd,以查看其是否存在。因为依赖关系文件foo.hd的存在性是可选的,所以缺乏这种文件可以暗示在文件foo.h中定义的函数的依赖关系特征未知,由此建议编译器200在矢量化调用函数时应当进行不利假定。然而,如果依赖关系文件存在,则编译器200可以使用该文件中的依赖关系信息,以在矢量化调用函数期间,利用包含在其中的依赖关系特征来进行更准确且主动的假定。
参照图3,根据某些实施例,对表示表达依赖关系文件中的依赖关系的方法的流程图进行描绘。在框300中,编译器200接收要编译的函数。例如,编译器200可以在处理用于编译的源代码时(如在编译包括该函数的库期间)接收函数。在框310中,编译器200分析该函数并且识别该函数内的所表达的依赖关系。该所表达的依赖关系例如可以是存储器或者与不是被调用函数的参数的数据项相关联的数据依赖关系。更一般地说,与函数对特定数据项的所表达的依赖关系可以指示该函数是仅读取该特定数据项,仅写入该特定数据项,还是既读取又写入该特定数据项。在各种实施例中,分析函数可以包括诸如执行对函数的词汇、语法、以及/或语义分析的动作。分析还可以包括生成指示被编译代码的操作和/或数据引用的某一方面的剖析树、符号表、中间代码表示、以及/或任何其它合适数据结构或表示。
在框320中,编译器200将对所表达依赖关系的指示存储在与该函数相关联的依赖关系数据库中。例如,在分析该函数期间,编译器200可以识别被该函数使用的、对于该函数来说不必是本地或专用的、并由此能够被该函数外部的代码读取或写入的变量。这种变量可以是编译器200可能识别的所表达的依赖关系的示例,并且编译器200可以将对这些变量的指示存储在依赖关系数据库内(应注意到,在一些实施例中,编译器200还可以识别和指示对于该函数来说是本地或专用的依赖关系)。在各种实施例中,对所表达的依赖关系的指示可以包括识别所表达的依赖关系的信息,如变量所依赖的名称。该指示还可以包括特征化所表达的依赖关系的信息,如有关函数是读取还是写入变量的信息,以及/或有关变量的数据类型或范围的信息(例如,该变量是否为全局的、专用的、静态的等)。如根据本公开将容易明白,依赖关系文件可以按任何合适格式(举例来说,如可扩展标记语言(XML)等)来创建或更新。而且,在一些实施例中,依赖关系可以代替肯定方式按否定方式来指示,或者除了肯定方式以外按否定方式来指示。例如,依赖关系文件可以明确地指示,除了或代替指示不存在的那些所表达的依赖关系,给定变量不取决于外部代码。
例如,考虑下面的示例,在要编译func1.c的情况下:
在这种情况下,func1.c对下面所示的外部函数foo1.c进行调用:
仅出于例示性目的,再现针对被调用函数foo1.c的源代码。应当明白,只要存在用于foo1.c的依赖关系数据库(在这个示例中,依赖关系文件),其源代码在编译调用函数func1.c期间就不需要可用。在这个示例中,存储在依赖关系文件foo1.hd中的所表达的依赖关系信息(其已经在编译文件foo1.c时的时刻生成)可以表达函数静态变量“e”被读取和写入的事实。这样,下面示出了对应依赖关系文件的一个非限制例:
在文件func1.c的编译时间,包含首部文件foo1.h可以导致依赖关系文件foo1.hd被编译器200读取。该信息向编译器通知被调用函数foo1()的所表达的依赖关系:即,该静态变量“e”被读取和写入。这还允许编译器200检测,即使它们在调用函数func1()中使用,全局变量“A”和“F”也不被被调用函数foo1()引用。这种获知允许编译器200矢量化函数func1()中的循环,因为其可以确定并行操作不会导致不正确操作。在这种情况下,func1()中的循环将针对被处理矢量中的每一个组元调用foo1()一次。
如果函数foo1()被写入全局“A”,则编译器200可能不矢量化func1()中的循环,或者其可以使用该信息以仅矢量化该函数的一部分。在这种情况下,编译器例如可以串行化针对函数foo1()的调用并且存储器引用至“A”,同时允许该循环的其余部分按并行方式执行。
参照图4,描绘了表示矢量化函数的方法的一实施例的流程图。在框400中,编译器200识别调用函数。在一非限制实施例中,调用函数可以包括非叶循环,在该情况下,调用函数可以包括针对外部或被调用函数的调用。参照刚才给出的代码例,编译器200可以处理func1.c源代码,并且识别func1()函数作为包括调用foo1()函数的非叶for循环的调用函数。
在框410中,编译器200可以尝试访问与被调用函数相关联的依赖关系数据库。在某些情况下,依赖关系数据库(例如,依赖关系文件)例如可以经由命令行参数、嵌入源代码内的编译器指令、或者经由另一合适技术,明确地指示给编译器200。在其它情况下,编译器200可以根据命名约定,尝试从其它数据推断依赖关系文件的名称。例如,如果首部文件被包括在源代码中,则编译器200可以搜索从首部文件的名称导出的依赖关系文件。在一些实施例中,编译器200可以基于被调用函数的名称来搜索依赖关系文件。
如果依赖关系数据库存在,则其可以指示被调用函数内的所表达的依赖关系。该所表达的依赖关系例如可以是与不是被调用函数的参数的数据项相关联的存储器或数据依赖关系,如上所述。在某些情况下,编译器200可以检查许多不同命名约定以确定是否存在依赖关系文件。
在框420中,接着,编译器200至少部分地基于所表达的依赖关系(或者缺乏依赖关系),确定调用函数是否与被调用函数交互。例如,在访问与函数foo1()相关联的依赖关系文件时,编译器200可以确定foo1()取决于变量“e”而非变量“A”或“F”。由此,至少关于变量“e',编译器200可以确定调用函数func1()不与被调用函数foo1()交互。
在框430中,根据对调用函数是否与被调用函数交互的确定,编译器200可以确定是否矢量化调用函数的至少一部分。例如,基于上述所表达的依赖关系信息,编译器200可以通过生成对多个数据项(例如,阵列组元)和/或多个循环迭代并发地操作的矢量代码,来尝试矢量化调用函数func1()。
在各种实施例中,依赖关系数据库可以表达各种类型的信息,该信息可以在确定是否矢量化函数时对编译器200有用。示例包括跟踪对以下项的读取和写入:数据对象、指针、被指向数据对象、被指向对象内的已知偏移、进入被指向对象的未知偏移(其可以有效地构成针对整个对象的引用)、对象内的可变偏移(被指向对象和数据对象两者,其可以利用所讨论变量使能实现运行时间依赖关系分析)、以及进入进入更高级对象中的未知偏移的对象中的已知偏移(例如,在引用未知数量的已知偏移但其它偏移仍保持未引用时)。
已知偏移信息可以使得编译器200能够矢量化,而不生成附加依赖关系检查指令,同时可变偏移信息可以被用于在运行时间生成分析变量依赖关系的依赖关系检查指令,其可以允许实现增加的矢量并行性,同时保持程序正确性。
如上说明的,依赖关系数据库可以表达有关被调用函数的信息,该信息在矢量化调用函数时有用于编译器200。在这点上,依赖关系数据库可以存储这样的信息:诸如存储器访问类型、寻址模式、以及/或附加限定符。
在一些实施例中,通过一函数访问的存储器通常落入两种类型中:读取和写入。由此,如在上面给出的示例中所示,依赖关系数据库可以明确地存储对数据项是被读取还是写入的指示。
寻址模式描述了如调用函数所观看的调用函数内的存储器访问。一些实施例可以定义三种寻址模式:常数、变量、以及未知,虽然另选实施例也是可能并且可以设想的。这三个寻址模式中的每一个可以分别根据寻址是否可以通过编译器在编译时间建立、根据运行时间的调用函数、或者根据运行时间的被调用函数来确定。另外,一些实施例可以定义针对寻址模式的两个正交限定符:公用和专用。这些指定所关联的变量是否可见于外部模块。
根据一些实施例,常数寻址描述了可以在编译时间从模块外部分解的寻址。这包括针对命名变量、命名结构内的命名结构组元、或者可以在编译时间分解的阵列索引。例如,g(命名变量)、str.g(命名结构内的命名结构组元)、h[5](根据常数索引的阵列)、以及str[5].h(根据常数索引的命名结构阵列内的命名结构组元)表示常数寻址的示例。这些示例可以表示静态变量或全局变量。(自动存储通常是临时的(例如,在进入模块时分配和在模块退出时解除分配),并由此通常在模块外部可见)。下面的示例例示了针对使用常数寻址的函数的依赖关系:
在一些实施例中,变量寻址描述了不是恒定的而且也不被被调用函数修改的寻址。因此,其可以在运行时间通过调用函数评估。示例包括对其中可以通过调用函数观察寻址的被指向对象和阵列的引用。考虑下面的函数:
该函数将输出针对依赖关系文件的下列依赖关系,声明函数写入A[g]和读取A[x](都是可变寻址阵列):
在这个示例中,如果函数assignA()每一调用函数迭代仅被调用一次,则依赖关系检查(其还可以被称为意外(hazard)检查)可能不必要。被调用函数assignA()可以确定g和x是否交叠,并因此例如利用Macroscalar技术来区分矢量。
考虑其中外部循环每一迭代调用assignA()两次的情形:
尽管意外可能存在于g1与x之间,或者g2与y之间,但这些依赖关系与函数的单一调用有关。在该特定实例中,调用循环可以仅检查g1与y以及g2与x之间的潜在意外,其可以根据依赖关系文件中的信息来识别。
在一些实施例中,未知寻址类似于如上所述的变量寻址,但通常应用至其中运行时间寻址不能通过调用函数评估的情形。这例如可以发生在其中被调用函数利用来自依赖关系文件的信息按不可见于调用函数的方式修改地址变量的值的情形中。
附加限定符“公用”和“专用”可以指定链接器是否输出一符号以允许通过调用函数检查变量。例如,针对接下来至上面给出的最后示例中的A[]的引用被指定“专用”,因为A[]被声明为不向调用assignA()的函数输出的文件静态变量。在这个示例中,编译器200可以根据依赖关系信息确定assignA()函数怎样寻址A[],但不能够生成实际上读取A[]的值的代码。
全函数矢量化
如上详细描述的,可以采用编译器自动矢量化,以按可以透明于程序员或其它用户的方式,根据非矢量化源代码来生成矢量化代码。这种编译器自动矢量化可以使得源代码能够在很少或没有程序员干涉的情况下利用由矢量计算硬件提供的性能改进的优点。
然而,如果非叶函数(即,调用其它函数的函数)要有效地矢量化,则可以希望提供向调用函数暴露矢量接口而非可能在原始源代码中表示的标量接口的被调用函数的形式。
而且,应用开发者可能希望以针对多种计算平台的应用为目标,并不是所有这些计算平台都可以提供矢量资源。例如,处理器家族的移动版可能省略矢量运算以缩减芯片尺寸和功耗,而同一处理器家族的台式版可能被开发成与功耗相比更注重处理功率。在这种情形下,为了在移动处理器上执行,应用可能需要仅利用标量函数来编译,而该应用当在台式处理器上执行时,可能使用标量函数或矢量函数。然而,关于上述自动矢量化,可以希望允许该应用在矢量平台和非矢量平台上有效执行,同时缩减或消除程序员干涉。
对应地,在矢量化一函数时,根据在此描述的一些实施例的编译器可以根据单一源代码描述生成函数的标量和矢量版本。该函数例如可以是库函数,尽管更一般地说,其可以对应于任何可调用过程或方法。在一些实施例中,函数的标量版本可以使用如由源代码最初指定的标量接口。同时,该函数的矢量版本可以实现针对该函数的矢量接口,接受矢量参数和/或生成矢量返回值。通过生成该函数的标量和矢量版本两者,编译器可以使得代码能够在编译时间或者运行时间更灵活地为可用资源特制。而且,通过生成被调用函数的矢量化版本并将所得矢量接口暴露给调用函数,编译器可以辅助调用函数的矢量化,由此传播用于从叶函数向上分级地矢量化的机会。
矢量接口例如可以在与该函数相关联的依赖关系数据库(如依赖关系文件)中表达。例如,考虑下面的函数外壳,其中,该函数的内部细节已经省略:
针对该函数的标量接口可以表示(例如,在依赖关系文件内)为:
int foo(int A)
该表示反映了,根据该版本,foo()采取标量参数并且返回标量结果。
同一函数在被矢量化以例如一次在多个数据项上执行操作时可以变为:
这样,针对该函数的矢量接口可以被表示(例如,在依赖关系文件内)为:
Vector foo(Vector A)
不同于现有表示,该表示指示foo()的该版本采取矢量参数并且返回矢量结果。
参照图5,描绘了表示全函数矢量化方法的一实施例的流程图。在框500中,编译器200接收要编译的函数。在框510中,编译器200可以编译该函数的标量形式。在框520中,编译器200可以编译该函数的矢量形式。而在框530中,编译器200可以在依赖关系数据库中表达与该函数的矢量版本相关联的矢量接口。
这种另选矢量接口的存在允许编译器200从矢量化循环内进行矢量函数调用,而非从矢量化循环内进行多个串行化标量函数调用。例如,考虑针对外部函数foo()进行调用的调用函数内的下列循环:
如果foo()仅具有标量接口,则用于矢量化该循环的机会可能受限,例如,限制矢量化的指配。然而,存在foo()的矢量版本可以增加对于循环矢量化的机会。例如,上述循环的矢量化版本可能利用矢量参数调用foo()并且可能接收矢量结果,使能实现更多并发执行并缩减循环内的串行化。而且,不同于先前方法,该技术准许函数的矢量化不包含循环。这可以增加应用中的总矢量化的量。
函数的两个版本中的循环可以被矢量化。一般而言,“水平”矢量化可以涉及这样类型的矢量化,即,其中,循环的迭代被映射成矢量的对应组元。“垂直”矢量化可以涉及这样类型的矢量化,即,其中,循环的迭代性质可以保留(即,与被映射至如在水平矢量化中的矢量组元相反),但其中标量变量用矢量变量替换,使得每一个迭代在比代码的标量版本更多的数据上并发地操作。
函数的标量版本中的循环可以利用Macroscalar技术水平地矢量化,而该函数的矢量版本中的循环可以水平地或者垂直地矢量化。这可以增加应用中用于矢量化的机会。除了矢量化函数调用的性能和效率益处以外,该技术还可以增加一应用中垂直地矢量化的循环的数量,由此缩减在水平地矢量化循环时导致的开销。
参照图6,描绘了表示利用矢量化函数的方法的一实施例的流程图。在框600中,编译器200识别针对被调用函数进行调用的调用函数。例如,调用函数可以包括针对预编译库内的一函数进行调用的循环。在框610中,编译器200访问与被调用函数相关联的依赖关系数据库。在框620中,编译器200检查依赖关系数据库,以确定被调用函数的矢量变型是否可用。在一个实现中,如果该矢量版本可用,则在框630中,编译器200编译调用函数,以利用被调用函数的矢量变型。如果该矢量版本不可用,则编译器200编译调用函数,以利用标量版本(例如,通过迭代地调用该函数的标量版本)。
例如,再次考虑下面的循环:
当矢量化该循环时,编译器可以检查与foo()相关联的依赖关系数据库,以确定与foo()相关联的矢量接口是否存在。如果foo()的矢量接口不存在,则编译器200可以仅局部地矢量化该循环,例如,在按标量格式留下函数调用的同时通过矢量化该指配来进行。
另一方面,如果foo()具有在其依赖关系数据库中表达的矢量化接口,则在一些实例中,编译器200可以整体矢量化该循环(例如,通过替换或以其它方式将该指配和函数调用变换成矢量运算)。
当编译器检查foo()的依赖关系数据库,以确定是否存在用于被调用函数的矢量化接口时,编译器可以另外或者另选地检查与被调用函数(可以被表达为与foo()相关联的同一(或另一)依赖关系数据库)相关联的任何存储器依赖关系。
在一些实现中,可以独立地跟踪针对一阵列的每一维的寻址,以最小化不确定性。这种构思通常可以应用至所有聚合数据类型,如结构和阵列。下列的示例更详细地例示了编译器(例如,如编译器200)怎样可以使用依赖关系数据库信息以使能矢量化,以及怎样可以在可能的时候采用函数的矢量版本来代替标量版本(应注意到,在其它实施例中,依赖关系数据库可以被使用而与确定是否存在矢量函数接口无关,反之亦然)。
在这个示例中,函数bar()将输出指示其写入p.ptr[]并且从p.b和j读取的依赖关系(例如,在编译函数bar()时由编译器200生成的依赖关系文件,如上所述):
应注意到,在这种特定情况下,可以不必识别参数的引用为“公共”或“私有”。而且,可以不必声明从p或j读取的函数,因为至少在该示例中可以假定函数使用其自身参数。可以在依赖关系数据库中包括myStruct的类型定义,以将其暴露至调用foo()的函数,但可以不必通过首部文件包含来暴露至myStruct的定义。
在编译期间,编译器200可以编译函数bar()而不需要矢量化其,因为不存在通过其矢量化的循环。这样做,其可以生成具有下列接口的bar()的标量版本:
int bar(myStruct*p,int j)
在这个示例中,bar()可以采取针对一结构的指针的单一实例和单一整数作为参数,并且返回单一整数作为结果。由此,这种版本的bar()在其输入和输出方面是标量。
然而,编译器200还可以利用还可以在依赖关系数据库中输出的下列接口来编译矢量函数:
Vector bar(Vector p,Vector j,Vector pred)
在这个示例中,预测矢量pred指定哪些矢量组元应当通过该函数来处理。例如,假定矢量包括限定数量的组元,预测矢量可以包含具有相同限定数量比特的矢量,每一个比特对应于相应组元。每一个比特可以用作确定其对应矢量组元是否应当被处理的布尔(Boolean)预测(例如,如果预测比特为“1”,则“是”,而如果其为“0”,则“否”,反之亦然)。预测允许调用函数进行条件化函数调用,并且如果其未在矢量长度边界上终止则注意该循环的尾部。应注意到,其它实施例可以采用不同类型的预测格式,如非布尔预测。
而且,在这个示例中,矢量p是针对结构的指针的矢量,尽管在这个示例中,它们全部指向同一实例。矢量j是简单整数的矢量。编译器可以根据标量函数声明来推断该类型信息。
函数bar()的一种可能矢量变型计算针对输入矢量的每一个组元的p.b+j,并将这些结果写入到p.ptr的恰当阵列索引中。还基于p.b和j的比较来返回结果的矢量。在该具体示例中,编译器垂直地矢量化该函数。即,因为bar()不包含循环,所以不存在要变换成矢量组元的循环迭代,如在水平矢量化中的情况。相反的是,矢量化版本的bar()可以在矢量输入的不同组元上并发操作。
在编译foo()期间,编译器200可以读取有关函数bar()的依赖关系信息信息,其可能不必位于同一源文件中,并且即使调用函数正在将一指针传递至结构g,也确定被调用函数bar()没有针对g.a的依赖关系。因为其具有这种信息,所以编译器200可以水平地矢量化函数foo()中的循环。而且,编译器200可以针对每一个所处理的矢量对bar()的矢量变型进行单一函数调用,而非在该循环的每一个迭代中调用标量变型。最后,编译器200可以创建具有矢量接口的foo()的矢量变型。在这种特定情况下,因不能针对依赖关系对x的整个范围进行分析,所以垂直矢量化可能不能应用。可以应用循环的水平矢量化,并且其被包含在另一循环内,该另一循环在被传递至函数foo()的矢量变型的矢量组元上迭代。
在这些假定下,函数foo()可能输出下列依赖关系:
(符号表示未知寻址)。因为函数bar()输出依赖关系“writep.ptr[p.b+j]”,所以编译器200可以断定结构成员ptr[]被写入为x的函数。由此,编译器200可以向foo()的调用方报告写入的索引未知,因为其不能通过foo()的调用方来确定。
附加实现技术
这部分描述了附加非限制编译器技术,其可以被用于实现非叶和全函数矢量化。下面的描述基于Macroscalar编译器技术,但本领域普通技术人员鉴于本公开将认识到,可以使用其它编译器技术。
先前的实例例示了寻址可以包括数学表达式。这种通常是真实的只要该表达式不涉及函数调用,并且仅包含对于调用函数可见的项。这可以包括间接寻址,如当在计算进入其它阵列的索引时使用的查寻表。
间接寻址是这样一种情形,其中配置编译器和链接器以输出为公共的静态阵列可以帮助矢量化更多循环。考虑下列示例:
针对foo()生成的依赖关系可以根据编译器和链接器是否被配置成公共地输出静态符号而不同。在下面的示例中,第一依赖关系文件表达专用静态变量,而第二依赖关系文件表达公共静态变量:
应注意到,类型声明A在其公开输出时在依赖关系文件中是必需的。当静态变量专用时,对B[]的寻址是未知的,因为其不能从该函数外部确定。因为意外检查不可能,所以可以不执行bar()中的循环的矢量化。然而,在将这些工具配置成公开输出静态变量时,编译器可以发射读取A[x]的内容的指令,并且检查B[A[x]]与B[x]之间的意外,由此使能实现循环的矢量化。
自然地,当静态变量被公开输出并外部地寻址时,针对名称冲突的机会上升。为帮助避免这种冲突,静态变量可以利用它们被声明的函数和文件来进行名字重整。
一些意外涉及条件化地发生的存储器操作,或者涉及可以基于条件化计算而不同的寻址。为支持调用涉及条件化依赖关系的函数的循环的矢量化,可以提供机制来表达该条件怎样影响依赖关系。
例如,考虑下面的代码:
if(A[x]<c)d=B[x];
该代码可以在依赖关系数据库中表达为:
条件化表达还可以存在于计算地址时。例如,考虑下面的代码:
该代码可以在依赖关系文件中表达为:
另选的是,上面稍后的条件化表达可以被表达为:
read public B[A[x]<c?x:x+c];
在某些情况下,未知可以潜入依赖关系表达式。在这种情况下,一个例示性示例可以是:
A[x]<c?read public B[x]:read public B[];
如果条件为真,则该表达式可以向编译器通知有关B的特定依赖关系,而如果该条件为假,则通知有关B的未知依赖关系。
潜入条件化表达的未知可以导致表现得好像该条件既为真又为假的非条件化依赖关系。例如:
A[x]<B[]?read public f:read public g;
可以表达为:
read public f;
read public g;
并且:
read public A[x>?x:x+y];
可以表达为:
read public A[x];
read public A[x+y];
因为调用函数通常不能够评估未知条件,所以它们可以进行保守假定,即,访问进入A[]的两种可能索引。
在一些实现中,还可以在依赖关系数据库中表达循环依赖关系。例如,考虑下面的函数:
if(A[x]>b)b=A[x]
在一个实现中,该函数可以表达为:
read public A[x];
read public b;
A[x]>b?write public b;
其中,将指针或引用传递至一函数(还被称为“按引用来传递”),针对该函数,可以修改其调用参数。这例如与对按值传递的参数的修改不同,因为按引用来传递的参数的修改可以影响调用函数的操作。按引用来传递的参数的修改可以按记录静态和全局存储的修改的相同方式来记录。按值传递的参数的修改可以被处理为局部自动存储的修改。在某些情况下,因它们对于调用函数不可见,所以可以不记录它们。
在一些实现中,满足一组标准的函数可以在其中软件推测将需要矢量化调用循环的情况下推测地调用。因此,推测安全指示符可以在依赖关系文件中表达,并且可以用作对应代码可以按推测性方式安全地调用的指示。在一个非限制例中,能够被推测性地调用的矢量函数可以落入两种类型之一:type-A和type-B。Type-A函数可以是具有在此描述的正常矢量接口的矢量函数。例如,如果Type-A函数满足下面的标准,则它们可没有有害副作用地被推测性地调用。首先,该函数除了本地自动非阵列存储装置以外不访问其它存储器。第二,该函数不调用不是type-A函数的任何其它函数。type-A函数的示例可能是先验的或者是其它迭代式收敛算法。
除了由源代码指定的任何返回值以外,type-B函数可以返回指示那些组元被处理的预测矢量。在一实施例中,用于推测性地调用type-B函数的标准可以如下。首先,来自非本地存储装置或本地阵列存储装置的任何读取使用第一故障读取指令。第二,该函数不写入非本地存储装置或静态本地存储装置。第三,该函数不调用也不是type-A或type-B函数的任何函数。
从一循环调用type-A函数可以与调用非推测函数相似。典型地讲,在推测性地调用type-A函数时在调用循环的部分上不需要非特定动作。然而,调用type-B函数可能需要该调用循环检查返回矢量,以便确定处理了哪些组元,并且响应地调节调用循环的行为。
诸如编译器200的编译器可以选择成使type-B矢量函数的所有调用方调节它们的行为,以适应实际上处理了的组元的数量,而不管软件推测是否在调用循环中使用。另选的是,编译器200可以针对每一个type-B函数创建两个矢量函数;一个推测性的和一个非推测性的。针对type-B循环的标准通常可以被指定成确保合格的那些循环很少且较小,并由此针对该方法的代码尺寸影响可以忽略。
Type-A和type-B矢量函数可以在依赖关系数据库中由它们的声明来识别,如下所示。在一个实现中,缺乏指定符暗示函数可能不被推测性地调用。
混叠有时可能是用于矢量化编译器的问题。虽然Macroscalar架构致力于通过运行时间混叠分析来解决该问题,但存在针对该方法的开销。Macroscalar程序中的开销贡献于Amdahl’s law中的串行组件,其可以限制更宽矢量的益处。而且,伴随外部或静态变量的混叠可以影响横跨函数调用的行为。因此,在一个实现中,执行编译时间混叠分析,并且将混叠指示符输出至依赖关系文件中。
例如,一种方法可以是将混叠事件分离成两种类别,举例来说,如入站和出站混叠。从被调用函数的观点来看,入站混叠可以涉及进入一函数的地址,如从外部变量读取的、或者通过采取外部变量的地址由该函数计算的作为参数传递的那些。同时,出站混叠可以涉及函数放出的指针。这些可以是返回值(即,该函数写入外部变量或非引用指针的值)。
而且,可以跟踪至少两类混叠。“副本混叠(Copies aliasing)”可以指示该指针可以是另一指针的副本并且可以混叠该指针可以混叠的任何事物。“指针混叠”可以指示一指针可能影响另一变量。依赖关系文件中的混叠信息是可能存在混叠的肯定表达。例如,在编译器因缺乏信息而不能简单地断定两个指针是否引用同一存储器时,不需要使用其。
声明针对变量的混叠可以类似于声明针对返回值的混叠。例如,考虑下面的函数:
在一个实现中,该函数可以表达下列依赖关系:
为清楚起见,前述在指针与副本之间区别,尽管其可以按另选语法组合这两个构思。关于其它依赖关系信息,混叠信息通常通过调用函数链向上传播。
通过一函数返回的值也可以导致混叠,例如,通过返回值本身,或者通过因修改按引用传递的变量而返回的信息。这些还可以在依赖关系文件中进行跟踪。例如,考虑下面的函数:
在一个实现中,该函数可以输出下列依赖关系:
依赖关系声明可以向调用循环通知由foo()返回的指针可能是被传递的指针的副本。这允许调用循环采取措施,以确保该循环的正确操作,而不管出现的混叠。而且,该获知还可以使得编译器能够在面临非ANSI-C兼容的代码时更好地杠杆化ANSI混叠规则。
作为另一考虑,指针的投影可以影响地址计算。例如,考虑下面的函数:
在一个实现中,该函数可以输出下列依赖关系:
经由函数指针的调用通常因其在编译时间不知道将调用什么函数或者被调用函数是否支持矢量接口的事实而不能被矢量化。经由指针调用其它函数的函数可以不输出依赖关系信息,其可以是有关被指向函数的依赖关系的不确定性的反映。这可以导致编译器将这种函数视为具有未知依赖关系的标量函数。
在一个实现中,版本化方案允许依赖关系在任何时间点利用最佳实践来表达。例如,实施例可以准许与由较旧编译器生成的依赖关系文件向后兼容,而另一实施例可以准许使得较旧编译器也能够读取由较新编译器生成的文件的双向兼容性。在向后兼容性是唯一需求的情况下,针对依赖关系文件的版本指示符被用于向较旧编译器通知给定文件不可读并且应当被忽略。
双向兼容性可如下实现。例如假定编译器版本1不支持阵列索引中的计算,而编译器版本2支持。A write to B[x+y],可以由版本1编译器表达为:
另一方面,版本2编译器可以另外利用版本2语法输出同一函数:
利用该方法,不仅版本2编译器可以读取版本1文件,而且其还可以允许版本2声明无视版本1声明。版本1编译器将获知忽略大于版本1的任何声明,向其赋予其能够理解的尽可能多的依赖关系信息。随着编译器技术的成熟这是一种重要能力。
一般而言,如果开发方被要求针对软件进行改变以使能矢量化,则相对较少的代码可以发生矢量化。为致力于解决这种问题,在此描述的技术提供了用于执行大规模矢量化的能力,而不需要开发方修改它们的源代码。
尽管上述实施例已经相当详细地进行了描述,但一旦完全清楚本说明书,本领域技术人员将明白许多变型例和修改例。下面的权利要求书旨在被解释成涵盖所有这种变型例和修改例。
Claims (20)
1.一种方法,包括:
通过一个或多个计算机来执行以下步骤:
识别调用函数,该调用函数包括针对被调用函数的调用;
访问与被调用函数相关联的永久依赖关系数据库,其中,该永久依赖关系数据库指示被调用函数的被表达的依赖关系,其中,该被表达的依赖关系指示被调用函数是仅读取数据项、仅写入数据项、还是既读取又写入数据项;以及
至少部分地基于被表达的依赖关系生成调用函数是否与被调用函数交互的确定。
2.根据权利要求1所述的方法,其中,针对被调用函数的调用发生在调用函数的循环内。
3.根据权利要求1所述的方法,其中,所述执行还包括:
从永久依赖关系数据库确定被调用函数的矢量版本的存在;并且
在调用函数内,将针对被调用函数的标量版本的调用变换成针对被调用函数的矢量版本的调用。
4.根据权利要求1所述的方法,其中,所述执行还包括:基于由永久依赖关系数据库指示的下列项中的一个或多个来确定是否矢量化调用函数的至少一部分:变量由调用函数读取还是写入、变量对于调用函数是公共的还是私有的、以及与变量相关联的寻址模式。
5.根据权利要求1所述的方法,其中,所述执行还包括:
编译与一函数相对应的源代码;
在编译期间,识别该函数对数据项的被表达的依赖关系,其中,该被表达的依赖关系指示该函数是仅读取数据项、仅写入数据项、还是既读取又写入数据项;以及
将对被表达的依赖关系的指示存储在永久依赖关系数据库中。
6.根据权利要求5所述的方法,其中,存储对被表达的依赖关系的指示包括:除了存储变量的名称以外,还将对以下各项中的一个或多个的指示存储在永久依赖关系数据库中:变量对于该函数是公共的还是私有的、以及与变量相关联的寻址模式。
7.根据权利要求5所述的方法,其中,所述执行还包括:生成该函数具有矢量接口的矢量版本,并且将对矢量接口的指示存储在永久依赖关系数据库中。
8.根据权利要求5所述的方法,其中,所述执行还包括:在函数的编译时创建永久依赖关系数据库。
9.根据权利要求5所述的方法,其中,存储指示包括:表达以下各项中的一个或多个:与该函数内的数据项相关联的寻址模式、与该函数内的数据项相关联的公共或私有限定符、与该函数相关联的推测安全指示符、以及与函数内的数据项相关联的混叠指示符。
10.根据权利要求5所述的方法,其中,存储指示包括:表达以下各项中的一个或多个:对该函数向被指向对象内的已知偏移读取还是写入的指示、对该函数向一对象内的可变偏移读取还是写入的指示、或者对该函数向一对象内的未知偏移读取还是写入的指示。
11.根据权利要求1或权利要求5所述的方法,其中,数据项不是经由函数的编程接口传递到该函数的参数。
12.根据权利要求1所述的方法,其中,所述执行还包括:至少部分地基于所述确定来矢量化调用函数内的代码。
13.根据权利要求12所述的方法,其中,所述矢量化调用函数内的代码还包括:至少部分地基于所述确定来矢量化调用函数内的循环。
14.根据权利要求12所述的方法,其中,所述矢量化调用函数内的代码还包括:将所述调用修改成引用被调用函数的矢量版本。
15.根据权利要求1所述的方法,其中,所述操作还包括:
根据对调用函数是否与被调用函数交互的确定,至少部分地基于被表达的依赖关系来确定是否矢量化调用函数的至少一部分;并且
响应于确定矢量化调用函数的至少一部分,生成当被执行时使矢量运算针对调用函数内所引用的多个数据项并发执行的矢量代码。
16.根据权利要求15所述的方法,其中,被调用函数包括预编译代码内的函数,并且其中,所述确定操作确定矢量化调用函数的至少一部分,即使预编译代码的源代码不可用。
17.根据权利要求1所述的方法,其中,该调用函数包括非叶循环,该非叶循环包括针对被调用函数的调用。
18.根据权利要求17所述的方法,其中,所述执行还包括:
矢量化非叶循环的第一部分;并且
串行化非叶循环的第二部分。
19.一种其中存储有程序指令的计算机可读存储介质,所述程序指令响应于计算机***的执行,使该计算机***执行实现根据权利要求1-18中的任一项所述的方法的操作。
20.一种***,包括:
一个或多个存储器,其在操作期间,存储指令;和
一个或多个处理器,其在操作期间,从所述一个或多个存储器检索指令,并且执行该指令以使该***执行实现根据权利要求1-18中的任一项所述的方法的操作。
Applications Claiming Priority (5)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
US12/888,658 US8949808B2 (en) | 2010-09-23 | 2010-09-23 | Systems and methods for compiler-based full-function vectorization |
US12/888,644 | 2010-09-23 | ||
US12/888,658 | 2010-09-23 | ||
US12/888,644 US8621448B2 (en) | 2010-09-23 | 2010-09-23 | Systems and methods for compiler-based vectorization of non-leaf code |
PCT/US2011/050713 WO2012039937A2 (en) | 2010-09-23 | 2011-09-07 | Systems and methods for compiler-based vectorization of non-leaf code |
Publications (2)
Publication Number | Publication Date |
---|---|
CN103119561A true CN103119561A (zh) | 2013-05-22 |
CN103119561B CN103119561B (zh) | 2016-03-09 |
Family
ID=44937720
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201180045583.4A Expired - Fee Related CN103119561B (zh) | 2010-09-23 | 2011-09-07 | 用于对非叶代码进行基于编译器的矢量化的***和方法 |
Country Status (9)
Country | Link |
---|---|
KR (1) | KR101573586B1 (zh) |
CN (1) | CN103119561B (zh) |
AU (1) | AU2011305837B2 (zh) |
BR (1) | BR112013008640A2 (zh) |
DE (1) | DE112011103190T5 (zh) |
GB (1) | GB2484000A (zh) |
MX (1) | MX2013003339A (zh) |
TW (1) | TWI446267B (zh) |
WO (1) | WO2012039937A2 (zh) |
Cited By (11)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN106371838A (zh) * | 2016-08-31 | 2017-02-01 | 福建联迪商用设备有限公司 | 一种维护软件包依赖关系的方法及*** |
CN107710150A (zh) * | 2015-06-15 | 2018-02-16 | 高通股份有限公司 | 从包含层次子例程信息的中间代码产生目标代码 |
CN108733432A (zh) * | 2017-04-14 | 2018-11-02 | 阿里巴巴集团控股有限公司 | 编程环境下私有方法的实现方法、调用方法及其装置 |
CN109240666A (zh) * | 2018-06-22 | 2019-01-18 | 北京大学 | 基于调用栈和依赖路径的函数调用代码生成方法及*** |
CN110998516A (zh) * | 2017-05-22 | 2020-04-10 | 起元技术有限责任公司 | 用于异构编程数据处理***的自动化依赖性分析器 |
CN111566616A (zh) * | 2017-11-03 | 2020-08-21 | 相干逻辑公司 | 多处理器***的编程流程 |
CN112214221A (zh) * | 2020-10-10 | 2021-01-12 | 上海上讯信息技术股份有限公司 | 一种用于Linux***构建的方法与设备 |
CN112799671A (zh) * | 2019-11-13 | 2021-05-14 | 北京配天技术有限公司 | 一种函数解析方法及其计算机设备 |
CN113342319A (zh) * | 2021-05-24 | 2021-09-03 | 重庆长安汽车股份有限公司 | 一种can故障诊断的软件代码自动生成的方法及*** |
CN113536316A (zh) * | 2021-06-17 | 2021-10-22 | 深圳开源互联网安全技术有限公司 | 组件依赖信息的检测方法及装置 |
CN113742646A (zh) * | 2020-05-28 | 2021-12-03 | 红帽公司 | 将单语言复合函数编译为单个实体 |
Families Citing this family (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US9298456B2 (en) | 2012-08-21 | 2016-03-29 | Apple Inc. | Mechanism for performing speculative predicated instructions |
US9817663B2 (en) | 2013-03-19 | 2017-11-14 | Apple Inc. | Enhanced Macroscalar predicate operations |
US9348589B2 (en) | 2013-03-19 | 2016-05-24 | Apple Inc. | Enhanced predicate registers having predicates corresponding to element widths |
US11809871B2 (en) * | 2018-09-17 | 2023-11-07 | Raytheon Company | Dynamic fragmented address space layout randomization |
Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
EP0785506A1 (en) * | 1996-01-17 | 1997-07-23 | Nec Corporation | Optimizing compiler using interprocedural dataflow analysis |
US20090138862A1 (en) * | 2007-11-22 | 2009-05-28 | Kabushiki Kaisha Toshiba | Program parallelization supporting apparatus and program parallelization supporting method |
CN101477472A (zh) * | 2009-01-08 | 2009-07-08 | 上海交通大学 | 动态二进制翻译器中热路径的多核多线程构建方法 |
US20090307656A1 (en) * | 2008-06-06 | 2009-12-10 | International Business Machines Corporation | Optimized Scalar Promotion with Load and Splat SIMD Instructions |
Family Cites Families (6)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
JP2002073333A (ja) * | 2000-08-25 | 2002-03-12 | Hitachi Ltd | 手続き呼び出し先のデータ依存の解析表示方法 |
JP2004246776A (ja) * | 2003-02-17 | 2004-09-02 | Ricoh Co Ltd | 自動変数共有化コンパイラ、自動変数共有化リンカ及びプログラム開発支援システム |
US7395419B1 (en) | 2004-04-23 | 2008-07-01 | Apple Inc. | Macroscalar processor architecture |
US7617496B2 (en) | 2004-04-23 | 2009-11-10 | Apple Inc. | Macroscalar processor architecture |
US7506331B2 (en) | 2004-08-30 | 2009-03-17 | International Business Machines Corporation | Method and apparatus for determining the profitability of expanding unpipelined instructions |
US8418161B2 (en) * | 2008-11-24 | 2013-04-09 | International Business Machines Corporation | System and method for loading a called class file table with data indicating a highest version of a class file |
-
2011
- 2011-09-07 BR BR112013008640A patent/BR112013008640A2/pt not_active IP Right Cessation
- 2011-09-07 DE DE112011103190T patent/DE112011103190T5/de not_active Withdrawn
- 2011-09-07 KR KR1020137010386A patent/KR101573586B1/ko active IP Right Grant
- 2011-09-07 CN CN201180045583.4A patent/CN103119561B/zh not_active Expired - Fee Related
- 2011-09-07 WO PCT/US2011/050713 patent/WO2012039937A2/en active Application Filing
- 2011-09-07 AU AU2011305837A patent/AU2011305837B2/en not_active Ceased
- 2011-09-07 MX MX2013003339A patent/MX2013003339A/es active IP Right Grant
- 2011-09-22 TW TW100134227A patent/TWI446267B/zh not_active IP Right Cessation
- 2011-09-23 GB GB1116429.0A patent/GB2484000A/en not_active Withdrawn
Patent Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
EP0785506A1 (en) * | 1996-01-17 | 1997-07-23 | Nec Corporation | Optimizing compiler using interprocedural dataflow analysis |
US20090138862A1 (en) * | 2007-11-22 | 2009-05-28 | Kabushiki Kaisha Toshiba | Program parallelization supporting apparatus and program parallelization supporting method |
US20090307656A1 (en) * | 2008-06-06 | 2009-12-10 | International Business Machines Corporation | Optimized Scalar Promotion with Load and Splat SIMD Instructions |
CN101477472A (zh) * | 2009-01-08 | 2009-07-08 | 上海交通大学 | 动态二进制翻译器中热路径的多核多线程构建方法 |
Cited By (18)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN107710150A (zh) * | 2015-06-15 | 2018-02-16 | 高通股份有限公司 | 从包含层次子例程信息的中间代码产生目标代码 |
CN106371838B (zh) * | 2016-08-31 | 2019-10-18 | 福建联迪商用设备有限公司 | 一种维护软件包依赖关系的方法及*** |
CN106371838A (zh) * | 2016-08-31 | 2017-02-01 | 福建联迪商用设备有限公司 | 一种维护软件包依赖关系的方法及*** |
CN108733432B (zh) * | 2017-04-14 | 2021-12-21 | 创新先进技术有限公司 | 编程环境下私有方法的实现方法、调用方法及其装置 |
CN108733432A (zh) * | 2017-04-14 | 2018-11-02 | 阿里巴巴集团控股有限公司 | 编程环境下私有方法的实现方法、调用方法及其装置 |
CN110998516A (zh) * | 2017-05-22 | 2020-04-10 | 起元技术有限责任公司 | 用于异构编程数据处理***的自动化依赖性分析器 |
CN110998516B (zh) * | 2017-05-22 | 2024-04-16 | 起元技术有限责任公司 | 用于异构编程数据处理***的自动化依赖性分析器 |
CN111566616A (zh) * | 2017-11-03 | 2020-08-21 | 相干逻辑公司 | 多处理器***的编程流程 |
CN111566616B (zh) * | 2017-11-03 | 2023-12-12 | 相干逻辑公司 | 多处理器***的编程流程 |
CN109240666A (zh) * | 2018-06-22 | 2019-01-18 | 北京大学 | 基于调用栈和依赖路径的函数调用代码生成方法及*** |
CN112799671A (zh) * | 2019-11-13 | 2021-05-14 | 北京配天技术有限公司 | 一种函数解析方法及其计算机设备 |
CN113742646A (zh) * | 2020-05-28 | 2021-12-03 | 红帽公司 | 将单语言复合函数编译为单个实体 |
CN112214221B (zh) * | 2020-10-10 | 2023-04-28 | 上海上讯信息技术股份有限公司 | 一种用于Linux***构建的方法与设备 |
CN112214221A (zh) * | 2020-10-10 | 2021-01-12 | 上海上讯信息技术股份有限公司 | 一种用于Linux***构建的方法与设备 |
CN113342319A (zh) * | 2021-05-24 | 2021-09-03 | 重庆长安汽车股份有限公司 | 一种can故障诊断的软件代码自动生成的方法及*** |
CN113342319B (zh) * | 2021-05-24 | 2024-03-22 | 重庆长安汽车股份有限公司 | 一种can故障诊断的软件代码自动生成的方法及*** |
CN113536316A (zh) * | 2021-06-17 | 2021-10-22 | 深圳开源互联网安全技术有限公司 | 组件依赖信息的检测方法及装置 |
CN113536316B (zh) * | 2021-06-17 | 2023-08-11 | 深圳开源互联网安全技术有限公司 | 组件依赖信息的检测方法及装置 |
Also Published As
Publication number | Publication date |
---|---|
CN103119561B (zh) | 2016-03-09 |
KR101573586B1 (ko) | 2015-12-01 |
BR112013008640A2 (pt) | 2016-06-21 |
TW201224933A (en) | 2012-06-16 |
TWI446267B (zh) | 2014-07-21 |
AU2011305837A1 (en) | 2013-03-28 |
WO2012039937A2 (en) | 2012-03-29 |
WO2012039937A3 (en) | 2012-09-20 |
DE112011103190T5 (de) | 2013-06-27 |
KR20130096738A (ko) | 2013-08-30 |
MX2013003339A (es) | 2013-06-24 |
AU2011305837B2 (en) | 2015-05-14 |
GB2484000A (en) | 2012-03-28 |
GB201116429D0 (en) | 2011-11-02 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN103119561B (zh) | 用于对非叶代码进行基于编译器的矢量化的***和方法 | |
US8621448B2 (en) | Systems and methods for compiler-based vectorization of non-leaf code | |
US8949808B2 (en) | Systems and methods for compiler-based full-function vectorization | |
US9529574B2 (en) | Auto multi-threading in macroscalar compilers | |
Grosser et al. | Polyhedral AST generation is more than scanning polyhedra | |
Verdoolaege et al. | Polyhedral extraction tool | |
CN100559346C (zh) | 用于实例化抽象类的***和方法 | |
JP5893038B2 (ja) | ユーザ定義型のコンパイル時境界検査 | |
Pop et al. | GRAPHITE: Polyhedral analyses and optimizations for GCC | |
US20120117552A1 (en) | Speculative compilation to generate advice messages | |
CN107003885B (zh) | 用于低级别可组合高性能计算库的技术 | |
US10705814B2 (en) | Systems and/or methods for generating reassemblable disassemblies of binaries using declarative logic | |
Grosse-Kunstleve et al. | Automatic Fortran to C++ conversion with FABLE | |
Sinz et al. | LLBMC: A Bounded Model Checker for LLVM’s Intermediate Representation: (Competition Contribution) | |
Haslbeck et al. | For a few dollars more: Verified fine-grained algorithm analysis down to llvm | |
Bang et al. | Smt-based translation validation for machine learning compiler | |
Schommer et al. | Embedded program annotations for WCET analysis | |
Göhringer et al. | An interactive tool based on polly for detection and parallelization of loops | |
Jang et al. | Automatic code overlay generation and partially redundant code fetch elimination | |
Arabnejad et al. | An OpenMP based parallelization compiler for C applications | |
Larsen et al. | Compiler driven code comments and refactoring | |
Jammer | Characterization and translation of OpenMP use cases to MPI using LLVM | |
Zhou | Guided automatic binary parallelisation | |
Ramanathan et al. | A case for precise, fine-grained pointer synthesis in high-level synthesis | |
WOODCOCK | FACFORMAL |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
C14 | Grant of patent or utility model | ||
GR01 | Patent grant | ||
CF01 | Termination of patent right due to non-payment of annual fee | ||
CF01 | Termination of patent right due to non-payment of annual fee |
Granted publication date: 20160309 Termination date: 20200907 |