CSAPP 家庭作业4.57
A
对于没有加载转发的情况下,加载/使用冒险的条件为:
E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB };
根据题干,我们可以得到加载转发的使用条件和效果:
- 当前指令从内存中读取一个值到寄存器,将该寄存器作为源操作数
- 下一条指令不会在执行阶段使用源操作数,会在访存阶段将源操作数写入内存,例如指令:
rmmov
,push
- 添加一条旁路,将内存输出信号(
m_valM
)转发到流水线寄存器M中的valA字段(转发到e_valA
)。
加载转发是在加载/使用冒险的组合中一种特殊的情况,可以不必使用暂停从而规避冒险。
那么能够使用加载转发的条件是什么?
- 当前指令会从内存中取值放入寄存器rX(处于访存阶段),例如指令
mrmov
和pop
- 下一条指令会将rX作为源操作数(处于执行阶段),写入内存:
- 写入内存的指令:
rmmov
,push
(没有call
指令,因为call
不需要rX作为操作数) - 将操作数写入内存:类似
mrmovq xxx,rX;pushq rX
的形式,即E_srcA == M_dstM
- 写入内存的指令:
最终得到加载转发的条件:
E_icode in { IMRMOVQ, IPOPQ } && E_srcA == M_dstM
在出现加载转发之前,加载/使用冒险的条件是
E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB };
我们需要对E_dstM in { d_srcA, d_srcB }
进行进一步的讨论:
-
E_dstM == d_srcA
代表着当前指令写入的寄存器,是下一条指令中的源操作数。如果下一条指令是mrmov
或push
,这样就满足了加载转发的情况,从而规避了加载/使用冒险,所以冒险发生的情况应该是:E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ });
-
E_dstM == d_srcB
代表当前指令写入的目标寄存器,在下一条指令中不会被用作源操作数,显然这不满足加载转发,所以当前情况下一定会发生冒险 -
综上所述,在存在加载转发的情况下,加载/使用冒险发生的条件是:
E_icode in { IMRMOVQ, IPOPQ } && ( E_dstM == d_srcB || ( E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ }) ) );
B
改动1
由于有了加载转发,所以满足条件时,可以转发给下一条指令的源操作数。此时当前指令在访存阶段,下一条指令在执行阶段,所以时e_valA
接受m_valM
word e_valA = [
E_icode in { IRMMOVQ, IPUSHQ } && E_srcA == M_dstM: m_valM;
1 : E_valA; # Use valA from stage pipe register
];
改动2
加载/使用冒险条件的改变,流水线寄存器的暂停条件也发生变化。
bool F_stall =
# Conditions for a load/use hazard
## Set this to the new load/use condition
(E_icode in { IMRMOVQ, IPUSHQ } &&
(
E_dstM == d_srcB ||
(
E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
)
)
) ||
# Stalling at fetch while ret passes through pipeline
IRET in { D_icode, E_icode, M_icode };
# Should I stall or inject a bubble into Pipeline Register D?
# At most one of these can be true.
bool D_stall =
# Conditions for a load/use hazard
## Set this to the new load/use condition
(
E_icode in { IMRMOVQ, IPUSHQ } &&
(
E_dstM == d_srcB ||
(
E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
)
)
);
bool D_bubble =
# Mispredicted branch
(E_icode == IJXX && !e_Cnd) ||
# Stalling at fetch while ret passes through pipeline
# but not condition for a load/use hazard
!(E_icode in { IMRMOVQ, IPOPQ } && (E_dstM == d_srcB || (E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })))) &&
IRET in { D_icode, E_icode, M_icode };
bool E_bubble =
# Mispredicted branch
(E_icode == IJXX && !e_Cnd) ||
# Conditions for a load/use hazard
## Set this to the new load/use condition
(
E_icode in { IMRMOVQ, IPUSHQ } &&
(
E_dstM == d_srcB ||
(
E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
)
)
);