1. 前言
Memory consistency model定义了使用Shared memory(共享内存)执行多线程(Multithread)程序所允许的行为规范。RISC-V使用的内存模型是RVWMO(RISC-V Weak Memory Ordering),该模型旨在为架构师提供更高的灵活性,以构建高性能可拓展的设计,同时支持可控制的编程模型。RSIC-V其实还支持Ztso扩展,这是为了方便移植x86或SPARC体系结构的代码,这两种体系结构默认情况下都使用TSO内存模型。至于什么是memory model、有哪些种类memory model以及它们有什么区别,可以看看这篇文章《一文读懂Memory consistency model (内存模型)》。
RISC-V的RVWMO模型主要包含了preserved program order、load value axiom、atomicity axiom、progress axiom和I/O Ordering。今天主要讲下preserved program order(保留程序顺序)中的Syntactic Dependencies(语法依赖)。
2. 语法依赖
RVWMO内存模型的定义部分取决于语法依赖。语法依赖关系是根据指令的源寄存器、指令的目的寄存器以及指令从源寄存器到目的寄存器携带依赖关系的方式来定义的。本文讲述的寄存器指的是整个通用寄存器、CSR的某些部分或整个CSR。
那么什么是源寄存器和目的寄存器呢?可以找到如下定义:
源寄存器定义:一般来说,如果满足下列任何条件之一,寄存器R(除X0)就是指令A的源寄存器:
- 在指令A的操作码中,rs1、rs2或rs3被设置为R;
- A是CSR指令,在A的操作码中,csr被设置为R。如果A是CSRRW或CSRRWI,需要rd不是x0;
- R是CSR,且是指令A的隐式源寄存器;
- R是CSR,它是A的另一个源寄存器别名;
目的寄存器定义:一般来说,如果满足下列任何条件之一,寄存器R(除x0)就是指令A的目的寄存器:
- 在指令A的操作码中,rd被设置为R;
- A是CSR指令,在A的操作码中,CSR被设置为R。如果A为CSRRS或CSRRC,需要rs1不是x0.如果A为CSRRSI或CSRRCI,需要umm[4:0]不是0;
- R是CSR,且是指令A的隐式目的寄存器;
- R是CSR,它是A的另一个目的寄存器别名;
比如有以下load和store指令:
lw x1,0(x2) // x1充当目的寄存器角色
sw x3,0(x4) // x3充当源寄存器角色
内存指令通常还进一步指定哪些源寄存器是地址源寄存器还是数据源寄存器。大多数非内存访问指令都带有从源寄存器到目的寄存器的依赖项。
那么什么是语法依赖呢?可以找到如下定义:
语法依赖定义:如果以下任何一个条件成立,那么指令j通过i的目的寄存器s和指令j的源寄存器r在语法上依赖于指令i。
- s和r是同一个,且在i和j之间排序的程序指令没有r作为目的寄存器;
- 在指令i和指令j之间有指令m,使得以下所有条件都成立:
- 指令m的目的寄存器q和指令j的源寄存器r在语法上存在依赖;
- 指令m的源寄存器p和指令i的目的寄存器s在语法上存在依赖;
- 指令m的p和q存在依赖;
下面两个例子分别对应语法依赖的两种场景:
例子1
指令i:lw x1,0(x2) // x1充当目的寄存器角色
指令j:sw x1,0(x4) // x1充当源寄存器角色
这里指令i和指令j通过x1寄存器形成语法依赖,称作指令j依赖于指令i,因为指令j是younger,指令i是older的。
例子2:
指令i:lw x1,0(x2) // x1充当目的寄存器角色
指令m:add x3,x1,x2 // x1充当源寄存器角色,x3充当目的寄存器角色
指令j:sw x3,0(x4) // x3充当源寄存器角色
这里指令m和指令i通过x1形成语法依赖,指令j和指令m通过x3形成语法依赖,而且指令m的x1和x3存在依赖,因此指令j和指令i存在语法依赖。
3. 语法依赖类别
对于内存访问操作中,Syntactic Dependencies(语法依赖)可以分为syntactic address dependency(地址依赖),syntactic data dependency(数据依赖)和syntactic control dependency(控制依赖)。
为了说明这个三个依赖的不同之处,假设有a和b两个内存操作,i和j分别是生成a和b的指令。
地址依赖:如果r是j的地址源操作数,并且j通过源寄存器r对i有语法依赖,则b有语法地址依赖于a。
指令i (操作a):lw r,0(r1)
指令j (操作b):sw r2,0(r)
数据依赖:如果b是一个store操作,r是j的数据源寄存器,j通过源寄存器r对i有语法依赖,那么b对a有语法数据依赖。
指令i (操作a):lw r,0(r1)
指令j (操作b):sw r,0(r0)
控制依赖:如果在i和j之间有一条指令m,m是一条分支或间接跳转指令,并且m在语法上依赖于i,则b在语法控制上依赖于a。
指令i (操作a):lw r,0(r0)
指令m:bne r,r1,next
指令j (操作b):sw r3,0(r4)
4. 总结
与其他现代内存模型一样,RVWMO内存模型使用语法依赖关系而不是语义依赖关系。换句话说,这个定义取决于被不同指令访问的寄存器的身份,而不是这些寄存器的实际内容。这意味着必须强制执行地址、控制或数据依赖,即使有些情况可以被优化掉。这种选择确保RVWMO与使用这些错误语法依赖关系作为轻量级排序机制的代码保持兼容。