动手实现一个 RISC-V GPGPU (二) : 指令集设计

前言

在上一篇文章中, 我们介绍了 NVIDIA GPU 的 SIMT 编程模型以及 CUDA 和 PTX 指令集中 SIMT 编程模型的实现. 在 RISC-V 指令集中, 目前还没有提供类似的并行计算相关功能的指令集拓展, 因此我们需要自己设计一个指令集拓展来支持 SIMT 编程模型. 在本文中, 我们将介绍我们设计的指令集拓展的细节.

指令集设计

Gelato GPU 指令集设计的基本目标为: 提供对于 SIMT 编程模型与 CUDA 指令集的良好支持, 同时尽可能简化指令集的设计. 为了实现这一目标, 指令集设计的基本思路为: 基础指令集 + SIMT 指令集 + 控制状态寄存器 (CSR) .

基础指令集

为了尽可能简化指令集的设计, Gelato GPU 使用的指令集的很大一部份均为原始的 RISC-V 指令集. 为了支持基本的算术与访存操作, 我们选取 RV32IMA 作为基础指令集, 未来还将加入对于单精度浮点运算的支持.

在 RV32IMA 指令集中, 由于 SIMT 编程模型可能出现的 branch divergence 问题, 以下一些指令可能受到影响, 出现未定义行为:

  • 跳转指令: JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU. 由于 SIMT 编程模型中不同线程的寄存器值可能各不相同, 因此编译器在代码生成阶段需要保证这些指令的跳转目标地址是相同的, 否则程序的运行结果将不可预期.
  • 存储指令: SB, SH, SW. 由于可能出现不同线程同时向同一位置写入数据的情况, 因此对于地址相同而数据不同的 store 类型指令, 程序的运行结果将不可预期.
  • 原子指令集: 不支持 AMOSWAP.W;对于 SC.W 有与同 store 操作相同的要求;对于其他算术原子指令, 目的寄存器的值可能不符合预期.
  • FENCE 指令: 将同时起到 synchronize threads 的作用, pred 和 succ 将被替换为表示 synchronize 范围的参数.

SIMT 指令集

为了支持 SIMT 编程模型, 我们需要在基础指令集的基础上加入一些指令, 以支持线程同步等操作. 由于该指令集与 RISC-V 的 Vector 拓展不兼容, 此处选取 Vector 拓展的 Opcode 作为该拓展的 Opcode.

  • 为了处理 branch divergence 问题, 我们需要加入指令以支持线程不一致的分支操作, 包含 BEQ.D 和 BNE.D, 格式如下:

      31-25 24-20 19-15 14-12 11-7 6-0
      imm rs2 rs1 funct3 imm opcode
    BEQ.D offset[12|10:5] src2 src1 010 offset[4:1|11] 1100111
    BNE.D offset[12|10:5] src2 src1 011 offset[4:1|11] 1100111


  • 为了进行 reduce 操作, 我们引入指令 REDADD, REDAND, REDOR, REDXOR, REDMIN, REDMAX, REDMINU, REDMAXU, 格式如下:

      31-25 24-20 19-15 14-12 11-7 6-0
      funct7 rs2 rs1 funct3 rd opcode
    REDADD 0000000 thread mask src 010 rd 1010111
    REDAND 0110000 thread mask src 010 rd 1010111
    REDOR 0100000 thread mask src 010 rd 1010111
    REDXOR 0010000 thread mask src 010 rd 1010111
    REDMIN 1000000 thread mask src 010 rd 1010111
    REDMAX 1010000 thread mask src 010 rd 1010111
    REDMINU 1110000 thread mask src 010 rd 1010111
    REDMAXU 00011100 thread mask src 010 rd 1010111


  • 为了进行 select 操作, 我们引入指令 SEL, 格式如下:

      31-27 26-25 24-20 19-15 14-12 11-7 6-0
      rs3 01 rs2 rs1 funct3 rd opcode
    SEL src2 01 src1 cond 011 rd 1010111


  • 为了加速矩阵乘法, 我们引入了硬件矩阵乘法指令, 格式如下:

      31-27 26-25 24-20 19-15 14-12 11-7 6-0
      imm/rs3   rs2 rs1 funct3 rd opcode
    MMADD matrix.c 10 matrix.b matrix.a step rd 1010111
    MMADD.U matrix.c 11 matrix.b matrix.a step rd 1010111
    MLOAD imm[11:0]     src 101 rd 0000111
    MSTORE imm[11:5]   src2 src1 110 imm[4:0] 0100111


控制状态寄存器

  • 为了实现 CUDA 指令集中的 grid, block, thread 等信息的维度与编号, 引入以下控制状态寄存器:
    • gridDimX, gridDimY, gridDimZ: 表示 grid 的维度.
    • blockDimX, blockDimY, blockDimZ: 表示 block 的维度.
    • blockIdxX, blockIdxY, blockIdxZ: 表示当前 block 的编号.
    • threadIdxX, threadIdxY, threadIdxZ: 表示当前 thread 的编号.