Patent Description:
Programming languages that compile programs on a file-by-file basis may separately compile each file of the source code into object files, and then merge the separate object files into an executable file. In some examples, the compiler may employ link-time optimization (LTO) techniques to apply interprocedural optimizations to eliminate duplicate calculations, inefficient use of memory, and other optimizations to the source code as a whole. <CIT> describes that duplicative code found in modules of high level computer code can be eliminated at link-time. A compiler forms a plurality of object files from a software program in which each object file includes one or more functions associated with the software program. An analyzer examines each function to ascertain whether any of the plurality of object files include functional duplicates. In addition, call and caller routing references are determined for each of the object files and functions contained therein. Responsive to determining that a functional equivalence exists, the routing of duplicative functions is altered to reference a golden copy of the same function. Once the call and caller information has been re-routed, the duplicative function(s) is(are) deleted. <NPL>, describes that the overhead in terms of code size, power consumption, and execution time caused by the use of precompiled libraries and separate compilation is often unacceptable in the embedded world, where real-time constraints, battery life-time, and production costs are of critical importance. A link-time optimizer for the ARM architecture is presented, and peculiarities of the ARM architecture related to its visible program counter and how the introduced overhead can to a large extent be eliminated are discussed. The link-time optimizer is evaluated with four tool chains, two proprietary ones from ARM and two open ones based on GNU GCC. When used with proprietary tool chains from ARM Ltd. , the link-time optimizer achieved average code size reductions of <NUM> and <NUM>%, while the programs became <NUM> and <NUM>% faster, and <NUM> to <NUM>% more energy efficient. Finally, how the incorporation of link-time optimization in tool chains may influence library interface design is described. <NPL>, describes that the ST120 Digital Signal Processor - MicroController Unit (DSP MCU) core was designed by STMicroelectronics in order to meet the ever-increasing digital signal processing requirements of portable and consumer applications. Like other recent high-end DSP MCU cores, the ST120 blends traditional DSP features with modem Instruction-Level Parallelism (ILP) capabilities. Compiler management of the ST120 features presents a unique challenge to code generation. The ST120 Linear Assembly Optimizer (LAO) effectively exploits instruction-level parallelism, while enabling compact code size. The LAO implementation of SSA representation, IF-conversion, SLIW scheduling, and LAO improvements to register allocation are described. This includes solutions to problems that arise when compiler optimizations are applied to assembly-level, already predicated code.

A computer device is disclosed herein that comprises a processor configured to execute instructions that include a compiler configured to receive a source code for a program including at least two code files, and process the source code for the program to generate a machine-level code file for each of the at least two code files of the source code. The instructions further include a control flow graph generator configured to generate control flow graph data for each machine-level code file generated for the at least two code files of the source code. The instructions further include a machine-level intermediate representation generator configured to generate a machine-level intermediate representation for each machine-level code file using a respective machine-level code file and the generated control flow graph data for that machine-level code file. The instructions further include a machine-level intermediate representation merger tool configured to merge the machine-level intermediate representations into a merged machine-level intermediate representation. The instructions further include a machine-level optimization tool configured to perform machine-level optimizations on the merged machine-level intermediate representation and output an optimized merged machine-level intermediate representation.

Compilers typically optimize each source code file separately on a file-by-file basis, translating the source code, which may, for example, be written in C, C++, or another programming language, into an executable and linkable format (ELF) file that includes object code. At link time, a linker tool of the compiler merges all of the ELF object files into an executable file. The linking process may include resolving symbol references and relocations, as well as other processes. However, performing file-by-file compilation in this manner may potentially cause the compiler to miss the optimization opportunities that are present in the program as a whole after linking, such as cross-module inlining and other optimizations.

Compilers may implement link-time optimization (LTO) techniques to apply interprocedural optimizations to eliminate duplicate calculations, inefficient use of memory, and other optimizations to the source code as a whole. However, LTO typically requires the generation of bitcode (also called bytecode) files that are used to describe a high-level intermediate representation (IR) for each of the source code files. These bitcode files contain more information regarding the source code files than an executable and linkable format (ELF) object, or other types of executable formats. The compiler may merge the high-level IR at link-time, and performs link-time optimizations on the merged IR.

By performing the optimizations on the merged IR, the compiler may potentially identify optimization opportunities for the program as a whole that would not have been identifiable when analyzing and optimizing each file separately. The optimized merged IR may then be compiled into machine code for the executable. However, these LTO techniques require the generation of the bitcode files for the high-level IR of each source code file, which requires additional backend pipelines to be loaded by the compiler. Further, these extra bitcode files for the high-level IR are stored in memory, which causes the memory footprint to be larger during compiling. The additional code generation and optimizations that are performed for LTO will cause additional overhead that slows down the link-time process. While the additional overhead, increased memory footprint, and increased time required for linking may be acceptable for non-runtime compilation, these issues may potentially degrade the performance of just-in-time compilation that may, for example, be used for shader program compilation.

To address these issues, <FIG> illustrates a computer device <NUM> that implements a machine-level IR optimization process that may provide the potential benefit of reducing computational overhead and memory footprint for performing optimizations compared to conventional LTO techniques. As illustrated, the computer device <NUM> includes a processor <NUM> configured to execute instructions stored in memory by one or more storage devices <NUM>. The one or more storage devices <NUM> may include volatile and non-volatile memory devices. The computer device <NUM> may further include an input device <NUM>, and other suitable computer components.

The instructions executed by the processor <NUM> include program modules for a compiler <NUM>, a control flow graph (CFG) generator <NUM>, a machine-level intermediate representation generator <NUM>, a machine-level intermediate merger tool <NUM>, an optimization tool <NUM>, and an executable tool <NUM>. In one example, these program modules may be separate from each other and arranged in a pipeline to perform the functions described herein. In another example, one or more of these program modules may be integrated together. For example, the CFG generator <NUM> may be included in the compiler <NUM>, and may perform the functions of the CFG generator <NUM> described herein during execution of the compiler <NUM>.

The processor <NUM> is configured to compile source code <NUM>, which includes two or more code files <NUM>, into an executable file <NUM>, as will be discussed in more detail below. In one example, the source code <NUM> may be compiled using static compilation techniques. That is, the source code <NUM> may be compiled into the executable file <NUM> during a compile-time, and the resulting executable file <NUM> may be stored and executed at a later point in time.

In another example, the source code <NUM> may be compiled using just-in-time or dynamic compilation techniques. In this example, the compiler <NUM>, the CFG generator <NUM>, the machine-level IR generator <NUM>, the machine-level IR merger tool <NUM>, and the machine-level optimization tool <NUM>, may be included in a just-in-time (JIT) compiler with optimization program <NUM>. In contrast to static compilation, the JIT compiler with optimization program <NUM> may be configured to compile the source code <NUM> during run-time of an application program that includes the source code <NUM>. In this example, the processor <NUM> is configured to execute an application program <NUM> that generates the source code <NUM> for a program at run-time of the application program <NUM>. The processor <NUM> is further configured to execute the JIT compiler with optimization program <NUM> to compile the source code <NUM> at run-time of the application program <NUM>, including executing instructions for the compiler <NUM>, the CFG generator <NUM>, the machine-level IR generator <NUM>, the machine-level IR merger tool <NUM>, the machine-level optimization tool <NUM>, and the executable tool <NUM>.

As a specific example, the application program <NUM> may take the form of a game application or another type of application that generates code for shader programs that are compiled and executed at run-time. In this example, the source code <NUM> is for a shader program that is generated at run-time of the application program <NUM>. The source code <NUM> for the shader program is compiled by the JIT compiler with optimization program <NUM>, which generates an executable file <NUM>. The executable file <NUM> for the shader program is executed, such as, for example, by a graphics processing unit (GPU), and a result is sent back to the application program <NUM>.

In the example illustrated in <FIG>, the source code <NUM> includes at least two code files <NUM>. However, it should be appreciated that the source code <NUM> may include a larger number of code files <NUM>, such as a hundred code files, a thousand code files, etc. For example, the source code <NUM> for a shader program may include a multitude of code files <NUM> that will be compiled file-by-file into the executable file <NUM>.

In the static and dynamic compilation examples, the compiler <NUM> is configured to receive the source code <NUM> for processing. The source code <NUM> may be compiled file-by-file using a compiler pipeline <NUM> of the compiler <NUM>. An example compiler pipeline <NUM> is shown in <FIG>.

In the example illustrated in <FIG>, each code files <NUM> of the source code <NUM> is separately processed by a compiler pipeline <NUM> of the compiler <NUM>. It should be appreciated that the compiler pipeline <NUM> shown in <FIG> is merely exemplary, and that the compiler <NUM> may implement other architectures for the computer pipeline <NUM>.

Each respective code file <NUM> is processed by a front end <NUM> of the compiler <NUM>. The front end <NUM> analyzes the code file <NUM> and divides the program into core parts, and checks for syntax, grammar, lexical, and other types of errors. The front end <NUM> also generates an abstract syntax tree (AST) <NUM> for the code file <NUM> of the source code <NUM>. The abstract syntax tree <NUM> is generated to represent a structure of the program code. Typically, each node of the AST <NUM> denotes a construct occurring in the source code.

A compiler intermediate representation (IR) generator <NUM> may use the AST <NUM> to generate an IR <NUM> for the code file <NUM>. Example IR formats may include Byte Code for Java, or a language independent format such as three-address code, or another type of IR format. These IRs are typically close to the source language itself of the source code <NUM> as compared to a lower level IR that is closer to a target machine that the executable will be run on. In some examples, the IR <NUM> may take the form of a medium-level IR that is between a high-level IR and a low-level IR, and is independent of the language of the source code and the target machine that the program will be executed on.

In a link-time optimization (LTO) implementation, the IR <NUM> for each code file <NUM> of the source code <NUM> will typically be dumped into memory on a file-by-file basis. Thus, when performing LTO, an IR <NUM> for every code file <NUM> of the source code <NUM> will be dumped into memory, which will increase the memory footprint used during compilation of the source code <NUM>, and further increase resource consumption by adding an LTO pipeline <NUM> that is required to perform LTO functions. The LTO pipeline <NUM> increases the overhead of the compilation of the source code <NUM>. For example, the LTO pipeline <NUM> may require all of the IRs <NUM> for all of the code files <NUM> of the source code <NUM> to be dumped into memory along with other libraries <NUM> that may be used by those code files <NUM>. These IRs <NUM> are typically generated to be close to the source language, and have a larger memory footprint than lower-level IRs that are closer to the machine-level of the target machine. Typically, the IRs <NUM> may be optimized individually before LTO is performed.

The IRs <NUM> for each code file <NUM> of the source code <NUM> and the other libraries <NUM> are processed by a link-time IR merger <NUM> of the LTO pipeline <NUM>. The link-time IR merger <NUM> generates a merged IR <NUM> that includes code from all of the IRs <NUM>. The merged IR <NUM> is sent to a link-time optimizer <NUM> of the LTO pipeline <NUM>. The link-time optimizer <NUM> analyzes and optimizes the program as a whole, and may perform different interprocedural optimizations, such as, for example, reducing duplicate calculations, reducing inefficient use of memory, and simplifying iterative loops. The resulting optimized merged IR <NUM> may then be directly compiled into an LTO optimized executable <NUM>.

However, as discussed above, implementing LTO in this manner may increase the memory footprint used by the compiler, and requires additional overhead for the LTO pipeline <NUM> that may consume additional computer resources. These issues are increasingly detrimental for just-in-time compilation scenarios such as run-time shader program compilation and execution.

To address these issues regarding increased memory footprint and overhead caused by typical LTO implementations, the computer device <NUM> does not implement LTO, and instead implements a machine-level optimization at link-time module, which will be discussed in more detail below. Thus, the compiler <NUM> implemented by the computer device <NUM> does not store IRs <NUM> of each code file <NUM> of the source code <NUM> in memory, and does not perform link-time optimization <NUM> using the IRs <NUM> of each code file <NUM> of the source code <NUM>. As discussed above, these IRs <NUM> of the compiler are high-level IRs or mid-level IRs that are higher than machine-level, and thus have a larger memory footprint compared to machine-level IRs. Instead, the computer device <NUM> will continue with the file-by-file compilation of each code file <NUM> of the source code <NUM> using the compiler pipeline <NUM> shown in <FIG>.

The IR <NUM> for each code file <NUM> may be processed by a compiler IR optimizer <NUM> on a file-by-file basis. That is, the compiler IR optimizer <NUM> does not optimize the program as a whole, but optimizes each code file <NUM> on a file-by-file basis. However, due to processing each code file <NUM> separately, a plurality of IRs <NUM> for every code file <NUM> of the source <NUM> does not need to be dumped concurrently to memory, which will reduce the memory footprint compared to LTO techniques. The compiler IR optimizer <NUM> will typically perform higher-level optimizations related to the code itself, rather than target machine specific optimizations.

The optimized IR <NUM> is sent to a compiler machine-level IR generator <NUM>, which generates a compiler machine-level IR <NUM> for that code file <NUM>. The compiler machine-level IR <NUM> is a reduced version of the high-level IR where high-level language features are lowered to simpler constructs. The compiler machine-level IR <NUM> is low-level IR that is closer to the level of the target machine that the program will be run on.

An individual file machine-level IR optimizer <NUM> may process the compiler machine-level IR <NUM> for each code file <NUM>, and may perform optimizations that are more specific to the machine-code and the architecture of the target machine on which the program will ultimately be executed. The individual file machine-level IR optimizer <NUM> may generate an optimized compiler machine-level IR <NUM> for the code file <NUM>. The compiler pipeline <NUM> may then use a register allocator <NUM> to allocate registers for the optimized compiler machine-level IR <NUM>, and produce a final compiler machine-level IR <NUM>. The final compiler machine-level IR <NUM> may then be compiled into a machine-level code file <NUM> for that code file <NUM>, which includes operation code for the program. Each code file <NUM> of the source code <NUM> may be compiled on a file-by-file basis into respective machine-level code files <NUM>. Typically, these machine-level code files <NUM> would be linked into an executable file that would then be executed on the target machine.

However, as illustrated in <FIG>, the computer device <NUM> implements a machine-level optimization at link-time module <NUM> to perform further machine-level optimizations on the machine-level code files <NUM> at link-time. The machine-level optimization at link-time module <NUM> takes as input, a machine-level code file <NUM> for each of the code files <NUM> of the source code <NUM> that are generated by the compiler <NUM>. The machine-level optimization at link-time module <NUM> also takes as input control flow graph data <NUM> for each machine-level code file <NUM> generated for the at least two code files <NUM> of the source code <NUM>. The control flow graph data <NUM> may be generated by the CFG generator <NUM>. As discussed above, in one example, the CFG generator <NUM> may use the AST <NUM> generated by the compiler <NUM> to produce the control flow graph data <NUM>. However, it should be appreciated that the CFG generator <NUM> may implement other types of flow-sensitive analysis techniques to generate the control flow graph data <NUM>. Typically, the control flow graph data <NUM> may define edges for a set of basic blocks of code of the machine-level code files <NUM>. The control flow graph data <NUM> may define how the blocks of code are connected to one another.

Each machine-level code file <NUM> and corresponding control flow graph data <NUM> is sent to the machine-level optimization at link-time module <NUM>, which will link and optimize the files, and generate an executable file <NUM> for the source code <NUM> as a whole using an executable tool <NUM>. One example pipeline for the machine-level optimization is illustrated in <FIG>.

As shown in <FIG>, each code file <NUM> of the source code <NUM> may be compiled by the compiler <NUM> into respective machine-level code files <NUM> using the compiler pipeline <NUM> described above and illustrated in <FIG>. The CFG generator <NUM> may perform flow analysis on the final compiler machine-level IR <NUM> to generate control flow graph data <NUM> for each of the machine-level code files <NUM>.

The machine-level IR generator <NUM> of the machine-level optimization at link time module <NUM> is configured to receive the machine-level code file <NUM> for a code file <NUM>, and control flow graph data <NUM> generated by the CFG generator <NUM> for that machine-level code file <NUM>. The machine-level IR generator <NUM> may then generate a machine-level IR <NUM> for each machine-level code file <NUM> using a respective machine-level code file <NUM> and the generated control flow graph data <NUM> for that machine-level code file <NUM>.

Each machine-level code file <NUM> typically includes a plurality of operation code, which is a basic computer operation in the instruction set of the target machine. Operation code, also known as instruction machine code, instruction code, instruction syllable, instruction parcel, or opstring, specifies the operation to be performed. Operation code may also specify the data that will be processed in the form of operands. The machine-level code files <NUM> may include machine-level code that is patterned to suit the architecture of the particular processor that the code will be executed on. In some examples, the operation code may use assembly language that has a strong correspondence between the instructions in the assembly language and the architecture's machine code instructions for the processor.

To generate the machine-level IR <NUM> for each machine-level code file <NUM>, the machine-level IR generator <NUM> configured to organize the plurality of operation code of that machine-level code file <NUM> into one or more code blocks based on the generated control flow graph data <NUM> for that machine-level code file <NUM>. <FIG> illustrates an example of generating machine-level IRs using machine-level code files and control flow graph data for those machine-level code files <NUM>. As shown, each machine-level code file <NUM> may include a plurality of operation code <NUM>. However, without control flow graph data <NUM>, it would be difficult to determine how the operation code <NUM> of a first machine-level code file should be merged with the operation code <NUM> of a second machine-level code file.

As discussed above, the control flow graph data <NUM> may define edges for a set of basic blocks <NUM> of code of the machine-level code files <NUM>. The control flow graph data <NUM> may define how the blocks of code <NUM> are connected to one another, and may identify successor and terminators for each block of code <NUM>. The machine-level IR generator <NUM> may use this control flow graph data <NUM> to group sets of operation code <NUM> of the first machine-level code file <NUM> into one or more code blocks <NUM> with defined succession between the code blocks. Typically, the machine-level IRs <NUM> are generated by the machine-level IR generator <NUM> with single static assignment which requires that each variable be assigned exactly once, and that every variable is defined before it is used.

The machine-level IR generator <NUM> is configured to generate machine-level IRs <NUM> for each machine level code file <NUM> on a file-by-file basis. Typically, the machine-level code files <NUM> generated by the compiler pipeline <NUM> will have been assigned physical or hardware registers for performing the various operation code in the machine-level code file <NUM>. However, as those physical registers were allocated separately for each code file, there may be memory inefficiencies in the register allocation across the program as a whole. Thus, in one example, a virtual register allocator <NUM> may be configured to determine a plurality of physical registers that have been allocated to each of the machine-level IRs <NUM>, and assign a plurality of virtual registers for the plurality of physical registers of the machine-level IRs <NUM>. These virtual registers are temporary, and will aid in performing memory optimizations across the program of the source code <NUM> as a whole.

The set of machine level IRs <NUM> are then sent to a machine-level IR merger tool <NUM>. The machine-level IR merger tool <NUM> is configured to merge the machine-level IRs <NUM> into a merged machine-level IR <NUM>, which may include merging the one or more code blocks of each machine-level IR <NUM> with corresponding one or more code blocks of each other machine-level IR <NUM>. <FIG> illustrates an example of merging two machine level IRs <NUM> into a merged machine-level IR <NUM>. As shown, the operation code <NUM> of each machine level IR <NUM> has been organized into code blocks <NUM> using the control flow graph data <NUM> generated by the CFG generator <NUM>. The machine-level IR merger tool <NUM> may merged each code block, such as BLOCK0, BLOCK1, and BLOCK2 from each machine-level IR <NUM>. That is, the operation code <NUM> for BLOCK0 in both the first and second machine-level IRs <NUM> may be merged, such that the BLOCK0 code block of the merged machine-level IR <NUM> includes operation code <NUM> from both machine-level IRs <NUM>. This merger process may be performed for each code block <NUM> across all of the machine-level IRs <NUM>. <FIG> shows an example merged machine-level IR <NUM> generated in this manner from the example first and second machine-level IRs <NUM>.

Turning back to <FIG>, the merged machine-level IR <NUM> links the entire program of the source code <NUM> together into a single code file. Thus, whole program optimizations may be performed on the merged machine-level IR <NUM>, which may provide improved optimizations compared to the individual file optimizations performed by the compiler pipeline <NUM> discussed above. It should be appreciated that the machine-level IRs <NUM> have a smaller memory footprint, and are typically more optimized than the high-level IRs <NUM> used for LTO in <FIG>. By not performing LTO on high-level IRs, and instead optimizing a merged machine-level IR <NUM>, the computer device <NUM> may reduce the total memory footprint required for compilation, and reduce the computational overhead incurred for performing these optimizations at link time, while still achieving whole program interprocedural optimizations that increase the efficiency of the resulting executable file <NUM>.

The machine-level optimization tool <NUM> configured to perform machine-level optimizations on the merged machine-level intermediate representation and output an optimized merged machine-level intermediate representation. The machine-level optimization tool <NUM> may be configured to perform any suitable interprocedural optimization on the merged machine-level IR <NUM>, such as, for example, reducing duplicate calculations, reducing inefficient use of memory, and simplifying iterative loops.

At this point, the optimized merged machine-level IR <NUM> includes virtual registers that provide potential improvements for memory optimizations performed by the machine-level optimization tool <NUM>. However, before a working executable file may be generated, physical registers are assigned based on the virtual registers of the IR. In one example, the register allocator <NUM> is further configured to determine one or more virtual registers that have been assigned to the optimized merged machine-level IR <NUM>, and allocate one or more physical registers to the optimized merged machine-level IR <NUM> based on the determined one or more virtual registers.

The optimized merged machine-level IR <NUM> that has been allocated physical registers may then be sent to the executable tool <NUM>, which may be configured to generate an executable file <NUM> from the optimized merged machine-level IR <NUM>. As discussed above, the source code <NUM> may be code generated at run-time for a shader program. The computer device <NUM> may implement the just-in-time compiler with optimization program <NUM> described above to compile the source code <NUM> into the executable file <NUM> at run-time of the application program <NUM> that generated the shader program. The executable file <NUM> may then be run, and a result returned to the application program <NUM>. The just-in-time compiler with optimization program <NUM> described herein provides interprocedural optimizations across the program of the source code <NUM> as a whole, while achieving a lower memory footprint and computational overhead than conventional LTO techniques that perform optimizations on high-level IRs at link-time.

<FIG> shows a flowchart for an example method <NUM> for performing a machine-level IR optimization process that may provide the potential benefit of reducing computational overhead and memory footprint for performing optimizations compared to conventional LTO techniques. The follow description of method <NUM> is provided with reference to the software and hardware components described above and shown in <FIG>. It should be appreciated that method <NUM> also can be performed in other contexts using other suitable hardware and software components.

At <NUM>, the method <NUM> may include receiving a source code for a program including at least two code files. In one example, the program is a shader program that is generated at run-time of an application program, and the method <NUM> is performed at run-time of the application program that generates the source code for the program. Other program types are also possible. In this example, the method <NUM> may be implemented as a just-in-time compiler for compiling the program generated by the application program at run-time.

At <NUM>, the method <NUM> may include processing the source code for the program to generate a machine-level code file for each of the at least two code files of the source code. Step <NUM> may include using a compiler pipeline that includes a compiler front end, a high-level IR generator, a high-level IR optimizer, a mid-level IR generator, a mid-level IR optimizer, a register allocator, and other suitable software components for compiling the code files of the source code into a machine-level code file. An example of a compiler pipeline is described above with reference to <FIG>.

At <NUM>, the method <NUM> may include generating control flow graph data for each machine-level code file generated for the at least two code files of the source code. The control flow graph data may be generated based on an abstract syntax tree, or another suitable flow analysis tool generated during compilation of the code file. The control flow graph data typically may define edges for a set of basic blocks of code of the machine-level code files. The control flow graph data may define how the blocks of code are connected to one another.

At <NUM>, the method <NUM> may include generating a machine-level intermediate representation for each machine-level code file using a respective machine-level code file and the generated control flow graph data for that machine-level code file. Each machine-level code file typically includes a plurality of operation code. Step <NUM> may be performed by organizing the plurality of operation code of that machine-level code file into one or more code blocks based on the generated control flow graph data for that machine-level code file.

At <NUM>, the method <NUM> may include merging the machine-level intermediate representations into a merged machine-level intermediate representation. Step <NUM> may be performed by merging the one or more code blocks of each machine-level intermediate representation with corresponding one or more code blocks of each other machine-level intermediate representation.

At <NUM>, the method <NUM> may include performing machine-level optimizations on the merged machine-level intermediate representation and outputting an optimized merged machine-level intermediate representation. Step <NUM> may include any suitable interprocedural optimizations, such as, for example, reducing duplicate calculations, reducing inefficient use of memory, and simplifying iterative loops.

At <NUM>, the method <NUM> may include generating an executable file from the optimized merged machine-level intermediate representation. The executable file may then be executed on the computer device <NUM>.

In one example, the method <NUM> is performed without storing high-level intermediate representations of each code file of the source code in memory. Additionally, the method <NUM> is performed without performing link-time optimization using the high-level intermediate representations of each code file of the source code. An example pipeline for performing LTO using high-level IRs is shown in <FIG>. As the method <NUM> is performed without using LTO, and instead by performing interprocedural optimizations across the whole program of the source code at a machine-level, the method <NUM> provides the potential benefits of achieving a lower memory footprint and computational overhead than conventional LTO techniques that perform optimizations on high-level IRs at link-time. The lower memory footprint and computation overhead provided by method <NUM> may increase the efficiency and performance of just-in-time compilation used for shader programs and other types of programs that are compiled at run-time.

Computing system <NUM> may embody the computer device <NUM> described above and illustrated in <FIG>. Computing system <NUM> may take the form of one or more personal computers, server computers, tablet computers, home-entertainment computers, network computing devices, gaming devices, mobile computing devices, mobile communication devices (e.g., smart phone), and/or other computing devices, and wearable computing devices such as smart wristwatches and head mounted augmented reality devices.

Non-volatile storage device <NUM> may include physical devices that are removable and/or built in.

The following paragraphs provide additional support for the claims of the subject application. One aspect provides a computer device (<NUM>) comprising a processor (<NUM>) configured to execute instructions. The instructions include a compiler (<NUM>) configured to receive a source code (<NUM>) for a program including at least two code files (<NUM>), and process the source code (<NUM>) for the program to generate a machine-level code file (<NUM>) for each of the at least two code files (<NUM>) of the source code (<NUM>). The instructions further include a control flow graph generator (<NUM>) configured to generate control flow graph data (<NUM>) for each machine-level code file (<NUM>) generated for the at least two code files (<NUM>) of the source code (<NUM>). The instructions further include a machine-level intermediate representation generator (<NUM>) configured to generate a machine-level intermediate representation (<NUM>) for each machine-level code file (<NUM>) using a respective machine-level code file (<NUM>) and the generated control flow graph data (<NUM>) for that machine-level code file (<NUM>). The instructions further include a machine-level intermediate representation merger tool (<NUM>) configured to merge the machine-level intermediate representations (<NUM>) into a merged machine-level intermediate representation (<NUM>). The instructions further include a machine-level optimization tool (<NUM>) configured to perform machine-level optimizations on the merged machine-level intermediate representation (<NUM>) and output an optimized merged machine-level intermediate representation (<NUM>).

This aspect provides the potential benefits of achieving a lower memory footprint and computational overhead than conventional LTO techniques that perform optimizations on high-level IRs at link-time. The lower memory footprint and computational overhead provided by this aspect may provide the potential benefits of increased efficiency and performance of just-in-time compilation that may be used for shader programs and other types of programs that are compiled at run-time.

In this aspect, additionally or alternatively, the instructions executed by the processor may further include an executable tool configured to generate an executable file from the optimized merged machine-level intermediate representation.

This aspect provides the potential benefit of increasing efficiency in memory utilization and resource consumption of the executable by generating the executable from the optimized merged machine-level intermediate representation that has been interprocedurally optimized.

In this aspect, additionally or alternatively, the processor may be configured to execute an application program that generates the source code for the program at run-time, and the processor may be further configured to execute the instructions for the compiler, the control flow graph generator, the machine-level intermediate representation generator, the machine-level intermediate representation merger tool, and the optimization tool at run-time of the application program.

This aspect provides the potential benefit of decreasing the memory footprint associated with performing whole program optimizations, which enables the whole program optimizations to be performed during just-in-time compilation of a program.

In this aspect, additionally or alternatively, the program may be a shader program that is generated at run-time of the application program.

This aspect provides the potential benefit of improving the run-time performance of an application that includes shader programs, such as, for example, video games and other visual applications.

In this aspect, additionally or alternatively, the machine-level intermediate representations may be generated by the machine-level intermediate representation generator with single static assignment.

This aspect provides the potential benefit of improved whole program optimizations that may be performed by the machine-level optimization tool on the merged machine-level intermediate representation of the program.

In this aspect, additionally or alternatively, each machine-level code file may include a plurality of operation code.

This aspect provides the potential benefit of increasing efficiency in memory utilization and resource consumption by performing whole program optimizations for machine-level intermediate representations that include operation code for the target machine compared to conventional LTO techniques that use higher-level intermediate representations.

In this aspect, additionally or alternatively, to generate the machine-level intermediate representation for each machine-level code file, the machine-level intermediate representation generator may be configured to organize the plurality of operation code of that machine-level code file into one or more code blocks based on the generated control flow graph data for that machine-level code file.

This aspect provides the potential benefit of increasing optimization opportunities for the machine-level optimization tool to optimize the machine-level code by generating a machine-level intermediate representation.

In this aspect, additionally or alternatively, to merge the machine-level intermediate representations, the machine-level intermediate representation merger tool may be configured to merge the one or more code blocks of each machine-level intermediate representation with corresponding one or more code blocks of each other machine-level intermediate representation.

This aspect provides the potential benefit of improving the whole program optimizations that are performed by the machine-level optimization tool.

In this aspect, additionally or alternatively, the instructions executed by the processor may further include a register allocator configured to determine a plurality of physical registers that have been allocated to each of the machine-level intermediate representations, and assign a plurality of virtual registers for the plurality of physical registers of the machine-level intermediate representations.

This aspect provides the potential benefit of improved memory management optimizations that may be performed by the machine-level optimization tool.

In this aspect, additionally or alternatively, the register allocator may be further configured to determine one or more virtual registers that have been assigned to the optimized merged machine-level intermediate representation, and allocate one or more physical registers to the optimized merged machine-level intermediate representations based on the determined one or more virtual registers.

In this aspect, additionally or alternatively, the compiler does not store higher than machine-level intermediate representations of each code file of the source code in memory, and does not perform link-time optimization using the higher than machine-level intermediate representations of each code file of the source code.

Another aspect provides a method (<NUM>) comprising, at processor of a computer device, receiving (<NUM>) a source code for a program including at least two code files, processing (<NUM>) the source code for the program to generate a machine-level code file for each of the at least two code files of the source code, generating (<NUM>) control flow graph data for each machine-level code file generated for the at least two code files of the source code, generating (<NUM>) a machine-level intermediate representation for each machine-level code file using a respective machine-level code file and the generated control flow graph data for that machine-level code file, merging (<NUM>) the machine-level intermediate representations into a merged machine-level intermediate representation, and performing (<NUM>) machine-level optimizations on the merged machine-level intermediate representation and outputting an optimized merged machine-level intermediate representation.

In this aspect, additionally or alternatively, the method may further comprise generating an executable file from the optimized merged machine-level intermediate representation.

In this aspect, additionally or alternatively, the method may be performed at run-time of an application program that generates the source code for the program.

In this aspect, additionally or alternatively, generating the machine-level intermediate representation for each machine-level code file may include organizing the plurality of operation code of that machine-level code file into one or more code blocks based on the generated control flow graph data for that machine-level code file.

In this aspect, additionally or alternatively, merging the machine-level intermediate representations may include merging the one or more code blocks of each machine-level intermediate representation with corresponding one or more code blocks of each other machine-level intermediate representation.

In this aspect, additionally or alternatively, the method does not include storing higher than machine-level intermediate representations of each code file of the source code in memory, and the method does not include performing link-time optimization using the higher than machine-level intermediate representations of each code file of the source code.

Another aspect provides a computer device (<NUM>) comprising a processor (<NUM>) configured to execute an application program (<NUM>) that generates a source code (<NUM>) for a program, wherein the source code (<NUM>) includes at least two code files (<NUM>), and execute a just-in-time compiler (<NUM>) configured to compile the source code (<NUM>) for the program at run-time of the application program (<NUM>). The just-in-time compiler (<NUM>) is configured to receive the source code (<NUM>) for the program, process the source code (<NUM>) for the program to generate a machine-level code file (<NUM>) for each of the at least two code files (<NUM>) of the source code (<NUM>), generate control flow graph data (<NUM>) for each machine-level code file (<NUM>) generated for the at least two code files (<NUM>) of the source code (<NUM>), generate a machine-level intermediate representation (<NUM>) for each machine-level code (<NUM>) file using a respective machine-level code file (<NUM>) and the generated control flow graph data (<NUM>) for that machine-level code file (<NUM>), merge the machine-level intermediate representations (<NUM>) into a merged machine-level intermediate representation (<NUM>), perform machine-level optimizations on the merged machine-level intermediate representation (<NUM>) and output an optimized merged machine-level intermediate representation (<NUM>), and generate an executable file (<NUM>) from the optimized merged machine-level intermediate representation (<NUM>). The processor (<NUM>) is further configured to execute the executable file (<NUM>) compiled from the source code (<NUM>) of the program during run-time of the application program (<NUM>).

Claim 1:
A computer device (<NUM>) comprising:
a processor (<NUM>) configured to execute instructions that include:
a compiler (<NUM>) configured to receive a source code (<NUM>) for a program including at least two code files (<NUM>), and process the source code (<NUM>) for the program to generate a machine-level code file (<NUM>) for each of the at least two code files (<NUM>) of the source code (<NUM>);
a control flow graph generator (<NUM>) configured to generate control flow graph data (<NUM>) for each machine-level code file (<NUM>) generated for the at least two code files (<NUM>) of the source code (<NUM>);
a machine-level intermediate representation generator (<NUM>) configured to generate a machine-level intermediate representation (<NUM>) for each machine-level code file (<NUM>) using a respective machine-level code file (<NUM>) and the generated control flow graph data (<NUM>) for that machine-level code file (<NUM>);
a machine-level intermediate representation merger tool (<NUM>) configured to merge the machine-level intermediate representations (<NUM>) into a merged machine-level intermediate representation (<NUM>);
a machine-level optimization tool (<NUM>) configured to perform machine-level optimizations on the merged machine-level intermediate representation (<NUM>) and output an optimized merged machine-level intermediate representation (<NUM>); and
an executable tool configured to generate an executable file from the optimized merged machine-level intermediate representation.