Appearance
题目
在采用"取指、译码/取数、执行、访存、写回"5 段流水线的处理器中,执行如下指令序列:
I1: add s2,s1,s0 // R[s2]←R[s1]+R[s0]
I2: load s3,0(t2) // R[s3]←M[R[t2]+0]
I3: add s2,s2,s3 // R[s2]←R[s2]+R[s3]
I4: store s2,0(t2) // M[R[t2]+0]←R[s2]下列指令对中,不存在数据冒险的是( )。
错因
A
I1 写 s2 → I3 读 s2,明显存在 RAW 数据冒险。可能错把"指令在序列中是否相邻"当成判定依据——其实只要"前者写、后者读同寄存器"就有冒险,相邻不相邻不影响。
B
I2 写 s3 → I3 读 s3,存在 RAW 数据冒险。而且 I2 是 load 指令,s3 在 MEM 段才能拿到结果——这是经典的 load-use 冒险,比普通 RAW 还严重。选 B 的人可能没注意 I3 中"R[s2]+R[s3]"读了 s3。
D
I3 写 s2 → I4 读 s2,存在 RAW 数据冒险。即使 I4 是 store 指令(写主存而不是寄存器),它仍然要读 s2 的值作为写入主存的数据;此时 s2 还没由 I3 写回,存在依赖。"store 指令也要读寄存器"是常见的盲点。
总解析
第一步:列出每条指令的"写"和"读"寄存器
| 指令 | 写 | 读 |
|---|---|---|
I1: add s2, s1, s0 | s2 | s1, s0 |
I2: load s3, 0(t2) | s3 | t2 |
I3: add s2, s2, s3 | s2 | s2, s3 |
I4: store s2, 0(t2) | (写主存) | s2, t2 |
store 关键提醒:store 不写寄存器(写主存),但它要读 s2 的值作为存入主存的数据,还要读 t2 算地址。所以 I4 的"读"列里 s2 和 t2 都要列上。
第二步:检查每个指令对的 RAW 依赖
RAW(Read After Write)= 前者写某寄存器,后者读同一寄存器。
| 指令对 | 前者写 | 后者读 | 交集 | 是否冒险 |
|---|---|---|---|---|
| I1 ↔ I3 | I1 写 s2 | I3 读 | ✓ 冒险(s2) | |
| I2 ↔ I3 | I2 写 s3 | I3 读 | ✓ 冒险(s3,且 load-use) | |
| I2 ↔ I4 | I2 写 s3 | I4 读 | ∅ | ✗ 无冒险 |
| I3 ↔ I4 | I3 写 s2 | I4 读 | ✓ 冒险(s2) |
只有 I2 和 I4 不存在数据冒险。
最终答案是 C(I2 和 I4)。
为什么 I2 和 I4 无冒险:
- I2 写的是 s3
- I4 读的是 s2 和 t2
- 没有任何寄存器既被 I2 写又被 I4 读 → 无数据依赖
注意:I4 的 t2 是 I2 也读过的(load s3, 0(t2)),但两条都读 t2 = RAR(读后读),不构成数据冒险。
判定流程速查(408 选择题里"数据冒险"专指 RAW):
对每个指令对 (前, 后):
若 前.写 ∩ 后.读 ≠ ∅ → 存在 RAW 数据冒险
否则 → 无冒险(即使有 RAR 也算无冒险)易错点速查:
- store 指令仍然读寄存器——它要读"存入主存的数据"那个寄存器
- RAW 才是数据冒险;RAR / WAW / WAR 在五段顺序流水线里都不构成冒险
- 列"读/写"寄存器时不要漏:算术 add 写一个读两个;load 写一个读一个(地址);store 不写寄存器但读两个(地址 + 数据)