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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user