A global register liveness analysis and context switch optimization method for atomic task flow
By using global register activity analysis and context switching optimization methods, the problems of ABI boundary overhead and RTOS context switching redundancy in embedded IoT devices are solved, achieving cross-task boundary optimization and improving performance and energy efficiency.
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- ZHEJIANG UNIV
- Filing Date
- 2026-04-24
- Publication Date
- 2026-07-10
AI Technical Summary
In existing embedded IoT devices, performance and energy efficiency are lost due to the application binary interface (ABI) boundary overhead caused by modular compilation and the redundancy of context switching of the general real-time operating system (RTOS). Existing optimization tools cannot perform global optimization across task boundaries.
By employing global register activity analysis and context switching optimization methods, and performing global static analysis based on the Abstract Task Graph (ATG), zero-copy register forwarding and minimum context set computation are achieved, generating compact machine code across task boundaries.
It eliminates ABI boundary overhead, reduces instruction count and memory access overhead, and lowers latency and power consumption, making it particularly suitable for resource-constrained embedded devices.
Smart Images

Figure CN122363757A_ABST
Abstract
Description
Technical Field
[0001] This invention relates to the fields of embedded system software optimization, compiler backend technology, and real-time operating system (RTOS) kernel design. Specifically, it relates to a global register activity analysis and context switching optimization method for atomic task flows. This invention eliminates application binary interface (ABI) overhead through global activity analysis during the code generation stage and dynamically generates minimal context switching logic. It is particularly suitable for code generation and optimization of resource-constrained embedded Internet of Things (IoT) devices, sensor nodes, smart wearable devices, and ultra-low power microcontrollers (MCUs). Background Technology
[0002] In resource-constrained embedded Internet of Things (IoT) devices, processor computing power (such as clock speed and pipeline depth) and energy budget (such as battery capacity) are extremely limited. Software stack optimization is crucial for achieving efficient task execution on these devices. However, existing embedded software construction methods are limited by two fundamental architectural bottlenecks, which this invention collectively refers to as the "Generic Penalty." The shortcomings of existing technologies are as follows: Defect 1: ABI boundary overhead ("compiler wall") caused by modular compilation Traditional embedded software employs modular development, and compilers (such as GCC and LLVM / Clang) must adhere to strict Application Binary Interface (ABI) specifications. Taking the RISC-V architecture as an example, its psABI (Procedure Standard ABI) specification strictly divides the 32 general-purpose registers into two categories: Caller-saved registers include a0-a7 (parameter registers) and t0-t6 (temporary registers). The caller function must save the values of these registers onto the stack before calling other functions (if they will be needed after the call).
[0003] Callee-saved registers: such as s0-s11 (saved registers). The called function must save the original values of these registers onto the stack before modifying them and restore them before returning.
[0004] Return Address Register: ra is the return address register, which is usually regarded as a register that the caller saves when needed according to the calling convention (for example, non-leaf functions save ra before making further calls and restore it before returning) to ensure that the function return address is not overwritten.
[0005] To ensure the generality and modularity of function calls, the compiler must generate standard prologue and epilogue code at the entry and exit points of each function, and push and pop the callee's saved registers onto and off the stack.
[0006] Compilers can typically only perform optimizations within a single compilation unit. Even with link-time optimization (LTO) enabled, compilers struggle to perform global register reuse across function boundaries.
[0007] When task A generates data in register a0, and task B subsequently needs to use that data, the standard compiler often first stores a0 on the stack, then reads it back from the stack in task B, resulting in redundant memory read / write instructions (Load / Store). In a typical IoT control task, function preamble / finale instructions account for 15%-25% of the total instructions, and approximately 60% of these register save operations may be redundant (i.e., the saved registers are never modified within the function). This mechanism constitutes the so-called "Compiler Wall," hindering global register optimization across task boundaries.
[0008] Defect 2: Redundancy in context switching of general-purpose real-time operating systems Existing mainstream RTOS kernels (such as FreeRTOS, Zephyr, and RT-Thread) adopt a conservative "context-unnaware" strategy when performing task scheduling and context switching.
[0009] Taking the implementation of FreeRTOS on the RISC-V architecture as an example, its context switching code is typically saved as follows: All general-purpose registers (s0-s11, a total of 12 registers) saved by all callees. Critical control status registers (CSRs), such as mepc (exception return address) and mstatus (machine status); Floating-point registers (if floating-point extension is enabled).
[0010] To ensure that interrupted tasks can be correctly resumed, a general-purpose RTOS must save all or most of the processor's state (Context Frame), without being aware of the actual register usage of a specific task.
[0011] For many concise atomic tasks, they may only use a very small number of temporary registers (such as t0-t2) during execution. However, general-purpose RTOSs still perform a full context save operation. This "overkill" mechanism introduces a huge amount of unnecessary instruction overhead. Specific performance impact metrics include: Additional instructions: Approximately 30-50 redundant instructions are added with each context switch; Memory access overhead: Each context switch generates approximately 20-40 high-energy-consuming memory bus transactions (Load / Store operations). Increased latency: Measured on the ESP32-C3 platform, FreeRTOS's context switching latency is approximately 8-12 microseconds, with about 60% of the time consumed by redundant register save / restore operations.
[0012] Existing "super-optimization" tools (such as Souper and STOKE) can perform optimization at the instruction sequence level, but they have the following fundamental limitations: Limitation 1: Limited working level. Most of these tools work at the compiler intermediate representation (IR) layer or only for a single function body, and cannot break the ABI boundaries between tasks at the operating system level.
[0013] Limitation 2: Lack of global perspective. Existing compiler register allocation algorithms (such as coloring and linear scanning) mainly work within a single function or compilation unit, lacking the ability to perform global activity analysis across task boundaries.
[0014] Limitation 3: Inability to dynamically optimize context switching. The context switching mechanism of existing RTOS has a fixed set of saved registers at the design time, which cannot be dynamically adjusted according to the actual usage of the task.
[0015] Therefore, a new global optimization method is urgently needed that can: Breaking ABI limitations: Providing a whole-system-level view of register usage across all tasks, enabling global optimization across task boundaries; Dynamically minimize context: dynamically calculate the minimized set of context switches based on the actual register usage of the task flow; Mathematical Verifiability: Provides a rigorous mathematical model based on graph theory and set theory to ensure the correctness and reproducibility of the optimization results; Independently applicable: It can be used as the core implementation method of deterministic backend, or it can be applied independently to other embedded code generation systems. Summary of the Invention
[0016] The purpose of this invention is to address the shortcomings of existing technologies by providing a global register activity analysis and context switching optimization method for atomic task flows. This method does not rely on traditional compiler optimization paths but instead performs global static analysis based on the Abstract Task Graph (ATG). Through zero-copy register forwarding and minimal context set computation, it generates extremely compact machine code that breaks the ABI (Application Binary Interface) limitations. This addresses the technical problems of Application Binary Interface (ABI) boundary overhead introduced by traditional modular compilation and context switching redundancy in general-purpose real-time operating systems (RTOS). Existing compilers, constrained by the ABI specification, must generate register save / restore instructions at each function boundary, making cross-task global optimization impossible. General-purpose RTOS employs a conservative "context-independent" strategy, saving the full register state during task switching, even if the task uses only a small number of registers.
[0017] The objective of this invention is achieved through the following technical solution: a global register activity analysis and context switching optimization for atomic task flows, comprising the following steps: S1: Task Flow Linearization: Obtain a directed acyclic graph structure describing the task execution logic, where nodes represent atomic tasks and edges represent data dependencies; each atomic task is associated with register semantic metadata for code generation, which includes at least input register interface constraints, output register interface constraints, and a polluted register list or register read / write set; transform the directed acyclic graph into a linear execution sequence that satisfies the data dependency constraints; S2: Global Activity Analysis: Traverse the linear execution sequence and calculate the active interval of each data variable based on the data dependencies between the atomic tasks. The active interval represents the time span from when the data variable is generated to when it is last used. S3: Zero-copy register forwarding: When allocating physical registers for adjacent tasks, determine whether the output data of the preceding task can be directly passed to the following task through the physical register; if it is determined that it can be passed, lock the physical register carrying the output data so that the physical register is not reallocated before the end of the active period of the output data, and skip the instruction to load the output data from memory when generating the machine code of the following task. S4: Minimal Context Switch Generation: Extract the polluted register list or register write set corresponding to each atomic task in the linear execution sequence, and calculate their union to obtain the full polluted set; obtain the set of registers that the target processor architecture requires to be retained at the context switch point; calculate the intersection of the full polluted set and the set of registers that need to be retained as the minimum register set; based on the minimum register set, generate context switch code containing only the necessary register save and restore instructions at the context switch point.
[0018] Furthermore, the nodes of the directed acyclic graph contain references to atomic primitives, which have predefined metadata, including at least an input register list, an output register list, and a pollution register list.
[0019] Furthermore, the active interval calculation method described in step S2 includes: identifying the definition point of each data variable and recording it as the starting position of the active interval of that variable; identifying the last usage point of each data variable and recording it as the ending position of the active interval of that variable; and defining the task sequence index interval between the starting position and the ending position as the active interval of that variable.
[0020] An interferogram is constructed based on the active regions. The nodes of the interferogram represent data variables. If the active regions of two data variables overlap, an edge is added between the corresponding nodes to indicate that the two variables cannot be assigned to the same physical register.
[0021] Furthermore, the determination in step S3 of whether the output data of the preceding task can be directly passed to the subsequent task includes the following checks: Data dependency check: Check whether the output data variable of the preceding task is used as the input data variable by the following task, and whether the active range of the output data variable covers the reading position of the following task; Safety gap check: Extract the polluted register list or register write set of the intermediate tasks between the preceding task and the following task and calculate their union to verify that the physical register carrying the output data has not been modified by any intermediate task between the two tasks. Interface alignment check: Verify that the physical registers simultaneously satisfy the output register interface constraints of the preceding task and the input register interface constraints of the following task, and do not conflict with the reserved registers or calling convention constraints of the target processor architecture.
[0022] Furthermore, the minimum set of registers mentioned in step S4 is calculated in the following way: Extract the polluted register list or register write set corresponding to each atomic task in the linear execution sequence; Calculate the union of the polluted register list or register write set to obtain the full polluted set Sclobber; Obtain the set of registers that the target processor architecture requires to be retained at the context switching point, wherein the retain set includes at least the set of registers that need to be retained as specified in the application binary interface (ABI) or calling convention; and, when the task flow contains a call instruction that will rewrite the return address register, the retain set also includes the return address register. Calculate the intersection of the full contaminated set and the set of registers to be kept: Cmin = Sclobber ∩Skeep, and use this intersection as the minimum set of registers.
[0023] Furthermore, context switching code is generated based on the minimum register set Cmin, including: Prologue generation: At the entry point of the context switch, traverse each register in Cmin and generate an instruction to save the register value to the stack or a predetermined storage area. Generate Epilogue: At the exit of the context switching point, traverse each register in Cmin and generate an instruction to restore the register value from the stack or a predetermined storage area.
[0024] When the minimum register set Cmin is empty, zero-overhead context switching code is generated. The zero-overhead context switching code does not contain register save and restore instructions and is used to complete the control flow transfer at the context switching point.
[0025] Furthermore, the method also includes a register allocation correctness verification process, specifically comprising the following steps: V1: Obtain the data to be verified: Obtain the machine code, register allocation table, and active range information of data variables generated through global register activity analysis; V2: Perform static activity check: Construct an interferogram based on the active interval information to verify whether the physical register assigned to each data variable has not been assigned to other data variables with overlapping active intervals within its active interval; if a conflict is found, mark it as an activity conflict error; V3: Perform forwarding legality checks: For task node pairs marked as "zero-copy forwarding", verify whether the output register of the preceding task has indeed not been modified by the intermediate task during the execution of the following task; if modification is found, mark it as a forwarding security error; V4: Output Verification Report: Generates a verification report containing all detected errors, error locations, and suggested remedial measures.
[0026] Furthermore, the forwarding legitimacy check described in step V3 includes: Extract the output register identifier Rout from the preceding task; Extract the list of polluted registers for all intermediate tasks between the preceding and following tasks; Calculate the union of all polluted register lists, Sgap; If Rout ∈ Sgap, then forwarding is deemed insecure and marked as an error.
[0027] Furthermore, the verification report also includes at least one of the following optimization recommendations: For liveness conflict errors, it is recommended to adjust the register allocation scheme or perform a register overflow (Spill) operation; For the forwarding security error, it is recommended to disable zero-copy forwarding optimization and restore the generation of standard memory loading instructions; If the minimum context set is calculated incorrectly, it is recommended to rescan the polluted register list of the task sequence.
[0028] On the other hand, the present invention also provides a global register activity analysis and context switching optimization system for atomic task flows, comprising: Linearization module: Used to transform a directed acyclic graph (DAG) of task dependencies into a linear execution sequence that satisfies data dependency constraints; Activity analysis engine: used to calculate the active interval of each data variable in the linear execution sequence and construct an interferogram based on the active interval; Zero-copy optimizer: used to analyze the data transfer relationship between adjacent tasks, determine whether zero-copy forwarding can be achieved by locking physical registers, and control the code generator to skip redundant memory load instructions; Context generator: Used to extract the full sludge set Sclobber of the task flow, obtain the set of registers required to be retained by the target processor architecture at the context switching point, where the retain set includes at least the set of registers to be retained as specified in the application binary interface (ABI) or calling convention; and when the task flow contains a call instruction that modifies the return address register, the retain set also includes the return address register, and calculates the minimum register set Cmin = Sclobber ∩ Retain, and generates minimal context switching code based on the minimum register set; Verification Subsystem: Performs static liveness checks and forwarding legitimacy checks on the generated register allocation scheme and outputs a verification report.
[0029] The beneficial effects of this invention are: 1. Eliminating ABI redundancy and overcoming compiler limitations: Through zero-copy register forwarding in step S3, this method achieves cross-task boundary optimizations that compilers cannot perform. In a typical IoT "smart sensing" workload (ADC sampling → FIR filtering → threshold detection), this method reduces the number of instructions by 62.0% compared to the GCC-O3 + LTO baseline (from 246,014 to 93,572). Zero-copy forwarding eliminates a large number of unnecessary memory load / store instructions between ADC reads and filters; data is transferred directly between registers.
[0030] 2. Extremely Low Latency and Power Consumption: By generating a minimal context in step S4, this method avoids saving unused registers. Even in computationally intensive tasks such as "secure communication" workloads (CRC32 + XOR encryption), an 18.2% instruction reduction is achieved; system power consumption is reduced by 60.6% (from 45.2 μJ to 17.8 μJ). Dynamic computation of the minimal context set eliminates the overhead of traditional RTOSs that force the saving of all s0-s11 registers, saving only the actually modified registers (e.g., saving only register s1). This method successfully overcomes the "compiler wall" limitation of traditional compilers and is particularly suitable for battery-powered embedded devices with extremely high performance and energy efficiency requirements.
[0031] 3. Determinism and Security: This method is based on rigorous set operations and graph algorithms, and its optimization results are deterministic, eliminating the randomness risk inherent in AI-generated code. After 1000 repeated generation tests, this method consistently produces byte-level consistent output for the same input.
[0032] 4. Mathematical Verifiability: The interferogram and set operation model provided by this method can be used to formally verify the correctness of the optimization results.
[0033] 5. Standalone application: This method can be applied independently to embedded code generation systems, compiler backends, or real-time operating system kernels that require extreme performance optimization. Attached Figure Description
[0034] To more clearly illustrate the technical solutions in the embodiments of the present invention or the prior art, the drawings used in the description of the embodiments or the prior art will be briefly introduced below. Obviously, the drawings described below are only some embodiments of the present invention. For those skilled in the art, other drawings can be obtained based on these drawings without creative effort.
[0035] Figure 1 This is a flowchart illustrating the overall process of the global register activity analysis and context switching optimization method provided in this embodiment of the invention. The flowchart shows the complete process from the abstract task graph (ATG) input to the optimized microkernel binary output, including five core stages: topology sorting and linearization, global activity analysis, zero-copy register forwarding optimization, minimum context set calculation, and assembly code concatenation and deployment.
[0036] Figure 2This diagram illustrates the linearization of the Abstract Task Graph (ATG) and the lifecycle analysis of symbolic variables in an embodiment of the present invention. The diagram is divided into two stages: the first stage shows how to transform the DAG-structured ATG into a linear sequence through topological sorting; the second stage shows how to calculate the active interval of each symbolic variable on the linear sequence and visualize it in the form of a timeline.
[0037] Figure 3 This is a flowchart illustrating the logical decision-making process of the zero-copy register forwarding algorithm in this embodiment of the invention. The diagram details how the algorithm determines whether zero-copy forwarding optimization can be performed through three steps (data dependency check, security gap check, and interface alignment check), and how, upon successful optimization, the register is locked and the generation of load instructions is skipped.
[0038] Figure 4 This diagram illustrates the set operation of the global minimum context switching set (C_min) in an embodiment of the present invention. The diagram uses Venn Diagram logic to demonstrate how the minimum set of registers to be saved is obtained by calculating the intersection of the full polluted set and the ABI callee's saved register set.
[0039] Figure 5 This diagram illustrates a structural comparison between the optimized assembly code generated in this embodiment of the invention and the code generated by a traditional compiler. The diagram visually compares the "V-shaped" stack data flow (register → stack → register) generated by the traditional compiler with the "one-word" zero-copy data flow (register → register) generated by this invention, demonstrating the difference in the number of instructions and the change in data flow before and after optimization. Detailed Implementation
[0040] To make the objectives, technical solutions, and advantages of this invention clearer, the invention will be further described in detail below with reference to the accompanying drawings and embodiments. It should be understood that the specific embodiments described herein are merely illustrative and not intended to limit the invention.
[0041] This invention provides a register activity analysis and context switching optimization method, comprising the following steps: S1: Task Flow Linearization: Obtain the Directed Acyclic Graph (ATG) structure describing the task execution logic. Nodes in the ATG represent atomic tasks, and edges represent data dependencies. Transform the ATG into a linear execution sequence that satisfies data dependency constraints. The linearization algorithm can employ topological sorting, depth-first search, breadth-first search, etc. The goal of linearization is to map the DAG structure into a one-dimensional sequence for easier subsequent activity analysis. For any dependency (T_i → T_j), T_i must precede T_j in the sequence, where T_i represents the i-th task node.
[0042] S2: Global Activity Analysis: Traverse the linear execution sequence and calculate the active interval for each data variable, where the active interval represents the time span from when the data variable is generated to when it is last used. Specifically, forward data flow analysis is used to mark the definition point of each variable; backward data flow analysis is used to mark the last use point of each variable; and an interferogram is constructed based on the active intervals for subsequent register allocation conflict detection.
[0043] S3: Zero-copy register forwarding: When allocating physical registers for adjacent tasks, determine whether the output data of the preceding task can be directly passed to the following task through the physical register; if it is determined that it can be passed, lock the physical register carrying the data, and skip the instruction to load the data from memory when generating the code of the following task.
[0044] The judgment condition must meet at least one of the following: Data dependency check: There is a data dependency between the output of the preceding task and the input of the following task; Safety gap check: The physical registers carrying the data have not been modified by other operations between the two tasks; Interface alignment check: The physical registers satisfy the hardware interface constraints of the two tasks.
[0045] S4: Minimal Context Switch Generation: By analyzing the set of physical registers actually modified by all tasks in the linear execution sequence (the full contaminated set), and the set of registers that the target processor architecture requires to be preserved at the context switch point (e.g., as specified by the ABI / calling convention / task boundary protection model), the minimum set of registers to be saved during the execution of the task flow is calculated (C_min = S_clobber ∩ S_ABI), where C_min represents the minimum context switch set, S_clobber represents the full contaminated set (the union of all task-contaminated registers), and S_ABI represents the set of callee-saved registers specified by the target architecture ABI. Based on the minimum set of registers, context switch code containing only necessary register save and restore instructions is generated. If C_min is an empty set, zero-overhead context switch code (containing only return instructions) is generated; if C_min is not empty, customized prologue and epilogue code is generated. The prologue and epilogue are code segments automatically generated by the compiler during function calls, used to manage the function's stack frame and register state.
[0046] This invention also includes a separate method for verifying the correctness of register allocation, comprising: Static activity check: By constructing an interferogram, it is verified whether the active regions of data variables assigned to the same physical register do not overlap; Forwarding legality check: For task node pairs marked as "zero copy forwarding", verify whether the intermediate task has indeed not modified the registers carrying the data; Output verification report: Generates a report containing all detected errors, error locations, and suggested remedial measures.
[0047] The system provided by this invention may include a visualization debugging module, which is used to graphically display task dependency graphs, active interval timelines, and interference graphs to help developers understand the optimization process.
[0048] Example 1: Global Linearization and Activity Analysis Algorithm for Atomic Task Flow This embodiment details how to transform a nonlinear Abstract Task Graph (ATG) into a linear model capable of global optimization and establish a lifecycle view of symbolic variables. This forms the basis for all subsequent optimizations.
[0049] 1.1 Algorithm Input and Symbolic Definition like Figure 1 As shown, the input to this method is an abstract task graph (ATG) generated by a semantic parser. For mathematical global analysis, the ATG is first formally defined: Definition 1: Abstract task graph G = (V, E, Σ) Node set V: Represents atomic task instances. Each node T_i ∈ V is bound to a specific atomic primitive P_i. The primitive P_i contains static metadata, including: Input(P_i): This primitive reads data from which registers; Output(P_i): This primitive writes the result to which registers; The list of polluted registers, Clobbers(P_i): Temporary registers that this primitive will modify during execution.
[0050] Edge set E: Represents data dependencies. An edge (T_i, T_j) ∈ E indicates that the output of node T_i is consumed by node T_j.
[0051] Symbolic variable set Σ: Each edge e ∈ E corresponds to a unique symbolic variable v ∈ Σ (e.g., var_temp_data). At this point, v is not yet bound to any physical register.
[0052] Example: A simple ATG containing 3 tasks: Task T1: ADC_READ → Output: var_sensor_data Task T2: FIR_FILTER → Input: var_sensor_data, var_coeffs → Output: var_filtered Task T3: THRESHOLD → Input: var_filtered, var_threshold → Output: var_alarm 1.2 Topological Sorting and Linearization Since embedded microcontrollers (MCUs) typically execute sequentially on a single core, the algorithm first maps the ATG of the DAG structure into a one-dimensional sequence.
[0053] like Figure 2 As shown, the linearization process includes the following steps: Step 1: Perform topological sorting: Perform the topological sorting algorithm on the ATG. Topological sorting is a classic graph algorithm that ensures that for any dependency (T_i → T_j), T_i will always appear before T_j in the sorted result.
[0054] Algorithm pseudocode: def topological_sort(G): L = [] # Output sequence S = {v for v in G.vertices if in_degree(v) == 0} # Nodes with an in-degree of 0 while S is not empty: n = S.pop() L.append(n) for m in neighbors(n): remove_edge(n, m) if in_degree(m) == 0: S.add(m) if G has edges: raise Error("A cycle exists in the graph") return L The core function of this pseudocode is to "flatten" a network graph (Abstract Task Graph, ATG) with dependencies into a one-dimensional linear execution sequence, while absolutely ensuring that the original sequential dependencies are not broken. Specifically, its execution logic can be divided into the following four core stages: 1. Initial state filtering (finding the source) When the algorithm starts, it first scans the entire task graph to find all nodes with an in-degree of 0 (i.e., source tasks that have no prerequisites and can be executed directly), and puts them into a set to be processed (resource pool). At the same time, it prepares an empty list to store the final sorting results.
[0055] 2. Core stripping loop (unlocking layer by layer) Once in the loop, the algorithm continuously retrieves a currently executable task from the resource pool and adds it to the final output list.
[0056] Once this task is "executed" (i.e. added to the list), the algorithm will trace back to find all "downstream tasks" that depend on it and "cut" the dependency edge connecting them. This is equivalent to telling the downstream tasks: "Your precondition has been met."
[0057] 3. Dynamic pool addition (triggered by new tasks) While pruning dependency edges, the algorithm continuously checks the remaining dependency count (in-degree) of downstream tasks. If all the prerequisites of a downstream task have been satisfied (in-degree becomes zero), it officially qualifies for execution, and the algorithm immediately adds it to the pending set, waiting to be stripped. This "stripping -> unlocking -> adding to the pool" process continues until the set is completely cleared.
[0058] 4. Loop Detection and Safe Return (Final Line of Defense) After all executable tasks have been processed, the algorithm performs a final "health check." If any unpruned dependency edges remain in the graph, it indicates that there are "infinite loops" between these tasks (i.e., A waits for B, B waits for C, and C waits for A). Such a graph cannot be linearized, and the program will directly report an error and intercept the process. If everything is normal and the graph is completely cleared, the algorithm will output the final sorted linear sequence of tasks.
[0059] Step 2: Generate a linear sequence: Output a linear task execution sequence S = [T_1, T_2, ..., T_N]; For any dependency (T_i → T_j) ∈ E, index(T_i) < index(T_j) must be satisfied in sequence S; T_i and T_j are task nodes, representing two specific atomic task instances in the abstract task graph (ATG). Among them, T_i is the task that produces data, and T_j is the task that consumes this data. E is the set of edges, representing the data dependencies between tasks. (T_i → T_j) ∈ E means that there is an edge from T_i to T_j, indicating that the execution of T_j must depend on the data provided by T_i. S is a linear execution sequence, which is a one-dimensional execution order list mapped after topologically sorting the original graph (DAG) with a complex branch structure. Index is an index function, representing the physical position of a task in sequence S. The core logic of this formula is: to ensure the correctness of the program, the task that produces data must be ranked before the task that consumes data.
[0060] Example: The linearization result of the above ATG is S = [T1: ADC_READ, T2: FIR_FILTER, T3: THRESHOLD] 1.3 Global Symbol Variable Liveness Analysis As Figure 2 shown, after obtaining the linear sequence S, the algorithm traverses the sequence and calculates the "live interval (Live Interval)" of each symbol variable v. The live interval LIVE(v) is the closed interval [DEF(v), USE(v)], where DEF(v) represents the task index i at which variable v is produced (i.e., v ∈ Output(T_i)), and USE(v) represents the task index j at which variable v is consumed last (i.e., v ∈ Input(T_j), and there does not exist k > j such that v ∈ Input(T_k)). Algorithm implementation: Step 1: Forward scan - mark the definition points for i, task in enumerate(S): for var in task.outputs: DEF[var] = i Step 2: Backward scan - mark the last use points for i in reversed(range(len(S))): task = S[i] for var in task.inputs: if var not in USE: USE[var] = i Step 3: Calculate the active range for var in all_variables: LIVE[var] = (DEF[var], USE[var]) Example: For the above ATG: var_sensor_data: LIVE = [1, 2] (defined in T1, used last in T2) var_filtered: LIVE = [2, 3] (defined in T2, used last in T3) This active range is used not only for register allocation, but more importantly, to determine whether a variable is "alive" at a specific point in time. If a physical register is occupied within a range, that register cannot be allocated to other variables that overlap with that range.
[0061] 1.4 Construction of Interference Graph Based on the active regions, the algorithm constructs an interferogram IG = (V_IG, E_IG), where V_IG is a set of nodes, with each symbolic variable corresponding to one node, and E_IG is a set of edges. If the active regions of two variables v1 and v2 overlap, then an edge (v1, v2) is added. Overlap determination criteria: OVERLAPS(v1, v2) = (DEF(v1) <= USE(v2)) AND (DEF(v2) <= USE(v1)) In an interference diagram, the edges represent two variables that "interfere," meaning they cannot be assigned to the same physical register. The register allocation problem can be transformed into a graph coloring problem.
[0062] Example 2: Zero-copy register forwarding algorithm based on interface contract This embodiment details the core innovation of the present invention—zero-copy register forwarding. This algorithm utilizes the "interface contract" of atomic primitives to eliminate data transfer instructions between tasks during generation.
[0063] 2.1 Problem Modeling Problems with traditional compilers: In the code generated by traditional compilers, after task T_prev calculates the result, it is usually stored on the stack (Store); before task T_curr is executed, it is read from the stack (Load).
[0064] Example assembly code (traditional method): # Task T1: ADC Read call ADC_READ sw a0, 0(sp) # Save a0 to the stack # Task T2: FIR Filtering lw a0, 0(sp) # Load a0 from the stack call FIR_FILTER The objective of this embodiment is to detect and mathematically prove that the result of the preceding task T_prev can be directly stored in a register for use by the current task T_curr, thereby eliminating the sw and lw instructions.
[0065] 2.2 Forwarding Decision Logic like Figure 3 As shown, when traversing the task sequence S, the algorithm performs the following three steps to determine the current task T_curr and its preceding task T_prev: Judgment Criterion A: Data Dependency Check Check if there exists a non-empty intersection between the input symbol set Input(T_curr) of T_curr and the output symbol set Output(T_prev) of T_prev: DEPENDS(T_prev, T_curr) = Input(T_curr) ∩ Output(T_prev) ≠ ∅ If the intersection is not empty, it means that there is a direct data path, proceed to the next step.
[0066] Example: T1 output: {var_sensor_data} T2 Input: {var_sensor_data, var_coeffs} Intersection: {var_sensor_data} ≠ ∅ → Dependency exists Decision criterion B: Physical Interface Alignment For the variable v in the intersection, query the primitive metadata: R_out = physical register(T_prev primitive to which register v is output) R_in = physical register(T_curr corresponding primitive expectation v, which register the input is from) If R_out = R_in, it indicates that the physical channels are aligned, proceed to the next step. Example: ADC_READ primitive: Output(var_sensor_data) = a0 FIR_FILTER primitive: Input(var_sensor_data) = a0 R_out = R_in = a0 → Interface alignment a0 is a physical register number in the target processor (taking the RISC-V architecture mentioned in the document as an example). In the standard Embedded Application Binary Interface (ABI), a0 is usually specified as the "parameter register" or "return value register", which is specifically used to pass the first parameter or return result between function calls.
[0067] Technical Logic (Interface Alignment): When the documentation mentions R_{out} = R_{in} = a0, it means that after the preceding task (such as ADC sampling) is completed, the result is placed in a0; and the subsequent task (such as filtering) also requires reading input from a0. This "coincidence" allows data to reside directly in a0 for forwarding without going through memory transfer (first stored on the stack by sw, then read out by lw), thus eliminating unnecessary instruction overhead.
[0068] Note: The design specifications of the Standard Atomic Assembly Library (SAAL) typically ensure the consistency of interfaces for commonly used data flows (such as computational flows).
[0069] Judgment C: Safety Gap Check Although T_prev and T_curr are logically adjacent, in some complex topologies, other tasks with no data dependencies may be inserted between them. The algorithm must check whether any intermediate tasks T_mid between T_prev and T_curr have polluted the target register R_out.
[0070] The specific formula for checking is as follows: SAFE(R_out, T_prev, T_curr) = ∀ T_mid ∈ GAP(T_prev, T_curr), R_out∉ Clobbers(T_mid) Where GAP(T_prev, T_curr) represents all tasks in sequence S located between T_prev and T_curr.
[0071] Example: Assuming T1 and T2 are directly adjacent, GAP(T1, T2) = ∅ Alternatively, assuming T_x is inserted in the middle, it is necessary to check a0 ∉ Clobbers(T_x). Comprehensive judgment: If all three judgment conditions A, B, and C are met, then it is determined that it is "forwardable".
[0072] 2.3 Action Execution Once determined to be "forwardable", the deterministic backend performs the following atomic operations: Operation 1: Lock Register: In the register allocation table, mark R_out as exclusively occupied by the symbolic variable v and set its status to FIXED.
[0073] RegAlloc[v] = R_out RegStatus[R_out] = FIXED Operation 2: Skip Load: When generating the assembly code for T_curr, the lw (Load Word) instruction used to load v is not generated.
[0074] if FORWARDABLE(T_prev, T_curr, v): # Do not generate: lw R_in, offset(sp) pass # Use the value in R_out directly Operation 3: Inherit State: T_curr assumes that R_out already contains the required data, and no additional operation is required.
[0075] 2.4 Effects of the Example Taking "ADC reading → FIR filtering" as an example: Traditional method: call ADC_READ # Output to a0 sw a0, 0(sp) # Save to stack lw a0, 0(sp) # Load from stack call FIR_FILTER # Input from a0 This embodiment uses a zero-copy approach: call ADC_READ # Output to a0 # (Skip the sw and lw commands) call FIR_FILTER # Read directly from a0 Result comparison: Two memory access instructions (sw + lw) have been eliminated. Reduced 2 memory bus transactions No runtime decision-making overhead is introduced (optimization is done at compile time). In the "Smart Sensing" workload, zero-copy optimization eliminates approximately 40% of Load / Store instructions, reducing energy consumption per task execution by approximately 25%.
[0076] Example 3: Global Minimal Context Switching Generation Algorithm Based on Set Operations This embodiment describes in detail how to dynamically calculate the minimum register storage set required for the current task flow using the set theory method, thereby breaking the "one-size-fits-all" context switching mechanism of general RTOS.
[0077] 3.1 Problem Definition In embedded development, the Application Binary Interface (ABI) specifies a set of "callee-saved" registers (denoted as set S_ABI).
[0078] Example: In the RISC-V RV32IM architecture: S_ABI = {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, ra} Traditionally, regardless of which registers the task actually uses, general-purpose RTOS or compilers usually save the entire S_ABI, resulting in a stack read / write overhead of |S_ABI| × 4 = 52 bytes (13 registers × 4 bytes / register).
[0079] This embodiment only saves those registers that are "required to be saved by the ABI and have actually been modified in the current task flow".
[0080] 3.2 Algorithm Flow like Figure 4 As shown, this algorithm is executed in the final stage of code generation and includes the following three steps: Step A: Construct the Global Clobber Set Calculation Scan each task node T_i in the linear task sequence S and extract the tainted register list Clobbbers(P_i) of its corresponding primitive P_i. Calculate the union of all task tainted lists: S_clobber = ⋃(i=1 to N) Clobbers(P_i) Algorithm implementation: S_clobber = set() for task in S: primitive = task.primitive S_clobber = S_clobber.union(primitive.clobbers) Here, S_clobber represents all physical registers that will be modified during the execution of the current task flow.
[0081] Example: Suppose the task flow contains 3 primitives: Primitive 1 pollution: {a0, a1, t0} Primitive 2 pollution: {t2, s0, a1} Primitive 3 pollution: {t0, s1} Then: S_clobber = {a0, a1, t0, t2, s0, s1} Under the RISC-V-based Application Binary Interface (psABI) specification, the above parameters refer to specific general-purpose physical registers: a0, a1 (parameter / return value registers): These belong to the "Caller-saved Registers". They are typically used to pass parameters to functions or to store the return value of function execution.
[0082] t0, t2 (temporary registers): These belong to the "caller-saved registers". They are mainly used to store intermediate calculations or temporary data during function execution. If the calling function needs this temporary data later, it must be responsible for pushing it onto the stack.
[0083] s0, s1 (Saved Registers): These belong to the "Callee-saved Registers". The values of these registers have a contract that they must remain unchanged across function calls. If a function or task needs to modify s0 or s1 during execution, it must push their original values onto the stack before modifying them and restore them from the stack before the function returns.
[0084] Step B: Calculate the minimum context intersection. Perform an intersection operation between the full contaminated set obtained in step A and the ABI set of the target architecture to obtain the minimum context switching set C_min: C_min = S_clobber ∩ S_ABI Algorithm implementation: S_ABI = get_ABI_callee_saved_regs(target_arch) C_min = S_clobber.intersection(S_ABI) If a register r ∈ S_clobber but r ∉ S_ABI (e.g., temporary register t0): it belongs to the "caller-saved" registers in the usual sense. Under the task boundary / kernel entry-exit protection model described in this invention, if the value of such a register does not need to be maintained across the boundary, it does not need to be saved by the current task and can be directly discarded. If a register r ∈ S_ABI but r ∉ S_clobber (e.g., s2 is not used by any task), it means that it remains unchanged during task execution and therefore does not need to be saved. Only the registers in the intersection (r ∈ S_clobber and r ∈ S_ABI) need to be saved.
[0085] Example calculation: S_clobber = {a0, a1, t0, t2, s0, s1} S_ABI = {s0, s1, s2, ..., s11} If the task flow contains function call instructions between kernel entry / exit points (e.g., `call` / `jal` rewrites `ra`), then `ra` needs to be included in the set of registers to be preserved (denoted as `S_preserve = S_ABI ∪ {ra}`). If atomic primitives are concatenated with inline instruction sequences and do not introduce call instructions that rewrite `ra`, then `ra` does not need to be included. Here, `call` / `jal` are "function call instructions" (short for Jump and Link, and pseudo-instructions) in RISC-V and other assembly languages. When the code executes these instructions, the processor jumps to the address of the target function. `ra` is short for "Return Address Register". Its core function is to store the memory address of the next instruction to return to after the current function has finished executing. When `call` or `jal` initiates a function call, the hardware automatically writes the address of the instruction after the call point and overwrites the `ra` register. Therefore, if the task flow contains such instructions that rewrite the value of `ra`, it must be included in the set of context registers to be preserved.
[0086] C_min = {a0, a1, t0, t2, s0, s1} ∩ {s0, s1, s2, ..., s11, ra} = {s0,s1} Step C: Dynamic Code Emission Generate customized Prologue and Epilogue based on the calculated C_min: Generate Prologue: # Assume C_min = {s0, s1} addi sp, sp, -8 # Allocate stack space (2 registers × 4 bytes) sw s0, 0(sp) # Save s0 sw s1, 4(sp) # Save s1 Generate Epilogue: lw s0, 0(sp) # Restore s0l w s1, 4(sp) # Restore s1 addi sp, sp, 8 # Release stack space ret This code demonstrates how to achieve extremely low-overhead register save and restore operations when dynamically generating minimal context switches. The implementation logic is explained below: When the algorithm calculates that the current task flow only needs to save the two registers s0 and s1 (i.e., the minimum context set C_{min} = {s0, s1}): 1. Entry Prologue: First, the `addi sp, sp, -8` instruction allocates 8 bytes of memory down the stack (because each of the two registers occupies 4 bytes). Then, the `sw` instruction is used to save the current value of register `s0` to a position offset 0 from the top of the stack, and save `s1` to a position offset 4. This saves only the protected registers that are actually corrupted.
[0087] 2. Epilogue: When the task flow finishes execution and is ready to exit, the reverse operation is performed at the same offset. The load instruction `lw` is used to read data from stack offset 0 to restore it to `s0`, and from offset 4 to restore it to `s1`. Then, the `addi sp, sp, 8` instruction reclaims these 8 bytes of stack space, resetting the stack pointer. Finally, the `ret` instruction is executed to complete the switch.
[0088] Zero-overhead context switching: If C_min = ∅ (empty set), and the task flow does not contain any call instructions that would modify the set of registers that need to be maintained between the kernel entry / exit (e.g., not modifying the return address of ra), then the generated context switching code does not contain save / restore instructions and may only contain return instructions (e.g., ret).
[0089] 3.3 Effects of the Example Scenario 1: Minimal Context Set Non-empty Assume the task flow contains only 3 primitives, which only use a0 (parameter register) and t0 (temporary register).
[0090] S_clobber = {a0, t0} S_ABI (RISC-V) = {s0, s1, ..., s11} Note: As above, whether ra is included depends on whether the task flow contains a call instruction that will rewrite ra.
[0091] Result of the operation: C_min = {a0, t0} ∩ {s0, s1, ..., s11, ra} = ∅ (empty set) Final code: The generated kernel entry and exit points contain no save / restore instructions (Zero Overhead), only a single ret instruction. This saves approximately 30 instructions compared to the traditional method (13 registers × 2 operations (save + restore) + stack pointer adjustment).
[0092] Scenario 2: Minimal context set contains a small number of registers. Assume the task flow uses {a0, a1, t0, s0, s1}.
[0093] S_clobber = {a0, a1, t0, s0, s1} S_ABI = {s0, s1, s2, ..., s11} Note: If the task flow contains function call instructions between the kernel entry / exit points (e.g., call / jal will rewrite ra), then ra needs to be included in the set of registers to be preserved (which can be denoted as S_preserve = S_ABI ∪ {ra}); if the atomic primitives are concatenated with an inline instruction sequence and do not introduce call instructions that rewrite ra, then ra does not need to be included.
[0094] Calculation result: C_min = {s0, s1} The traditional approach saves the entire S_ABI (13 registers) = 52 bytes of stack space. This method only saves C_min (2 registers) = 8 bytes of stack space, reducing stack space by 84.6% and context switching instructions by about 85% compared to the traditional approach.
[0095] Example 4: Register Allocation Correctness Verification Algorithm This embodiment describes how to ensure, through an independent verification method, that the register allocation scheme generated by the aforementioned optimization algorithm is functionally correct.
[0096] 4.1 Static Liveness Verification Verify that the active regions of data variables allocated to the same physical register do not overlap.
[0097] Algorithm flow: Step 1: Reconstruct the interferogram. Based on the active region information, reconstruct the interferogram IG = (V_IG, E_IG).
[0098] Step 2: Collision Detection. Traverse all edges (v1, v2) ∈ E_IG of the interferometric graph and check: if RegAlloc[v1] == RegAlloc[v2]: report_conflict(v1, v2, RegAlloc[v1]) Step 3: Output the verification results If no conflict is found, output "Static activity check passed". If a conflict is detected, a detailed error report will be generated. Error report example: Error type: Activity conflict Conflicting variables: var_sensor_data, var_filtered Register allocation: a0 Active range: [1, 2] and [2, 3] Recommended fix: Allocate a different register (e.g., a1) for var_filtered or perform a register overflow. 4.2 Forwarding Legality Verification For task node pairs marked as "zero-copy forwarding", verify whether the intermediate task has indeed not modified the registers carrying the data.
[0099] Algorithm flow: Step 1: Extract forwarding records. Traverse all task nodes and extract the node pairs (T_prev, T_curr, R_out) marked as "zero-copy forwarding".
[0100] Step 2: Security Gap Revalidation For each forwarding record, re-perform the security gap check: gap_tasks = get_tasks_between(T_prev, T_curr, S) S_gap = set() for task in gap_tasks: S_gap = S_gap.union(task.primitive.clobbers) if R_out in S_gap: report_forwarding_error(T_prev, T_curr, R_out) This code belongs to the register allocation verification module and is used to re-verify whether the previous "zero-copy register forwarding" decision is physically absolutely safe. The implementation logic is explained below: 1. Obtain intermediate tasks: First, call the get_tasks_between function to extract all intermediate tasks between the preceding task T_prev and the following task T_curr from the linear task sequence S and store them in the list gap_tasks.
[0101] 2. Construct the pollution set: Initialize an empty set named S_gap. Then, iterate through all extracted intermediate tasks, and continuously merge the union of the register lists (clobbers) modified by each intermediate primitive into the S_gap set. At this point, S_gap contains all registers that may have been modified along the way.
[0102] 3. Conflict Detection: Finally, check if the physical register R_out carrying the data exists in the intermediate pollution set S_gap. If it exists, it means that the data we want to pass to subsequent tasks via R_out has been overwritten or corrupted by some intermediate task en route. In this case, the forwarding is deemed invalid, the report_forwarding_error function is called to throw a forwarding security error, and the optimization is aborted.
[0103] Step 3: Output the verification results If all forwards are safe, output "Forwarding legality check passed". If an insecure forwarding is detected, a detailed error report will be generated. Error report example: Error type: Forwarding security error Preceding task: T1 (ADC_READ) Subsequent task: T3 (THRESHOLD) Forwarding register: a0 Intermediate task: T2 (FIR_FILTER) Contamination detection: a0 ∈ Clobbers(T2) Recommended fix: Disable zero-copy forwarding and restore the generation of lw a0, offset(sp) 4.3 Generation of Comprehensive Validation Report The system ultimately generates a comprehensive verification report, which includes the task flow name, verification time, static liveness check results, forwarding legality check results, minimum context set verification results, and suggests whether deployment to the target hardware is allowed.
[0104] Example 5: Algorithm Validation and Performance Testing This embodiment verifies the overall performance benefits of the above algorithm on real hardware through comparative experiments.
[0105] 5.1 Experimental Setup Hardware platform: Model: ESP32-C3 Development Board Processor: RISC-V RV32IMC single-core, 160MHz Memory: 400KB SRAM, 4MB Flash Comparison objects: Baseline: Bare-metal C code compiled using GCC v13.2.0 (-O3 -flto -fomit-frame-pointer) with the highest optimization level enabled, link-time optimization (LTO) enabled, and framepointer removed, representing the performance limit of traditional compilation toolchains; This invention (Ours): Microkernel assembly code generated using the algorithm described in this patent, tested under a typical IoT hybrid load, includes: ADC_READ: I / O intensive (reads 12-bit ADC, 10 channels) FIR_FILTER: Computationally intensive (8th-order FIR digital filter) CRC32: Control flow intensive (CRC32 checksum calculation) 5.2 Comparison of Assembly Structures like Figure 5 As shown, the optimization effect of this invention can be clearly seen through disassembly and comparison: Baseline code characteristics: It is filled with a large number of stack frame operation instructions such as addi sp, -64, sw s0, 48(sp), etc. Each function boundary has a complete Prologue and Epilogue, and the data flow presents a V-shaped pattern of "register → stack → register". The code features of this invention: primitives are tightly concatenated, stack operation instructions are almost invisible, stackless execution for logic flow is achieved, and the data flow presents a horizontal linear pattern of "register → register".
[0106] Code size comparison: The baseline is 4,820 bytes (.text segment), while this invention is 1,750 bytes, representing a 63.7% reduction.
[0107] 5.3 Actual Performance Data Metric 1: Total number of instructions executed Use the instruction-level simulator (Spike) to count the number of instructions:
[0108] Cause analysis: Smart sensing yielded the greatest benefit (62.0%): This workload involves a large number of memory access operations, and zero-copy forwarding optimization eliminated approximately 40% of Load / Store instructions. Secure communication yields smaller benefits (18.2%): This workload is computationally intensive, with relatively limited optimization space; the main benefit comes from minimal context switching. Feature extraction yielded moderate gains (30.6%): This workload is memory intensive, and both zero-copy optimization and minimal context contributed to its performance. Metric 2: End-to-end execution time (Latency) GPIO toggle time was measured using a logic analyzer.
[0109] Indicator 3: System Energy Consumption Measurements were taken using a Nordic PPK2 power analyzer (sampling rate 100kHz).
[0110] Reasons for reduced energy consumption: Reduced instruction count: Fewer instructions mean the CPU is active for a shorter period of time. Reduced memory access: Load / Store operations consume approximately 10-20 times more energy than register operations. Reduced context switching: Minimal context set reduces stack accesses. Practical application value: Assuming an IoT sensor node performs 10,000 "smart sensing" tasks per day: The baseline daily energy consumption is approximately 452 mJ → with a 500mAh button cell battery (3.0V, 1.5Wh), it can operate for approximately 3,311 days (approximately 9 years). The present invention consumes approximately 178 mJ per day → and can operate for approximately 8,427 days (approximately 23 years). This invention can extend battery life by approximately 2.5 times, which has significant commercial value for deployment in remote areas or difficult-to-maintain scenarios.
[0111] Experimental data show that the global activity analysis and context optimization method for atomic task flows proposed in this invention significantly overcomes the performance bottlenecks of traditional compilers and RTOS while ensuring functional correctness. ABI boundary overhead is eliminated: cross-task optimizations that compilers cannot achieve are realized through zero-copy register forwarding.
[0112] Minimize context switching: By dynamically calculating C_min, the saving of unused registers is avoided.
[0113] Ultimate energy efficiency: Achieves a 60.6% reduction in energy consumption under "smart sensing" loads, making it particularly suitable for battery-powered devices.
[0114] The above embodiments are used to explain and illustrate the present invention, but not to limit the present invention. Any modifications and changes made to the present invention within the spirit and scope of the claims shall fall within the protection scope of the present invention.
Claims
1. A global register activity analysis and context switching optimization method for atomic task flows, characterized in that, Includes the following steps: S1: Task Flow Linearization: Obtain a directed acyclic graph structure describing the task execution logic, where nodes represent atomic tasks and edges represent data dependencies; each atomic task is associated with register semantic metadata for code generation, which includes at least input register interface constraints, output register interface constraints, and a polluted register list or register read / write set; transform the directed acyclic graph into a linear execution sequence that satisfies the data dependency constraints; S2: Global Activity Analysis: Traverse the linear execution sequence and calculate the active interval of each data variable based on the data dependencies between the atomic tasks. The active interval represents the time span from when the data variable is generated to when it is last used. S3: Zero-copy register forwarding: When allocating physical registers for adjacent tasks, determine whether the output data of the preceding task can be directly passed to the following task through the physical register; if it is determined that it can be passed, lock the physical register carrying the output data so that the physical register is not reallocated before the end of the active period of the output data, and skip the instruction to load the output data from memory when generating the machine code of the following task. S4: Minimal Context Switch Generation: Extract the polluted register list or register write set corresponding to each atomic task in the linear execution sequence, and calculate their union to obtain the full polluted set; obtain the set of registers that the target processor architecture requires to be retained at the context switch point; calculate the intersection of the full polluted set and the set of registers that need to be retained as the minimum register set; based on the minimum register set, generate context switch code containing only the necessary register save and restore instructions at the context switch point.
2. The method according to claim 1, characterized in that, The nodes of the directed acyclic graph contain references to atomic primitives, which have predefined metadata, including at least a list of input registers, a list of output registers, and a list of polluted registers.
3. The method according to claim 1, characterized in that, The active interval calculation method described in step S2 includes: identifying the definition point of each data variable and recording it as the starting position of the active interval of that variable; identifying the last usage point of each data variable and recording it as the ending position of the active interval of that variable; defining the task sequence index interval between the starting position and the ending position as the active interval of that variable; constructing an interferogram based on the active interval, wherein the nodes of the interferogram represent data variables, and if the active intervals of two data variables overlap, an edge is added between the corresponding nodes to indicate that the two variables cannot be assigned to the same physical register.
4. The method according to claim 1, characterized in that, Step S3, which determines whether the output data of the preceding task can be directly passed to the subsequent task, includes the following checks: Data dependency check: Check whether the output data variable of the preceding task is used as the input data variable by the following task, and whether the active range of the output data variable covers the reading position of the following task; Safety gap check: Extract the polluted register list or register write set of the intermediate tasks between the preceding task and the following task and calculate their union to verify that the physical register carrying the output data has not been modified by any intermediate task between the two tasks. Interface alignment check: Verify that the physical registers simultaneously satisfy the output register interface constraints of the preceding task and the input register interface constraints of the following task, and do not conflict with the reserved registers or calling convention constraints of the target processor architecture.
5. The method according to claim 1, characterized in that, The minimum register set mentioned in step S4 is calculated in the following way: Extract the polluted register list or register write set corresponding to each atomic task in the linear execution sequence; Calculate the union of the polluted register list or register write set to obtain the full polluted set Sclobber; Obtain the set of registers that the target processor architecture requires to be retained at the context switching point, wherein the retain set includes at least the set of registers that need to be retained as specified in the application binary interface (ABI) or calling convention; and, when the task flow contains a call instruction that will rewrite the return address register, the retain set also includes the return address register. Calculate the intersection of the full contaminated set and the set of registers to be kept: Cmin = Sclobber ∩Skeep, and use this intersection as the minimum set of registers.
6. The method according to claim 5, characterized in that, Context switching code is generated based on the minimum register set Cmin, including: Prologue generation: At the entry point of the context switch, traverse each register in Cmin and generate an instruction to save the register value to the stack or a predetermined storage area. Generate Epilogue: At the exit of the context switching point, traverse each register in Cmin and generate an instruction to restore the register value from the stack or a predetermined storage area. When the minimum register set Cmin is empty, zero-overhead context switching code is generated. The zero-overhead context switching code does not contain register save and restore instructions and is used to complete the control flow transfer at the context switching point.
7. The method according to claim 1, characterized in that, The method also includes a register allocation correctness verification process, which specifically includes the following steps: V1: Obtain the data to be verified: Obtain the machine code, register allocation table, and active range information of data variables generated through global register activity analysis; V2: Perform static activity check: Construct an interferogram based on the active interval information to verify whether the physical register assigned to each data variable has not been assigned to other data variables with overlapping active intervals within its active interval; if a conflict is found, mark it as an activity conflict error; V3: Perform forwarding legality checks: For task node pairs marked as "zero-copy forwarding", verify whether the output register of the preceding task has indeed not been modified by the intermediate task during the execution of the following task; if modification is found, mark it as a forwarding security error; V4: Output Verification Report: Generates a verification report containing all detected errors, error locations, and suggested remedial measures.
8. The method according to claim 7, characterized in that, The forwarding legitimacy check described in step V3 includes: Extract the output register identifier Rout from the preceding task; Extract the list of polluted registers for all intermediate tasks between the preceding and following tasks; Calculate the union of all polluted register lists, Sgap; If Rout ∈ Sgap, then forwarding is deemed insecure and marked as an error.
9. The method according to claim 7, characterized in that, The verification report also includes at least one of the following optimization recommendations: For liveness conflict errors, it is recommended to adjust the register allocation scheme or perform a register overflow (Spill) operation; For the forwarding security error, it is recommended to disable zero-copy forwarding optimization and restore the generation of standard memory loading instructions; If the minimum context set is calculated incorrectly, it is recommended to rescan the polluted register list of the task sequence.
10. A global register activity analysis and context switching optimization system for atomic task flows, characterized in that, include: Linearization module: Used to transform a directed acyclic graph (DAG) of task dependencies into a linear execution sequence that satisfies data dependency constraints; Activity analysis engine: used to calculate the active interval of each data variable in the linear execution sequence and construct an interferogram based on the active interval; Zero-copy optimizer: used to analyze the data transfer relationship between adjacent tasks, determine whether zero-copy forwarding can be achieved by locking physical registers, and control the code generator to skip redundant memory load instructions; Context generator: Used to extract the full sludge set Sclobber of the task flow, obtain the set of registers required to be retained by the target processor architecture at the context switching point, where the retain set includes at least the set of registers to be retained as specified in the application binary interface (ABI) or calling convention; and when the task flow contains a call instruction that modifies the return address register, the retain set also includes the return address register, and calculates the minimum register set Cmin = Sclobber ∩ Retain, and generates minimal context switching code based on the minimum register set; Verification Subsystem: Performs static liveness checks and forwarding legitimacy checks on the generated register allocation scheme and outputs a verification report.