Register allocation method and system for RISC-V microkernel compiler

By employing a multi-level intermediate representation and staged processing register allocation method in the RISC-V microkernel compiler, the problems of register overflow and hardware expansion adaptation are solved, achieving efficient register allocation and improved hardware performance.

CN123048034APending Publication Date: 2026-11-06CHINA TELECOM CORP LTD TECHNOLOGY INNOVATION CENTER +1
View PDF 0 Cites 0 Cited by

Patent Information

Application Number
CN202611382931.1
Authority / Receiving Office
CN · China
Patent Type
Applications(China)
Current Assignee / Owner
Filing Date
2026-09-07
Publication Date
2026-11-06

AI Technical Summary

Technical Problem

Existing compilers cannot effectively preserve structured control flow semantics in RISC-V microkernel scenarios through their register allocation mechanisms, leading to frequent register overflows that affect hardware performance. Furthermore, they are difficult to adapt to hardware expansion constraints, increasing development costs and performance bottlenecks.

Method used

A register allocation method employing multi-level intermediate representation and staged processing is adopted. By preserving structured loop control flow information, identifying cross-region variables, traversing basic blocks in reverse and recursively processing loop bodies, and combining the RISC-V ABI specification and hardware extension constraints, overflow-free allocation is achieved.

Benefits of technology

It reduces the complexity of register allocation algorithms, decreases memory access performance overhead, improves hardware utilization and compilation adaptation efficiency, and simplifies engineering implementation costs.

✦ Generated by Eureka AI based on patent content.

Smart Images

  • Figure CN123048034A_ABST
    Figure CN123048034A_ABST
Patent Text Reader

Abstract

This application provides a register allocation method for a RISC-V microkernel compiler, comprising: obtaining a multi-level intermediate representation corresponding to the microkernel to be compiled; excluding pre-bound and occupied registers in the multi-level intermediate representation from the initial available register pool to obtain a target available register pool; identifying cross-region variables; traversing basic blocks in reverse, saving the current state of the target available register pool, and recursively entering a loop to repeatedly execute the register allocation process; and generating RISC-V target code. By utilizing a multi-level intermediate representation that preserves the structured loop control flow, and employing a register allocation method that combines reverse traversal with recursive loop processing, complex graph analysis and register overflow problems are avoided, improving the code execution performance of RISC-V microkernel compilation, while enhancing adaptability to hardware expansion constraints. This application also provides a system with corresponding advantages.
Need to check novelty before this filing date? Find Prior Art

Description

Technical Field

[0001] This application relates to the field of computer technology, and in particular to a register allocation method and system for a RISC-V microkernel compiler. Background Technology

[0002] The fifth-generation Reduced Instruction Set Computing (RISC-V) architecture, with its open-source nature and modular extensibility, has been widely used in edge intelligent computing and heterogeneous dedicated processor acceleration. The compilation performance of neural network operators and computationally intensive microkernels directly determines the energy efficiency and peak utilization of edge hardware. The register allocation stage in the compiler backend, responsible for mapping virtual variables in the intermediate representation to physical registers, is a crucial step connecting high-level abstractions and low-level hardware. Its allocation strategy directly affects the memory access overhead and hardware unit utilization during program execution.

[0003] Current general-purpose compilers' register allocation mechanisms are mostly based on unstructured intermediate representations, relying on control flow graph analysis and heuristic overflow strategies to complete resource mapping. In high-performance microkernel scenarios, these mechanisms have several limitations. During the downgrade from high-level domain-specific languages ​​to low-level intermediate representations, semantic information such as structured control flow (e.g., nested loops) and implicit hardware memory access is gradually lost, making it impossible to leverage high-level semantics to unlock hardware optimization potential. When register pressure increases, existing allocation mechanisms lack the precision to calculate variable lifetimes, easily triggering overflow operations due to premature register resource insufficiency. Temporarily storing data in memory introduces additional memory access latency, especially when overflow occurs in loop hotspots, significantly reducing the execution efficiency of floating-point units and making it difficult to approach peak hardware performance. Various hardware extensions in fifth-generation RISC architectures have customized requirements for register usage rules and structured loop constraints. General-purpose allocation mechanisms struggle to express these domain-specific constraints, often requiring developers to rely on hand-written assembly or dedicated function libraries for optimization, increasing development costs and reducing code portability. The step-by-step conversion process of multi-layer intermediate representations continuously weakens domain-specific optimization information. The register allocation stage cannot directly map high-level abstractions such as linear algebra iteration space to low-level hardware characteristics, further exacerbating the semantic gap between software and hardware and forming a performance bottleneck.

[0004] Existing register allocation optimization schemes for fifth-generation reduced instruction set architectures (RISC) focus on improving binary code density and end-to-end microkernel code generation. However, none have yet developed a practical, overflow-free register allocation implementation specifically for the loop-based structured characteristics of computationally intensive microkernels. How to achieve efficient register allocation in microkernel scenarios while preserving structured control flow semantics, reducing overflow memory access overhead, and adapting to various hardware extension constraints is a pressing technical challenge in the field of RISC microkernel compilation.

[0005] It is evident that there is an urgent need to develop a register allocation method and corresponding system for RISC-V microkernel compilers. Summary of the Invention

[0006] To address all or part of the problems in the prior art, this application presents a register allocation method and system for RISC-V microkernel compilers. It provides an overall solution for register allocation based on multi-level intermediate representations and phased processing of loop and linear code, ensuring that the structured loop control flow information of the multi-level intermediate representations is not lost, avoiding register overflow, adapting to hardware expansion constraints, and realizing reliable register allocation in microkernel scenarios.

[0007] Firstly, this application discloses a register allocation method for a RISC-V microkernel compiler, comprising: obtaining a multi-level intermediate representation corresponding to the microkernel to be compiled, wherein the multi-level intermediate representation retains structured loop control flow information; executing a register allocation process, comprising: delineating an initial available register pool according to the RISC-V application binary interface specification, excluding registers pre-bound and occupied in the multi-level intermediate representation from the initial available register pool to obtain a target available register pool; identifying cross-region variables defined outside the loop region and used inside the loop region within the multi-level intermediate representation, and establishing a tracking record for the cross-region variables; and traversing the register allocation process in reverse order. When a loop structure is encountered in the basic block of the multi-level intermediate representation, the traversal of the current basic block is paused. Registers are first allocated for the cross-region variables, and the available range of the registers of the cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the loop body is recursively entered to repeat the register allocation process. After the recursion returns, the state of the target available register pool is restored. For non-loop linear basic blocks in the basic block, registers are allocated at the first point of use of the variable in reverse order, and registers are released at the last point of use of the variable. The RISC-V target code is generated based on the final register allocation result.

[0008] In some embodiments, the initial available register pool includes caller-stored integer registers and caller-stored floating-point registers as determined in accordance with the application binary interface specification.

[0009] In some embodiments, before identifying the cross-region variables, the control flow region of the multi-level intermediate representation is analyzed and the loop region boundaries are marked.

[0010] In some embodiments, when the loop structure is scanned, the loop's iteration operands and the loop body's block parameters are assigned to the same register.

[0011] In some embodiments, when the recursion enters the loop body, the loop body is treated as an independent register allocation unit, and the register allocation process is executed.

[0012] In some embodiments, the structured loop control flow information includes structured control flow semantics corresponding to linear algebra computation, wherein the structured control flow semantics originates from the front-end compilation output for linear algebra computation.

[0013] In some embodiments, prior to the register allocation process, a cyclic transformation and scheduling constraint are performed to constrain the total register requirement to within the number of physical registers.

[0014] In some embodiments, the method further includes: reading declarative hardware constraints stored in the multi-level intermediate representation and adding an occupancy flag to the register based on the declarative hardware constraints.

[0015] Secondly, this application discloses a register allocation system for a RISC-V microkernel compiler, which executes the method shown in one aspect of this application; the system includes: an intermediate representation acquisition module, a register pool preprocessing module, a cross-region variable identification module, a register allocation scanning module, and a code generation module; the intermediate representation acquisition module is configured to acquire a multi-level intermediate representation corresponding to the microkernel to be compiled, wherein the multi-level intermediate representation retains structured loop control flow information; the register pool preprocessing module is connected to the intermediate representation acquisition module and the register allocation scanning module respectively, and is configured to delineate an initial available register pool according to the RISC-V application binary interface specification, exclude registers pre-bound and occupied in the multi-level intermediate representation from the initial available register pool, and output the target available register pool to the register allocation scanning module; the cross-region variable identification module is connected to the intermediate representation acquisition module and the register allocation scanning module respectively, and is configured to identify... The multi-level intermediate representation defines cross-region variables defined outside the inner loop region and used inside the loop region. Tracking records for these cross-region variables are established and output to the register allocation scanning module. The register allocation scanning module is configured to traverse the basic blocks of the multi-level intermediate representation in reverse order. When a loop structure is encountered, the traversal of the current basic block is paused. Registers are first allocated for the cross-region variables, and the available range of the registers for these cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the module recursively enters the loop body to perform register allocation. After recursion returns, the state of the target available register pool is restored. For non-looping linear basic blocks within the basic blocks, registers are allocated at the first point of use of the variable in reverse order, and released at the last point of use. The code generation module is connected to the register allocation scanning module and is configured to generate RISC-V target code based on the final register allocation result.

[0016] In a specific embodiment, the register allocation scanning module is configured to allocate the loop's iteration operands and the loop body's block parameters to the same register when the loop structure is scanned.

[0017] Thirdly, this application discloses an electronic device comprising: a processor; and a memory for storing processor-executable instructions; wherein the processor is configured to perform the method as described in any of the preceding aspects.

[0018] Fourthly, this application discloses a non-transitory computer-readable storage medium in which, when the instructions in the storage medium are executed by a processor of an electronic device, enable the electronic device to perform the methods described in any of the preceding aspects.

[0019] Fifthly, this application discloses a computer program product in which, when the instructions in the computer program product are executed by a processor of an electronic device, the electronic device is enabled to perform the method described in any of the preceding aspects.

[0020] The technical solution provided in this application may include the following beneficial effects: This application provides a register allocation method for RISC-V microkernel compilers, which reduces the complexity and runtime overhead of register allocation algorithms. The allocation process does not require complex control flow graph analysis and heuristic overflow decisions, resulting in more predictable behavior. It relies on structured semantics to achieve precise control over variable lifetimes, thereby eliminating the memory access performance loss caused by register overflows and stably releasing the computational peak of the microkernel. At the same time, it establishes a mapping link from high-level domain semantics to low-level hardware characteristics, improving the compilation and adaptation efficiency of RISC-V customized extensions.

[0021] This application provides a register allocation system for RISC-V microkernel compilers, which adopts a layered and decoupled modular architecture with clear boundaries of responsibility for each functional unit. This facilitates targeted iteration, debugging, and maintenance for different RISC-V hardware extensions. The overall architecture can be directly embedded into existing compiler backend systems, significantly reducing the engineering implementation and scenario adaptation costs of this overflow-free register allocation mechanism. Attached Figure Description

[0022] Figure 1 This is a schematic diagram of a register allocation method for a RISC-V microkernel compiler according to an embodiment of this application. Figure 2 This is a schematic diagram illustrating the workflow of a register allocation method for a RISC-V microkernel compiler according to an embodiment of this application.

[0023] Figure 3This is a flowchart illustrating the steps of a register allocation method for a RISC-V microkernel compiler according to an embodiment of this application.

[0024] Figure 4 This is a block diagram of a register allocation system for a RISC-V microkernel compiler according to this application. Detailed Implementation

[0025] The technical solutions of the embodiments of this application will be clearly and completely described below with reference to the accompanying drawings. Obviously, the described embodiments are only some embodiments of this application, not all embodiments. Based on the embodiments of this application, all other embodiments obtained by those skilled in the art without creative effort are within the scope of protection of this application.

[0026] In the compilation of deep learning operator microkernels for RISC-V architecture, such as highly loop-intensive computational tasks like convolution, matrix multiplication, and attention operators, the compilation link often generates multi-level intermediate representations from a specific dialect of linear algebra. These intermediate representations retain the structured information of multi-layered nested loops. If a traditional flat register allocation process is used, loop boundaries and cross-loop variable information are easily lost after intermediate representation conversion, making it difficult to accurately identify cross-region variables defined outside the loop and frequently used inside the loop, and easily triggering unnecessary register overflows inside hot loops. The same contradiction also appears in high-performance scientific computing operator microkernels such as matrix factorization, fast Fourier transform, and iterative solution of linear equations. Deeply nested loop structures allow a large number of array temporary variables to survive across multiple loops, making it difficult to accurately define their survival range under flat intermediate representations. In contrast, in digital signal processing and communication baseband operation microkernel scenarios such as filtering and channel demodulation, there are often long-resident iterative state variables, and some RISC-V baseband extension instructions affect iteration. The storage location of registers for parameters and loop parameters has special constraints, and traditional allocation strategies lack an entry point for collaborative allocation based on structured loop information. In real-time kernels such as robot motion control loops and industrial sensor data stream processing, loops are high-frequency, never-ending periodic iterations, and the lifetime of cross-loop variables covers the entire loop execution interval. Once a register overflow occurs, the additional memory access overhead will bring unpredictable latency jitter. In ray tracing tile rendering and finite element fluid simulation iterative calculations, the number of loop iterations is huge, and block boundary parameters and iteration state variables need to be maintained in the loop for a long time. Flattening processing is prone to underestimating the variable survival interval and incorrectly releasing registers. The multi-layered loop vector operation code automatically vectorized by the compiler itself fully retains the structured loop semantics produced by the front end. The traditional register allocation process, after flattening the loop hierarchy, is very likely to destroy the variable-register mapping relationship pre-planned by the front end. The above-mentioned series of unique problems caused by dense loops, multi-layer nesting, hardware extension constraints, high-level structured semantic links, and real-time latency sensitivity all need to be effectively solved.

[0027] The solutions provided in this application through embodiments are applicable to various compilation scenarios under the RISC-V architecture: In edge AI accelerator inference libraries, register allocation can be performed on multi-level intermediate representations of multi-layer nested loops of convolution operators, identifying cross-loop variables such as image block parameters and defining their register occupancy range, reducing the possibility of register overflow in hot loops within convolution layers; In RISC-V scientific computing math libraries, it can be used for the compilation and processing of matrix multiplication and LU decomposition iterative microkernels, handling deeply nested loops, distinguishing cross-layer surviving array temporary variables, and allocating loop body register resources recursively to reduce the problem of long-lived iterative variables being released prematurely; In RISC-V software radio baseband platforms, register allocation can be completed for FIR filtering and carrier demodulation loop microkernels, relying on structured loop information to perform coordinated register allocation for iterative state variables and loop parameters, adapting to register constraints brought by baseband hardware extension instructions; In RISC-V-based servo controller firmware, for The high-frequency, periodically running position-closed-loop control loop microkernel performs register allocation, maintaining register occupancy for cross-loop variables such as control parameters, reducing latency jitter caused by overflow memory access, and improving the predictability of control loop execution time. In the edge-side real-time rendering engine, allocation processing is performed for the tile traversal loop and ray intersection calculation microkernels, setting register survival intervals for cross-loop variables such as tile boundary parameters and traversal indices, alleviating the high register pressure on inner rendering loops. In RISC-V industrial simulation programs, it can be used for compiling fluid and stress simulation iterative convergence loop microkernels, identifying simulation state variables that survive long-term during multiple iterations, reducing the probability of register release due to misjudgment in flattened lifecycle analysis. In specific embodiments, it can also be used with an automatic vectorization compiler for RISC-V to perform register allocation on multi-layered loop vector operation code generated by linear algebra-specific languages, preserving the structured loop semantics of the front-end output and avoiding disruption of pre-planned variable-register mapping relationships. Specific application scenarios are not limited here.

[0028] To better understand this application, and without limiting it in any way, some terms used in the embodiments are explained by way of example as follows: RISC-V (Reduced Instruction Set Computing): An open-source and free instruction set architecture based on RISC principles, whose modular design allows for free use and modification.

[0029] DSL (Domain-Specific Language): A computer language designed for a specific application domain, aiming to significantly improve the development efficiency of related software by abstracting and simplifying the concepts of that domain.

[0030] Intermediate Representation (IR): A machine-independent intermediate representation generated by the compiler between the source code and the target code, used for optimization and analysis.

[0031] xPU (Processing Unit): A hardware processor designed specifically for a particular computing domain (such as graphics and AI), which greatly improves energy efficiency and performance through heterogeneous computing.

[0032] ABI (Application Binary Interface): A binary-level specification that defines how programs interact with the system and other programs; the rules for using registers are a key part of it.

[0033] SSA (Static Single Assignment): A compiler intermediate representation in which each variable is assigned a value only once. It uses the φ function to handle the confluence point, greatly simplifying optimization analysis.

[0034] CFG: Control-Flow Graph, a graph structure used in compilers to represent the jump logic of program execution, consisting of basic blocks and jump edges; it is a commonly used intermediate representation structure in the backend of existing traditional compilers.

[0035] FPU: Floating-Point Unit, a functional unit in a hardware processor dedicated to floating-point arithmetic operations.

[0036] Spilling: Overflow, a technical term in the field of register allocation, refers to the process of transferring the corresponding data of the virtual register to the memory stack space when physical register resources are insufficient; in the embodiment, no overflow means that the data transfer to memory operation is not performed.

[0037] Linalg: Linear Algebra Dialect, a high-level domain dialect (DSL) for compilers oriented towards linear algebra operations. It is used to express computational operators such as matrices and convolutions, and serves as the front-end input source for the compiler in the implementation example.

[0038] a0~a7: The integer parameter register numbers stored by the caller in the RISC-V architecture, which are general-purpose integer registers defined by the ABI specification.

[0039] t0~t6: The RISC-V architecture caller stores the temporary integer register numbers, which are general-purpose integer registers defined by the ABI specification.

[0040] fa0~fa7: RISC-V architecture caller stores floating-point parameter register numbers, which belong to the floating-point registers defined by the ABI specification.

[0041] ft0~ft11: RISC-V architecture callers store floating-point temporary register numbers, which belong to the floating-point registers defined by the ABI specification.

[0042] s-reg (s0-s11): Saved Register, defined by the RISC-V ABI specification, is a register that the callee needs to save and restore when a function is called.

[0043] IoT: Internet of Things (IoT) refers to smart hardware devices on the IoT edge that are equipped with RISC-V chips.

[0044] HPC: High-Performance Computing, refers to high-performance computing nodes at the edge.

[0045] φ function: Phi function, a pseudo-operation used in SSA (Static Single Assignment) intermediate representation to handle the assignment of variables at the junction of multiple control flow branches.

[0046] refer to Figure 1The register allocation method for a RISC-V microkernel compiler provided in a specific embodiment includes: obtaining a multi-level intermediate representation corresponding to the microkernel to be compiled, wherein the multi-level intermediate representation retains structured loop control flow information; executing a register allocation process S; and generating RISC-V target code based on the final register allocation result. The execution of the register allocation process S includes: performing a register pool preprocessing step on the multi-level intermediate representation; performing a cross-region variable identification step on the multi-level intermediate representation; and performing a register allocation scanning step on the multi-level intermediate representation. Specifically, the register allocation process S includes: defining an initial available register pool according to the RISC-V application binary interface specification; excluding pre-bound registers in the multi-level intermediate representation from the initial available register pool to obtain the target available register pool; identifying cross-region variables defined outside the loop region and used inside the loop region within the multi-level intermediate representation, and establishing tracking records for the cross-region variables; traversing the basic blocks of the multi-level intermediate representation in reverse order, distinguishing between loop structures and non-loop linear basic blocks during the traversal process: when a loop structure is scanned, traversing the current basic block is paused, registers are allocated for the cross-region variables first, and the available range of the registers for the cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the process recursively enters the loop body to repeat the register allocation process. After recursion returns, the state of the target available register pool is restored; for non-loop linear basic blocks in the basic blocks, registers are allocated at the first point of use of the variable and released at the last point of use of the variable in reverse order.

[0047] This embodiment targets a computationally intensive microkernel based on the RISC-V architecture. It uses a multi-level intermediate representation that preserves complete structured loop control flow information as its processing base, constructing a register allocation and execution process without overflow. The process first defines an initial available register pool according to the RISC-V ABI specification, removing pre-bound and occupied registers to complete register resource preprocessing. Then, it identifies cross-region variables defined outside the loop and used inside the loop, establishing tracking records. The allocation phase employs a reverse traversal combined with recursive nesting processing logic. When a loop structure is encountered, registers are allocated preferentially for cross-region variables, extending their lifetime to cover the entire loop execution interval. After saving the current register pool state, the process recursively enters the loop body to execute the complete allocation process. Upon recursive return, the register pool state is restored. For non-looping linear code blocks, the rule of allocating registers at the first use point and releasing them at the last use point is followed under the reverse traversal order, achieving time-sharing multiplexing of registers. It abandons the complex control flow graph analysis and heuristic overflow strategies that traditional register allocation relies on. Instead, it accurately calculates variable lifetimes by relying on the structured semantics preserved by multi-level IR. It can combine pre-loop transformation and scheduling to constrain the total register demand from the source, while being compatible with declarative constraints of hardware extensions. It achieves deterministic overflow-free allocation in microkernel scenarios and is deeply adapted to the register specifications and domain hardware extension characteristics of the RISC-V architecture.

[0048] refer to Figure 2 This illustrates a three-round register allocation workflow in a specific embodiment. In this embodiment, after the initial setup, the first round of traversal is performed: all registers already used in the In-Registry (IR) are excluded from the caller-saved registers. This corresponds to the register pool preprocessing stage, where the ABI-defined set of caller-saved registers is defined as a candidate resource pool. Registers pre-bound by function parameters and hardware constraints in the multi-level IR are scanned, and pre-occupied registers are removed to obtain the target available register pool. This round of traversal only filters register resources and does not perform variable allocation. The initial available register pool in the example includes caller-saved integer registers and caller-saved floating-point registers.

[0049] The second round of traversal tracks variables defined outside the reference region for use in subsequent loop processing. This corresponds to the cross-region variable identification stage. It traverses multi-level IR control flow regions, marking the boundaries of each loop region; identifies cross-region variables defined outside the loop but used inside, and establishes a dedicated tracking list to store variable identifiers, variable types, definition locations, usage locations, and loop hierarchy information, providing input for subsequent loop processing. This round of traversal only performs variable analysis and recording; it does not perform actual register allocation.

[0050] The third round of traversal: Traverses the intermediate representation in reverse and allocates values ​​locally. Registers are allocated upon first use and released upon definition. Register allocation is completed locally using a reverse traversal of the IR basic blocks: upon encountering a loop structure, the current basic block scan is paused, and the cross-region variable tracking list generated in the second round of traversal is read first to complete the cross-region variable register allocation, extending the register lifetime to cover the entire loop execution interval; the state of the available register pool is saved, and the loop body is recursively entered. The entire three-round traversal logic is reused within the loop body, and the original state of the register pool is restored after the loop body is processed. During loop processing, it is ensured that the loop iteration operands and loop body block parameters use the same physical register.

[0051] For linear non-loop code, the operation is traversed in reverse order. The first time a variable is used, a physical register is allocated. The last time a variable is used, the register is released. After the register is released, it is returned to the target available register pool for reuse.

[0052] In this embodiment, the traversal process synchronously reads the declarative hardware constraints carried by the IR and adds an occupied flag to the dedicated registers required by the hardware.

[0053] After all three rounds of traversal are completed, the complete register allocation mapping relationship is obtained and output to the code generation stage to generate RISC. V. Target machine code, assembly code.

[0054] Reference Figure 3 This document illustrates the complete execution steps within the register allocation process in a specific embodiment, providing a detailed example of the register allocation process. In this specific embodiment, the compiler's internal function `allocate` is used as the top-level entry point, and the entire set of processing logic is executed, including reserved registers, exclusion of pre-occupied registers, loop region analysis, cross-region variable identification and recording, reverse IR traversal, loop priority processing, cross-region variable register allocation, loop body recursive processing, linear code block allocation, and hardware extension constraint resolution. The complete execution steps of this embodiment are as follows: Step 1. Initialize the ABI-compliant register candidate pool. Based on the caller-saving rules specified by the RISC-V architecture application binary interface, class A and class T registers in the integer field, and class FA and class FT registers in the floating-point field are collected to construct an initial candidate register set, which serves as a candidate pool for subsequent dynamic resource allocation.

[0055] Step 2. Remove pre-occupied register resources. Scan all operation nodes of the multi-level intermediate representation, identify physical registers that have been statically bound due to function parameter binding, hardware special function binding, etc., remove these registers from the candidate register set, and output a pool of available registers for dynamic scheduling.

[0056] Step 3. Parse the control flow region structure of the multi-level intermediate representation. Traverse the region tree structure of the intermediate representation, identify all loop instances within the program, and parse out structured information such as the boundary range and loop body coverage area of ​​each loop, providing a basic context for cross-loop variable analysis.

[0057] Step 4. Identify variables that survive across loop boundaries. Based on the parsed loop boundary information, filter out a special type of variable: the instantiation and definition of this type of variable occurs outside the loop boundary, but the reading and use of the variable occur inside the loop body. This type of variable is called a cross-boundary variable.

[0058] Step 5. Construct a cross-region variable tracking list. All cross-region variables identified above are collected into an independent tracking list. Each list entry records metadata such as the variable's unique identifier, the loop hierarchy it belongs to, the variable's definition location, and the variable's reference point. This list is used by subsequent loop processing logic for reading and calling.

[0059] Step 6. Traverse the multi-level intermediate representation in reverse order and prioritize loop instances. Traverse the operation sequence of the intermediate representation in reverse order; once a loop-type operation node is detected, including general for loops and hardware-specific loop primitives adapted for hardware acceleration, immediately interrupt the scanning process of the current basic block and prioritize the processing of that loop instance. During loop processing, assign the same physical register to the loop iteration input operands and the loop body entry block parameters to ensure the semantic consistency of the SSA intermediate representation and eliminate unnecessary data movement instructions within the iteration process.

[0060] Step 7. Complete register assignment for cross-region variables. Read the variable entries belonging to the current loop level from the tracking list, and allocate the corresponding physical register for each cross-region variable from the available register pool. Considering the running characteristic of loops that will undergo multiple rounds of iteration, set lifetime constraints on the allocated registers to ensure that they effectively cover the entire execution range of the loop, avoiding variable data overwriting errors caused by register reuse during loop iteration.

[0061] Step 8. Recursively isolate the allocation logic within the loop body. The allocator's processing logic is recursively called to enter the loop body and perform allocation operations. Within the recursive call context, the entire loop body is treated as an independent register allocation unit, achieving isolation between the allocation states inside and outside the loop. Before initiating recursion, a snapshot of the currently available register pool is saved; after all allocation logic within the loop body is executed and returns, the snapshot-recorded register pool state is restored, thereby achieving isolation and reuse of register resources inside and outside the loop.

[0062] Step 9. Register Scheduling within Linear Basic Blocks. For sequentially executed code segments that do not contain loops, establish scheduling rules: release the registers occupied by a variable when its lifetime ends (i.e., when its last reference occurs); allocate register resources at the point where the variable is instantiated. Perform register allocation and deallocation operations on each variable within the sequential code segment one by one in reverse traversal order.

[0063] Step 10. Parse the declarative constraints of hardware extensions. When traversing and processing the hardware extension operations corresponding to the xPU accelerator (such as hardware loop execution primitives), read the declarative hardware constraints attached to the IR operation nodes; based on the parsed constraint information, mark the occupancy status of specific physical registers, reserve corresponding register resources for hardware-specific functions, and ensure that the output register allocation results meet the usage restrictions of the target hardware.

[0064] After all sub-steps have been executed, the complete mapping relationship between virtual registers and physical registers is generated and output. The pseudocode example for this embodiment is as follows: function allocate(ir_function): int_regs = [a0..a7, t0..t6] # 15 integer registers fp_regs = [fa0..fa7, ft0..ft11] # 20 floating-point registers # Step 1: Reserve and Exclude exclude_preallocated_registers(int_regs, fp_regs) # Step 2: Identify cross-regional variables external_vars = find_external_variables(ir_function) # Step 3: Backward linear scan backward_scan(ir_function.blocks, int_regs, fp_regs, external_vars) function backward_scan(blocks, int_regs, fp_regs, external_vars): for block in reverse(blocks): for op in reverse(block.operations): if is_loop(op): # Recursive processing loop allocate_loop_args(op, int_regs, fp_regs) allocate_external_vars(op, external_vars, int_regs, fp_regs) # Save the state and recursively enter the loop body saved_regs = (int_regs.copy(), fp_regs.copy()) exclude_used_registers(int_regs, fp_regs) backward_scan(op.body_blocks, int_regs, fp_regs, []) int_regs, fp_regs = saved_regs else: # Allocate registers for operands (using dots) for operand in op.operands: if needs_register(operand): allocate_reg(operand, int_regs, fp_regs) # Allocate registers (definition points) for the results For the result in op.results: if needs_register(result): allocate_reg(result, int_regs, fp_regs) # Release operand registers at the point of definition for operand in op.operands: if is_last_use(operand): free_reg(operand, int_regs, fp_regs) The pseudocode for the example is explained in detail below: The top-level function `allocate` initializes the register pool, removes pre-occupied registers, and retrieves cross-region variables. Then, it calls `backward_scan` to perform a reverse scan. `backward_scan` traverses all basic blocks and their operations in reverse order; it determines if the current operation is a loop operation: if so, it performs loop parameter allocation, cross-region variable allocation, saves a snapshot of the register pool, recursively calls `backward_scan` to process the blocks within the loop body, and recursively returns to restore the register pool snapshot; if it is a normal operation, it performs operand allocation, result allocation, and releases the register when the variable is detected as being used for the last time. Hardware extension constraint query processing is embedded within the scan loop; each parsed hardware extension operation completes the corresponding register occupancy marking.

[0065] In a specific embodiment, the structured loop control flow information, in addition to basic loop nesting and iteration boundary information, may also include structured control flow semantics corresponding to linear algebra computations derived from the front-end compilation output for linear algebra computations. In this embodiment, the multi-level intermediate representation fully inherits high-level semantics such as iteration space dimensions, data access patterns, and computation operator types from the linear algebra domain dialect output. The register allocation processing logic is no longer limited to low-level control flow analysis but can also adjust the allocation strategy based on domain-level computational characteristics. For microkernels with fixed computational paradigms such as matrix multiplication and convolution, the register allocation scanning module can predict register pressure based on inherited iteration space information and prioritize allocating physical registers for core multiply-accumulate operation variables; for hardware operations with implicit memory access, address registers can be reserved in advance based on data access characteristics to reduce the consumption of register resources by address calculations. At the same time, the computation block information obtained from the front end can be passed down to the register allocation stage to adapt the block size to the physical register hardware specifications, further improving computational execution efficiency. This end-to-end semantic transfer link makes register allocation no longer an isolated processing step in the compiler backend, enabling deep integration with frontend domain-specific language optimization logic and improving the problem of general compilers being insensitive to domain-specific computing patterns.

[0066] In some embodiments, to ensure that register overflow is avoided throughout the register allocation process, loop transformation and scheduling can be performed in the compiler before the register allocation process begins, constraining the total register requirements of the microkernel to within the number of physical registers in the hardware. This processing is a pre-processing guarantee in the register allocation process and does not participate in the specific allocation of register resources. It reduces peak register usage through mid-compilation program transformation. Specifically, various transformation methods can be used: when too many coexisting variables in a single loop cause excessive register pressure, loop splitting is performed, dividing the large loop into several smaller loop segments to reduce the number of variables surviving simultaneously in a single loop; the loop unrolling factor is adjusted based on the actual number of hardware registers to prevent over-expansion and register resource overdraft; instruction reordering can also be used to adjust the order of operations, shorten the variable lifetime, and promote earlier register release and reuse; for linear algebra calculation scenarios, the size of the computation block is adjusted to ensure that all intermediate data of a single computation block is contained in physical registers, reducing memory access during runtime. After the above mid-level constraint processing, there are always enough available physical registers in the back-end register allocation stage. There is no need to introduce the traditional overflow write-back memory logic, which simplifies the back-end algorithm and eliminates the performance loss caused by overflow. It is especially suitable for microkernel compilation scenarios with regular computing patterns.

[0067] In a preferred embodiment, the register allocation process is also compatible with various custom RISC-V hardware extensions and xPU-specific accelerators. The multi-level intermediate representation stores declarative hardware constraints corresponding to hardware operations. During register allocation, these constraints are read to mark the corresponding registers as occupied. These declarative hardware constraints include several types: first, dedicated register constraints, which specify that a particular operation must use a physical register with a designated number, such as a hardware loop counter register or a DMA address configuration register; second, register grouping constraints, which limit the input and output of an operation to a specific register group, often used in vector extension architectures; and third, register alignment constraints, which impose alignment requirements on register numbers. When the register allocation scanning module traverses IR operation nodes, if it encounters a hardware extension operation carrying the aforementioned declarative constraints, it prioritizes marking the corresponding register as occupied according to the constraint, excluding it from the dynamic available register pool, and then allocates the remaining available registers for the remaining operands of the operation. Based on this processing method, adapting to different RISC-V hardware extension specifications does not require modification of the main register allocation algorithm; only the constraint descriptions at the intermediate representation level need to be supplemented, improving the compiler toolchain's extensibility and the portability of the generated code.

[0068] In a preferred embodiment, regarding the register pool preprocessing stage, in compilation scenarios where the microkernel is not a leaf function, contains sub-function calls, or experiences high overall register pressure, some callee-saved registers can be included in the initial available register pool. A context-saving instruction for the corresponding register is added at the function entry point, and a register restoration instruction is added at the function exit point, enabling safe reuse of callee-saved registers and thus expanding the total amount of dynamically allocated available registers. Furthermore, usage priorities can be set for each register in the register pool, prioritizing the allocation of high-priority temporary registers and reserving parameter registers for function calls as much as possible, reducing the overhead of additional data copying during function calls. For RISC-V extended hardware supporting multiple data bit widths, independent register sub-pools can also be divided according to data type. Different types of variables are only allowed to select resources within their corresponding sub-pools, avoiding resource waste caused by mixing registers of different bit widths. This is not a limitation.

[0069] In some embodiments, for the cross-region variable identification stage, when the multi-level intermediate representation to be processed contains a small number of incompletely structured fragments that cannot be fully resolved by relying solely on the loop region tree, a dominance tree and a nested loop tree of the program control flow graph can be constructed, combined with loop invariant analysis logic to identify cross-region variables. Alternatively, data flow analysis can be used to solve for the complete lifetime intervals of all variables, and the coverage relationship between the variable lifetime intervals and the loop region boundaries can be compared. If the variable lifetime crosses the loop boundary, it is determined to be a cross-region variable. This method can obtain the precise start and end points of the variable, facilitating more precise control over the register lifetime. Furthermore, the cross-region variable identification logic can be moved forward to the IR degradation stage in the compiler, where the upper-level optimization stage directly completes the variable marking. The marking information is passed down to the back-end register allocation module along with the multi-level intermediate representation, eliminating the need for repeated analysis and calculation at the back-end, reducing the computational overhead of the back-end compilation stage, and making it suitable for scenarios with high compilation speed requirements.

[0070] In some embodiments, basic blocks are traversed in the forward execution order of the program, physical registers are allocated at variable definition points, and registers are released and reclaimed at the last usage point of the variable. Although the traversal direction is reversed, the variable lifetime is still accurately captured by the SSA attribute, maintaining linear time complexity and adapting to third-party compilation frameworks accustomed to forward traversal logic. For large-scale microkernel programs, the program can be partitioned according to loop regions, with each program partition performing independent linear scan allocation. The partitions are connected by variable lifetime extension, breaking down large-scale allocation tasks into several small-scale subtasks and reducing the complexity of single-processing operations. For minimal microkernels with simple logic containing only sequentially executed statements, a forward greedy allocation strategy can be adopted, allocating registers sequentially according to the order of variable definition, and directly outputting a compilation warning when the available registers are exhausted. The implementation code of this embodiment is simple in logic and has a fast compilation speed, making it suitable for lightweight compilation environments with extremely limited resources.

[0071] In a preferred embodiment, besides implementing loop body isolation allocation through function recursion, an explicit stack iterative processing scheme can also be used for the loop body processing logic. A custom stack structure is maintained in memory, storing context information such as the register pool state and cross-region variable sets during each loop processing level. Allocation processing for each nested loop is completed iteratively, eliminating reliance on function recursion and avoiding the risk of call stack overflow caused by function recursion when the loop nesting level is too deep. This is suitable for computational microkernels with deeply nested loops. Alternatively, a top-down allocation approach can be adopted, assigning registers layer by layer from the outermost loop inwards. Registers allocated by the outer loop are visible to the inner loops throughout their allocation, and the inner loops only process their own local variables. This implementation is intuitive, easy to debug, and suitable for scenarios with simple and regular loop nesting levels. Recursive isolation can also be abandoned by pre-calculating the lifetime range of all variables globally, uniformly extending the lifetime of cross-loop variables, and then performing a single global linear scan to complete the allocation. This eliminates recursion-related logic, simplifies code implementation, and is suitable for compilation scenarios with fewer loop levels. Specific situations are not limited here.

[0072] In some embodiments, a register partitioning reservation approach is adopted, pre-allocating dedicated register partitions for different loop levels. Each loop level is only allowed to use the register resources within its own partition, thus avoiding insufficient register resources from the resource allocation level. This approach has lower requirements for mid-compilation optimization capabilities and is suitable for hardware platforms with abundant physical register resources. For hard real-time applications, the peak demand for microkernel registers can be statically pre-calculated before formal allocation. If the peak demand is determined to exceed the total number of physical registers, a compile-time error is directly thrown, prompting developers to adjust the microkernel code. This exposes the register pressure issue during the compilation stage, ensuring that runtime performance is deterministic and controllable. Lightweight overflow logic can also be set as a fallback branch, maintaining no overflow allocation in most scenarios and triggering overflow operations only in a small number of extreme scenarios when register resources are insufficient. This improves the robustness of the compilation tool while maximizing the performance benefits of no overflow allocation.

[0073] It should be noted that, for the sake of simplicity, the method embodiments are all described as a series of actions. However, those skilled in the art should understand that this application is not limited to the described order of actions, because according to this application, some steps can be performed in other orders or simultaneously. Secondly, those skilled in the art should also understand that the embodiments described in the specification are all optional embodiments, and the actions involved are not necessarily required by this application.

[0074] Reference Figure 4 This paper illustrates a block diagram of a register allocation system for a RISC-V microkernel compiler, comprising: an intermediate representation acquisition module 1, a register pool preprocessing module 2, a cross-region variable identification module 3, a register allocation scanning module 4, and a code generation module 5. The modules interact via a standardized multi-level IR data structure. The intermediate representation acquisition module 1 is configured to acquire the multi-level intermediate representation corresponding to the microkernel to be compiled. This multi-level intermediate representation retains structured loop control flow information. The intermediate representation acquisition module 1 serves as the system input source, connecting upwards to the compiler's intermediate optimization unit (not shown), and downwards to the register pool preprocessing module 2, the cross-region variable identification module 3, and the register allocation scanning module 4, respectively. The multi-level intermediate representation retains semantics such as loop nesting and iteration space from the front-end DSL / linalg dialect, and is not degraded into an unstructured control flow graph.

[0075] Register pool preprocessing module 2 is connected to intermediate representation acquisition module 1 and register allocation scanning module 4 respectively, and is configured to operate according to RISC. The V application binary interface specification defines an initial available register pool, excludes registers pre-bound and occupied in the multi-level intermediate representation from the initial available register pool, and outputs the target available register pool to register allocation scan module 4. Register pool preprocessing module 2 simultaneously identifies and removes pre-occupied registers bound by function parameters and hardware extension constraints.

[0076] The cross-region variable identification module 3 is connected to the intermediate representation acquisition module 1 and the register allocation scanning module 4, respectively. It is configured to identify cross-region variables defined outside the loop region and used inside the loop region within a multi-level intermediate representation, establish a tracking record for the cross-region variables, and output it to the register allocation scanning module 4. During operation, it first analyzes the control flow region to mark the loop boundary, then identifies the cross-region variables corresponding to each level of loop, and generates a tracking list.

[0077] The register allocation scanning module 4 receives the target available register pool, cross-region variable tracking records, and multi-level intermediate representations, and is configured to traverse the basic blocks of the multi-level intermediate representations in reverse order. When a loop structure is scanned, the traversal of the current basic block is paused, registers are allocated for cross-region variables first, and the available range of the registers for cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the module recursively enters the loop body to perform register allocation. After the recursion returns, the state of the target available register pool is restored. For non-loop linear basic blocks in the basic blocks, registers are allocated at the first point of use of the variable and released at the last point of use of the variable in reverse order.

[0078] In a preferred embodiment, the register allocation scanning module 4 is further configured to allocate the loop's iteration operands and the loop body's block parameters to the same register when a loop structure is scanned, thereby maintaining the semantic correctness of the SSA form.

[0079] The register allocation scanning module 4 has a built-in hardware constraint parsing unit that reads the declarative hardware constraints within the multi-level IR and completes the special register occupancy marking process; when recursively processing the loop body, each loop body is treated as an independent register allocation unit.

[0080] The code generation module 5 is connected to the register allocation scanning module 4 and is configured to generate RISC-V target code based on the final register allocation result; map the IR internal virtual registers to physical registers, perform instruction selection and scheduling, output assembly or machine code, and do not generate overflow-related load and store instructions.

[0081] As the system implementation is basically similar to the method implementation, it is described in a relatively simple way. For relevant details, please refer to the description of the method implementation.

[0082] As demonstrated by the above embodiments, to address the issue of semantic information loss, allocation is performed based on the structured regions of multi-level IRs, preserving semantic information inherited from the high-level DSL, such as nested loop structures and iterative space parameters, throughout the process. Register allocation can directly perceive high-level computing patterns, fully tapping the potential for hardware optimization. To address the issue of overflow performance loss, the total register requirement is constrained during the loop transformation and scheduling phase in the middle of compilation, ensuring that the peak register requirement of the microkernel does not exceed the total number of physical registers. There are no overflow operations during the allocation phase, avoiding latency caused by memory access and ensuring the peak utilization of floating-point computing units. To address the issue of insufficient hardware extension support, declarative hardware extension constraints in the IR can be directly read, reserving dedicated registers for specific hardware operations. This adapts to the register usage specifications of various custom extensions of RISC-V and domain-specific accelerators (xPUs), eliminating the need for developers to manually write assembly code. To address the issue of software and hardware semantic barriers, this solution bridges the semantic link from the high-level DSL to the underlying hardware registers, directly mapping high-level abstractions in fields such as linear algebra to RISC-V hardware characteristics, achieving end-to-end compilation optimization, and reducing semantic loss caused by multi-level IR conversion.

[0083] The specific technical solutions provided in the embodiments break through the performance bottleneck of traditional general-purpose register allocators in RISC-V dedicated domain microkernel scenarios, and open up the end-to-end compilation optimization link from high-level domain-specific languages ​​to RISC-V hardware extensions. This can help the commercialization of RISC-V architecture in edge AI, IoT and other fields, promote the technological evolution of RISC-V dedicated compilers, and enrich the RISC-V toolchain ecosystem.

[0084] Through the above description of the embodiments, those skilled in the art can clearly understand that the methods of the above embodiments can be implemented by means of software plus necessary general-purpose hardware platforms. Of course, they can also be implemented by hardware, but in many cases the former is a better implementation method. Based on this understanding, the technical solution of this application, in essence, or the part that contributes to the prior art, can be embodied in the form of a software product. This computer software product is stored in a storage medium (such as ROM / RAM, magnetic disk, optical disk) and includes several instructions to cause a terminal (which may be a mobile phone, computer, server, air conditioner, or network device, etc.) to execute the methods described in the various embodiments of this application.

[0085] The embodiments of this application have been described above with reference to the accompanying drawings. However, this application is not limited to the specific embodiments described above. The specific embodiments described above are merely illustrative and not restrictive. Those skilled in the art can make many other forms under the guidance of this application without departing from the spirit and scope of the claims, and all of these forms are within the protection scope of this application.

Claims

1. A register allocation method for a RISC-V microkernel compiler, characterized in that, include: Obtain the multi-level intermediate representation corresponding to the microkernel to be compiled, wherein the multi-level intermediate representation retains structured loop control flow information; The register allocation process includes: The initial available register pool is defined according to the RISC-V application binary interface specification. Registers that are pre-bound and occupied in the multi-level intermediate representation are excluded from the initial available register pool to obtain the target available register pool. Identify the cross-region variables defined outside the inner loop region and used inside the loop region in the multi-level intermediate representation, and establish tracking records for the cross-region variables; The basic blocks of the multi-level intermediate representation are traversed in reverse order. When a loop structure is encountered, the traversal of the current basic block is paused. Registers are allocated for the cross-region variables, and the available range of the registers of the cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the loop body is recursively entered to repeat the register allocation process. After the recursion returns, the state of the target available register pool is restored. For non-loop linear basic blocks in the basic blocks, registers are allocated at the first point of use of the variable in reverse order, and registers are released at the last point of use of the variable. The RISC-V target code is generated based on the final register allocation results.

2. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, The initial available register pool includes a caller-save integer register and a caller-save floating-point register.

3. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, Before identifying the cross-region variables, the control flow region of the multi-level intermediate representation is analyzed and the boundaries of the loop region are marked.

4. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, When the loop structure is encountered, the loop's iteration operands and the loop body's block parameters are assigned to the same register.

5. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, When the recursion enters the loop body, the loop body is treated as an independent register allocation unit, and the register allocation process is executed.

6. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, The structured loop control flow information includes the structured control flow semantics corresponding to linear algebra computation, which originates from the front-end compilation output for linear algebra computation.

7. The register allocation method for a RISC-V microkernel compiler according to claim 1, characterized in that, Before the register allocation process, a loop transformation and scheduling constraint are performed to limit the total register requirement to the number of physical registers.

8. The register allocation method for a RISC-V microkernel compiler according to any one of claims 1-7, characterized in that, The method further includes: reading the declarative hardware constraints stored in the multi-level intermediate representation, and adding an occupancy flag to the register based on the declarative hardware constraints.

9. A register allocation system for a RISC-V microkernel compiler, characterized in that, The system performs the method as described in any one of claims 1 to 8; the system comprises: an intermediate representation acquisition module, a register pool preprocessing module, a cross-region variable identification module, a register allocation scanning module, and a code generation module; The intermediate representation acquisition module is configured to acquire the multi-level intermediate representation corresponding to the microkernel to be compiled, wherein the multi-level intermediate representation retains structured loop control flow information. The register pool preprocessing module is connected to the intermediate representation acquisition module and the register allocation scanning module respectively. It is configured to delineate the initial available register pool according to the RISC-V application binary interface specification, exclude the registers pre-bound and occupied in the multi-level intermediate representation from the initial available register pool, and output the target available register pool to the register allocation scanning module. The cross-region variable identification module is connected to the intermediate representation acquisition module and the register allocation scanning module respectively, and is configured to identify cross-region variables defined outside the loop region and used inside the loop region of the multi-level intermediate representation, establish tracking records for the cross-region variables and output them to the register allocation scanning module; The register allocation scanning module is configured to traverse the basic blocks of the multi-level intermediate representation in reverse order. When a loop structure is encountered, the traversal of the current basic block is paused. Registers are allocated for the cross-region variables first, and the available range of the registers of the cross-region variables is set to cover the entire loop execution interval. After saving the current state of the target available register pool, the module recursively enters the loop body to perform register allocation. After recursion returns, the state of the target available register pool is restored. For non-loop linear basic blocks in the basic blocks, registers are allocated at the first point of use of the variable in reverse order, and registers are released at the last point of use of the variable. The code generation module is connected to the register allocation scanning module and is configured to generate RISC-V target code based on the final register allocation result.

10. The register allocation system for a RISC-V microkernel compiler according to claim 9, characterized in that, The register allocation scanning module is configured to allocate the loop's iteration operands and the loop body's block parameters to the same register when the loop structure is scanned.