cpu: Fix RAS behaviour when both isReturn and isCall are set.

As discussed in [1], current BP cannot handle the instruction
with both isReturn and isCall on RAS. This hurts the performance
of coroutine-based programs.

This patch adjusts the behaviour of RAS. When the isReturn flag
is set, it will pop a RAS. Then, if the isCall flag is set, it
will push a RAS. Previous implementation only pop a RAS when both
isReturn and isCall are set.

This behaviour follows the RISC-V Spec [2]. Since other ISAs do
not have instructions that set both isCall and isReturn, this
patch has no impact on other ISAs.

[1] https://gem5-review.googlesource.com/c/public/gem5/+/58209
[2] https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf

Change-Id: I52c01bbea41347711edff9ce9a03076e46aadc92
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/63311
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Luming Wang
2022-09-08 02:23:49 +00:00
parent 6807f70b81
commit f43e722238

View File

@@ -173,6 +173,8 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
// Now lookup in the BTB or RAS.
if (pred_taken) {
// Note: The RAS may be both popped and pushed to
// support coroutines.
if (inst->isReturn()) {
++stats.RASUsed;
predict_record.wasReturn = true;
@@ -192,22 +194,25 @@ BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
DPRINTF(Branch, "[tid:%i] [sn:%llu] Instruction %s is a return, "
"RAS predicted target: %s, RAS index: %i\n",
tid, seqNum, pc, *target, predict_record.RASIndex);
} else {
}
if (inst->isCall()) {
RAS[tid].push(pc);
predict_record.pushedRAS = true;
if (inst->isCall()) {
RAS[tid].push(pc);
predict_record.pushedRAS = true;
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
// Record that it was a call so that the top RAS entry can
// be popped off if the speculation is incorrect.
predict_record.wasCall = true;
DPRINTF(Branch,
"[tid:%i] [sn:%llu] Instruction %s was a call, adding "
"%s to the RAS index: %i\n",
tid, seqNum, pc, pc, RAS[tid].topIdx());
}
DPRINTF(Branch,
"[tid:%i] [sn:%llu] Instruction %s was a call, adding "
"%s to the RAS index: %i\n",
tid, seqNum, pc, pc, RAS[tid].topIdx());
}
// The target address is not predicted by RAS.
// Thus, BTB/IndirectBranch Predictor is employed.
if (!inst->isReturn()) {
if (inst->isDirectCtrl() || !iPred) {
++stats.BTBLookups;
// Check BTB on direct branches
@@ -333,6 +338,13 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
while (!pred_hist.empty() &&
pred_hist.front().seqNum > squashed_sn) {
if (pred_hist.front().wasCall && pred_hist.front().pushedRAS) {
// Was a call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Squashing"
" Call [sn:%llu] PC: %s Popping RAS\n", tid, squashed_sn,
pred_hist.front().seqNum, pred_hist.front().pc);
RAS[tid].pop();
}
if (pred_hist.front().usedRAS) {
if (pred_hist.front().RASTarget != nullptr) {
DPRINTF(Branch, "[tid:%i] [squash sn:%llu]"
@@ -350,12 +362,6 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
RAS[tid].restore(pred_hist.front().RASIndex,
pred_hist.front().RASTarget.get());
} else if (pred_hist.front().wasCall && pred_hist.front().pushedRAS) {
// Was a call but predicated false. Pop RAS here
DPRINTF(Branch, "[tid:%i] [squash sn:%llu] Squashing"
" Call [sn:%llu] PC: %s Popping RAS\n", tid, squashed_sn,
pred_hist.front().seqNum, pred_hist.front().pc);
RAS[tid].pop();
}
// This call should delete the bpHistory.
@@ -477,6 +483,17 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
}
} else {
//Actually not Taken
if (hist_it->wasCall && hist_it->pushedRAS) {
//Was a Call but predicated false. Pop RAS here
DPRINTF(Branch,
"[tid:%i] [squash sn:%llu] "
"Incorrectly predicted "
"Call [sn:%llu] PC: %s Popping RAS\n",
tid, squashed_sn,
hist_it->seqNum, hist_it->pc);
RAS[tid].pop();
hist_it->pushedRAS = false;
}
if (hist_it->usedRAS) {
DPRINTF(Branch,
"[tid:%i] [squash sn:%llu] Incorrectly predicted "
@@ -489,16 +506,6 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
hist_it->RASIndex, *hist_it->RASTarget);
RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget.get());
hist_it->usedRAS = false;
} else if (hist_it->wasCall && hist_it->pushedRAS) {
//Was a Call but predicated false. Pop RAS here
DPRINTF(Branch,
"[tid:%i] [squash sn:%llu] "
"Incorrectly predicted "
"Call [sn:%llu] PC: %s Popping RAS\n",
tid, squashed_sn,
hist_it->seqNum, hist_it->pc);
RAS[tid].pop();
hist_it->pushedRAS = false;
}
}
} else {