1. Introduction
With the development of heterogeneous computing, the GPGPUs have become one of the mainstream accelerator architectures, able to handle a wide range of computational tasks. The data level parallelism (DLP) of GPGPUs is usually realized based on the SIMT execution model. SIMT is a high-level abstraction at the programming model and thread scheduling level. Each thread executes independently, with its own instruction address and register state. Threads within a warp are of the same type and start from the same program address. Instructions are broadcast synchronously to the active threads in the warp, while individual threads may become inactive due to independent branching or predicates [
1,
2,
3]. At the hardware level, GPU execution units fundamentally perform parallel execution in a Single Instruction Multiple Data (SIMD) model, threads are mapped to the lanes of the underlying execution units [
2,
4,
5].
Under the SIMT execution model, GPGPUs leverage parallel programming models such as CUDA [
5] and OpenCL [
6] for multithreaded scheduling. This enables efficient utilization of data parallelism, significantly boosting computational speed while maintaining relatively low hardware resource overhead. This particular suitability for data-parallel computing makes GPGPUs a core acceleration platform for large scale parallel computing scenarios, widely applied in fields such as scientific computing and artificial intelligence [
7]. In these applications, GPGPUs not only handle computationally intensive workloads but also act as an important computing platform with relatively low power consumption thanks to their high degree of parallelism.
Meanwhile, both academia and industry are exploring lighter and more open architectures to meet the demands for flexibility and portability across diverse application scenarios. In recent years, with the emergence of the open-source RISC-V instruction set [
8,
9,
10], GPGPU designs based on the RISC-V architecture have gradually become a research hotspot, attracting widespread attention from both academia and industry. Compared to traditional closed source architectures, the RISC-V architecture offers high customizability and modular extensibility, providing a solid foundation for building GPGPU systems.
GPUs use two mechanisms to schedule the execution of multiple threads. First, threads are grouped into warps, and in each cycle, the warp scheduling mechanism selects the active warps for execution [
11]. Second, the control flow management mechanism determines which threads within an active warp are active. The control flow management mechanism handles the differences in thread execution paths caused by divergences, loops, and function calls during execution. It can be controlled or assisted by software through instructions in the ISA to achieve optimal and efficient thread scheduling. In GPUs, a group of threads within a warp usually executes the same instruction in parallel. When encountering conditional statements that require different control flow paths, branch divergence occurs, and the branch control mechanism is needed to decide the execution paths [
12].
Due to the occurrence of divergence, the execution paths are split into multiple sub-paths, resulting in serialized execution and performance degradation. Therefore, GPGPUs still face challenges in methods involving control flow divergence decisions. The handling of thread divergence and reconvergence is essential for preserving consistent execution and efficient thread scheduling [
13]. Modern GPUs rely on dedicated control flow management mechanisms to coordinate thread activity, deciding which threads in a warp should participate in the execution of each instruction. These mechanisms can be controlled or assisted by software through instructions within the ISA to achieve optimal and efficient thread scheduling [
14]. All complete GPU ISAs provide standard branch instructions. NVIDIA’s PTX [
15] and SASS rely on predicate-based control to manage thread activation, while AMD’s CDNA [
16] adopts a thread mask mechanism. In addition, AMD’s GCN [
17] introduces explicit split and join instructions to directly manage thread divergence and reconvergence. Improving program performance in the presence of divergence has also become an active research topic in recent years. Saumya et al. employed compiler techniques, such as DARM, to reduce divergence under the SIMT execution model [
18]. Bagies et al. focused on accelerating parallel execution by minimizing branch divergence [
19]. P Plebański et al. mitigated execution divergence in GPGPU computing through dynamic data remapping [
20].
Research on GPGPUs based on the RISC-V architecture is still in its early stage of development. Vortex developed a GPGPU system solution based on RISC-V scalar instructions and designed a minimal instruction set extension to support the SIMT execution model [
21]. Ventus adopted the RISC-V vector instruction extension to construct a GPGPU architecture, exploring the application of vectorization in parallel processing [
22,
23]. These pioneering works fully demonstrate the flexibility and customizability of the RISC-V architecture for GPGPU design, providing a solid foundation for subsequent research.
Due to the dependence on the RISC-V, branch prediction is not supported in the GPU design. In Vortex, the SIMT stack mechanism is adopted to manage control flow. The split instruction pushes information about the current thread mask (tmask), the new thread mask and Program Counter (PC) onto the Immediate Post-Dominator (IPDOM) stack [
24], while the join instruction pops this information during reconvergence [
25]. To reduce the performance overhead caused by divergent branches, this paper introduces a thread-mask-based branch control mechanism for RISC-V GPGPU. It maintains thread mask information in dedicated registers and updates it through logical operations with predicate results, thereby controlling the activity of each thread and realizing control flow. This approach eliminates the need for complex branch stack and PC jump, significantly reducing the pipeline overhead caused by control path switching. At the same time, due to the characteristics of the RISC-V architecture, the proposed thread mask mechanism was adapted accordingly, making it different from traditional thread mask mechanisms. The design and execution model were implemented on the RISC-V GPGPU platform Vortex SimX [
26], and the performance overhead caused by divergence was evaluated through microbenchmark testing.
This paper makes the following contributions:
We propose a high-performance branch control mechanism under the RISC-V instruction set architecture and design a mask control instruction set based on logical operations.
The RISC-V instruction set architecture restricts the storage of thread masks in conventional thread-local registers, so the thread mask is stored in Control and Status Registers (CSRs) instead, which differs from traditional GPU architectures such as AMDs. The proposed branch control mechanism was adapted to this architectural characteristic.
In Vortex, the original SIMT pipeline relies on the PC and IPDOM stack to manage control flow, which cannot support the thread mask mechanism. To address this limitation, the proposed mechanism was modeled and validated on the Vortex SimX platform.
The rest of this paper is structured as follows.
Section 2 reviews prior research related to control flow and briefly introduces the control flow characteristics of mainstream instruction set architectures.
Section 3 provides a comprehensive explanation of the proposed control mechanism, outlines the existing SIMT stack mechanism in the RISC-V architecture, and presents a comparative analysis between the two.
Section 4 describes in detail the modeling and implementation of the mechanism, while
Section 5 presents the performance evaluation and discussion of the experimental results. Conclusions are provided in
Section 6.
3. Branch Control Method
When threads within the same warp take different control paths upon encountering a conditional branch, the architecture must provide a mechanism to coordinate their divergence and reconvergence. In
Section 3.1, we describe the original SIMT stack mechanism in the current Vortex architecture, and the following sections provide a complete introduction to our thread-mask-based control mechanism. The two mechanisms reflect different control flow management models in terms of execution semantics and architectural design.
3.1. SIMT Stack Mechanism
When divergence occurs within a warp, the system generates multiple sub-paths based on the branch predicates of individual threads, where each path corresponds to a specific subset of threads. Two new instructions, split and join, are introduced to manage thread divergence and reconvergence in parallel execution [
25]. During branch execution, information about inactive branches must be preserved, which is handled through an SIMT stack mechanism. In the Vortex architecture, this functionality is implemented using an IPDOM scheme, and each warp is equipped with its own stack to maintain correct coordination and restoration of thread execution paths [
21,
26].
In a reconvergence mechanism that uses a post-dominator stack [
24], each entry corresponds to a specific branch level. When a warp encounters a branch instruction, the SIMT stack module determines the next instruction address according to the branch condition, ensuring that every thread in the warp follows the correct execution path. At the same time, the module tracks the branch condition for each thread to determine whether it satisfies the condition and selects the appropriate execution path accordingly.
By inserting a split instruction before the branch and a join instruction after it, the SIMT stack mechanism can be implemented. The detailed divergent execution process is shown in Algorithm 1 (summarized based on Vortex [
25]).
| Algorithm 1 Branch Execution with SIMT Stack |
| Input: warp PC, active thread mask active_mask, branch predicate cond, next PC next_pc |
| Output: updated warp PC and thread mask |
| 1: | then_mask = active_mask ∧ cond |
| 2: | else_mask = active_mask ∧ ~cond |
| 3: | push (active_mask, else_mask, next_pc) onto IPDOM Stack |
| 4: | next_mask = mask with more active threads |
| 5: | set next_mask to warp active mask |
| 6: | execute threads in next_mask |
| 7: | retrieve current thread stack pointer stack_ptr (saved IPDOM Stack depth) |
| 8: | if stack_ptr ≠ current IPDOM Stack size then |
| 9: | if IPDOM Stack is empty then |
| 10: | error: stack underflow |
| 11: | end if |
| 12: | if top of stack fallthrough flag is true then |
| 13: | active_mask = top.orig_mask |
| 14: | pop top of stack |
| 15: | else |
| 16: | active_mask = top.else_mask |
| 17: | PC = top.PC |
| 18: | mark top.fallthrough = true |
| 19: | end if |
| 20: | end if |
When entering a branch, the split instruction divides the control paths and pushes branch point information onto the stack. Each stack entry stores the target PC of the new branch, the reconvergence PC, and the thread mask corresponding to the threads diverging to that branch. The join instruction triggers a stack pop at the reconvergence point, restoring the active state of threads and merging the control paths, ultimately completing the reconvergence of the warp and concluding branch execution [
21,
25].
As shown in
Figure 2, the program starts from the entry node and reaches node A, where it branches. Depending on the condition, it follows different execution paths B and C. Both B and C have D as their post-dominator, and threads reconverge at node D. The arrows in the figure indicate the active threads in the warp at each state (taking a four-thread example). The control mechanism inserts a split before entering the branch. The split pushes the contexts of each path onto stack entries, as shown in
Table 2, and pops the entries when entering the corresponding path.
Table 2 shows the entry information inside the IPDOM stack in the SIMT stack mechanism.
3.2. Thread Mask Mechanism
3.2.1. Overview
The fundamental idea of the thread mask control mechanism is to manage thread activity directly through a dedicated mask register, effectively transforming dynamic control flow into logical operations on the thread mask. The system assigns each warp a private thread mask register, where each thread is represented by a single bit activity flag. These flags are uniformly encoded as bitmasks and stored within the thread mask register. A bit value set to 1 indicates that the corresponding thread is active in the current cycle and participates in subsequent instruction scheduling and execution. Conversely, a bit value set to 0 means that the thread is masked out during that cycle. By performing bitwise operations on the mask, the architecture enables explicit control over thread-level execution flow.
When a divergence occurs within a warp, the system first computes a dynamic Boolean mask based on the branch predicates. The thread mask register is then updated using logical operation instructions such as AND, OR, and XOR, explicitly controlling the execution paths of individual threads and adapting the thread mask to the specific branch condition. The updates to the thread mask rely entirely on these dedicated mask logic instructions. The results of these operations are used solely to update the state of the thread mask register and do not consume resources from the conventional Arithmetic Logic Unit (ALU). Unlike conventional branch mechanisms that rely on jumps, this mechanism advances branches under a single PC path. To support reversible thread states and path merging, the system stores the current thread mask before branch divergence. After all sub-paths are executed, a mask restore instruction is used to roll back the thread mask, achieving thread reconvergence without jumps or stack operations, as shown in Algorithm 2.
| Algorithm 2 Branch Execution with Thread Mask |
| Input: current thread mask exec_mask, branch condition cond |
| Output: updated thread mask exec_mask |
| 1: | exec_start = exec_mask |
| 2: | exec_if = exec_start ∧ cond |
| 3: | for each thread i in warp do |
| 4: | if exec_if[i] == 1 then |
| 5: | execute_if_path (thread i) |
| 6: | end if |
| 7: | end for |
| 8: | exec_else = exec_start ⊕ exec_if |
| 9: | for each thread i in warp do |
| 10: | if exec_else[i] == 1 then |
| 11: | execute_else_path (thread i) |
| 12: | end if |
| 13: | end for |
| 14: | exec_mask = exec_if ∨ exec_else |
The branch execution process is shown in
Figure 3. When the branch condition is satisfied, the set of truth value threads generated by the Boolean predicate will be mask-activated and enter the if branch path, threads that do not satisfy the condition will activate in the else branch. After evaluating the conditional predicate, a Boolean flag is generated for each thread. The logical AND operation instruction performs a bitwise AND operation between this flag bit and the current thread mask, yielding the thread mask for the condition being true. Simultaneously, the logical AND operation instruction directly updates the thread mask register and preserves the mask state prior to divergence. The warp then proceeds to execute the if branch. Using logical XOR instruction to perform an XOR operation between the initial thread mask and the thread mask of the if branch generates the thread mask corresponding to the else branch. To execute multiple branches or other complex branching logic, the corresponding masks can be constructed by combining multiple predicate results with logical operation instructions. During the thread convergence phase, since the warp records the mask state before entering the divergence, convergence can be achieved either by restoring the initial mask directly through the thread mask set instruction, or by gradually restoring the thread states of all sub paths using the mask merge instruction, allowing all threads to reunite on a unified execution path.
3.2.2. Extension of Mask Logical Operation Instruction Set
RISC-V is an open-source instruction set architecture that follows the Reduced Instruction Set Computing (RISC) philosophy. Its base instruction set employs a fixed 32-bit instruction length, defining different instruction formats through opcodes, function codes (func3, func7), and register fields (rd, rs1, rs2) to define different instruction formats. The most common formats include R-type, I-type, and S-type.
The RISC-V instruction set specification reserves custom opcode space to support user-defined extensions. The logical operation instructions extended in this study all adopt the R-type instruction format, as shown in
Figure 4. R-type instructions define a 3-bit func3 field and a 7-bit func7 field. The operand combination follows the general form C = f (A, B). For single input operations, one of the operands is set to the integer register x0, which always holds the value of 0.
To support fine-grained control flow management at the thread level, this paper proposes and implements eight mask logic operation extensions to the RISC-V instruction set. These instructions are specifically designed to perform Boolean logic transformations on the thread mask, dynamically adjusting the activation state of threads to handle complex control flow divergence and reconvergence patterns. All new instructions follow a consistent semantic structure: before performing the logical operation, the current thread mask is saved to the destination register for subsequent state recovery or mask merging. Subsequently, thread mask is updated based on the result of the logical operation between the source operand and the old mask.
The new instructions not only cover conventional Boolean operations (AND, OR, XOR) but also include their negated logical forms (such as NAND, NOR, XNOR, ANDN2, ORN2), enabling more flexible expression of active thread sets. If only using basic logical operations, additional NOT instructions or extra registers are often required to construct new target masks, which increases control overhead. By directly supporting negated logic at the instruction level, the control flow code sequence can be significantly simplified and register pressure can be reduced. The new instruction set encompasses operations as shown in
Table 3.
3.2.3. CSR Register Constraint
In the implementation of mask state updates, different GPU architectures exhibit different register models. AMD GPUs employ the exec mask to indicate currently active work items, stored in special scalar general-purpose register (SGPR) within a wavefront [
16]. Essentially, it is still a scalar general-purpose register, allowing any logical instruction to modify it directly, including both ordinary logical instructions and control flow logic instructions. That is, the target register for standard logical instructions can be either the exec register itself or any other general-purpose register. This design ensures flexible mask modification and preservation.
In GPUs designed based on the RISC-V architecture, the exec register is implemented as a dedicated CSR that can only be modified by control flow logic instructions. This mechanism ensures structured management of the thread mask state but reduces the direct programmability of logical instructions. This means that mechanisms like in traditional GPUs, which rely on logical instructions to directly modify the exec register, cannot be implemented. To balance flexibility and security, this study employs the Vortex TMC instruction to assist in branch reconvergence. TMC is an extension instruction in RISC-V designed for GPU adaptation, which allows the desired thread mask to be provided as input and directly updates the warp’s thread mask.
In this mechanism, thread reconvergence can still be achieved through control flow logic instructions. However, when the process becomes overly complex, the TMC instruction cooperates to complete reconvergence, enabling the RISC-V architecture to realize equivalent thread-mask operations under CSR constraints. This mechanism separates mask updates from the general instruction domain, making thread-activity management more deterministic and providing a feasible approach for implementing fine-grained thread control in RISC-V GPGPUs.
3.3. Mechanism Comparison
The SIMT stack mechanism can maintain high execution efficiency in scenarios with long branch paths. In such cases, the frequency of branch instructions is relatively low, and the overhead of branching and stack operations occupies only a limited proportion of the total execution cycles; thus, it does not significantly affect the overall performance. In contrast, the thread mask mechanism switches control flow by updating masks without the need for branch instructions, effectively reducing pipeline stalls and instruction overhead, thereby achieving higher execution efficiency.
In highly divergent scenarios, the need to maintain multiple masks simultaneously and the increased number of idle threads may incur additional execution cycle overhead. Therefore, in complex branching scenarios, both mechanisms incur significant overhead. As the branch path length decreases or the branching complexity increases, the SIMT stack mechanism triggers frequent stack push/pop and PC jump operations, which substantially increase the burden on control logic and storage resources. When there are numerous short branches, the performance of the SIMT stack mechanism degrades rapidly; in contrast, under complex branch structures such as nested branches, the thread mask mechanism tends to experience greater performance loss. Furthermore, since the SIMT stack mechanism requires a hardware IPDOM stack to preserve execution context, each warp must maintain its own independent branch stack. As the degree of parallelism increases, the total stack resource consumption also rises, leading to higher hardware implementation and maintenance costs.
6. Conclusions
The study introduces and implements a high-performance branch control mechanism based on a thread mask to address control flow processing challenges in RISC-V GPGPU architectures. The original SIMT stack mechanism relies on split/join branch instructions for control and path management, where the stack module computes target addresses for different paths, records them in stack entries, and selects the correct execution path through conditional jumps and push/pop operations. In contrast, the proposed thread mask mechanism determines thread activity through mask control instructions that apply logical operations between the thread mask and the predicate of each condition. It sequentially generates the thread masks for different paths to achieve fine grained divergence and reconvergence within a warp, thereby eliminating the need for PC jumps and branch stack operations and improving the performance of branch divergence handling. A software implementation and microbenchmark evaluation were conducted on the Vortex cycle-accurate simulator to assess the execution performance of two control mechanisms under various levels of parallelism. Experimental results show that, across diverse branch scenarios, the thread mask mechanism reduces branch instruction execution cycles by an average of approximately 31%, with a maximum reduction of 40%, while improving SIMT pipeline performance. This work provides a feasible and efficient solution for control flow optimization in RISC-V GPGPU architectures.
This work focuses on architectural exploration and mechanism evaluation using the cycle-accurate SimX simulator, and on integrating the thread mask mechanism into the Vortex pipeline architecture. The C++ compiler is already compatible with this work, and we are currently optimizing the OpenCL toolchain to support high level parallel programming language. Future research will focus on a complete hardware implementation, further validating the advantages of the thread mask control mechanism through hardware analysis.