cpu: Use PCStateBase in the branch predictors.

Use PCStateBase instead of TheISA::PCState in the branch predictors.

Change-Id: I0b0867bc09b6191a54d7658813c0b9656c436811
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52055
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Reviewed-by: Earl Ou <shunhsingou@google.com>
Maintainer: Gabe Black <gabe.black@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/cpu/minor/fetch2.cc b/src/cpu/minor/fetch2.cc
index 3c9659c..58b68de 100644
--- a/src/cpu/minor/fetch2.cc
+++ b/src/cpu/minor/fetch2.cc
@@ -156,7 +156,7 @@
         /* Unpredicted branch or barrier */
         DPRINTF(Branch, "Unpredicted branch seen inst: %s\n", *inst);
         branchPredictor.squash(inst->id.fetchSeqNum,
-            branch.target->as<TheISA::PCState>(), true, inst->id.threadId);
+            *branch.target, true, inst->id.threadId);
         // Update after squashing to accomodate O3CPU
         // using the branch prediction code.
         branchPredictor.update(inst->id.fetchSeqNum,
@@ -172,8 +172,7 @@
         /* Predicted taken, not taken */
         DPRINTF(Branch, "Branch mis-predicted inst: %s\n", *inst);
         branchPredictor.squash(inst->id.fetchSeqNum,
-            branch.target->as<TheISA::PCState>() /* Not used */,
-            false, inst->id.threadId);
+            *branch.target /* Not used */, false, inst->id.threadId);
         // Update after squashing to accomodate O3CPU
         // using the branch prediction code.
         branchPredictor.update(inst->id.fetchSeqNum,
@@ -184,7 +183,7 @@
         DPRINTF(Branch, "Branch mis-predicted target inst: %s target: %s\n",
             *inst, *branch.target);
         branchPredictor.squash(inst->id.fetchSeqNum,
-            branch.target->as<TheISA::PCState>(), true, inst->id.threadId);
+            *branch.target, true, inst->id.threadId);
         break;
     }
 }
@@ -206,8 +205,7 @@
         DPRINTF(Branch, "Trying to predict for inst: %s\n", *inst);
 
         if (branchPredictor.predict(inst->staticInst,
-                    inst->id.fetchSeqNum, inst_pc->as<TheISA::PCState>(),
-                    inst->id.threadId)) {
+                    inst->id.fetchSeqNum, *inst_pc, inst->id.threadId)) {
             set(branch.target, *inst_pc);
             inst->predictedTaken = true;
             set(inst->predictedTarget, inst_pc);
diff --git a/src/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc
index 3b93160..34e00d4 100644
--- a/src/cpu/o3/fetch.cc
+++ b/src/cpu/o3/fetch.cc
@@ -524,7 +524,7 @@
 
     ThreadID tid = inst->threadNumber;
     predict_taken = branchPred->predict(inst->staticInst, inst->seqNum,
-                                        next_pc.as<TheISA::PCState>(), tid);
+                                        next_pc, tid);
 
     if (predict_taken) {
         DPRINTF(Fetch, "[tid:%i] [sn:%llu] Branch at PC %#x "
@@ -968,7 +968,7 @@
         if (fromCommit->commitInfo[tid].mispredictInst &&
             fromCommit->commitInfo[tid].mispredictInst->isControl()) {
             branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
-                    fromCommit->commitInfo[tid].pc->as<TheISA::PCState>(),
+                    *fromCommit->commitInfo[tid].pc,
                     fromCommit->commitInfo[tid].branchTaken, tid);
         } else {
             branchPred->squash(fromCommit->commitInfo[tid].doneSeqNum,
@@ -990,7 +990,7 @@
         // Update the branch predictor.
         if (fromDecode->decodeInfo[tid].branchMispredict) {
             branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
-                    fromDecode->decodeInfo[tid].nextPC->as<TheISA::PCState>(),
+                    *fromDecode->decodeInfo[tid].nextPC,
                     fromDecode->decodeInfo[tid].branchTaken, tid);
         } else {
             branchPred->squash(fromDecode->decodeInfo[tid].doneSeqNum,
diff --git a/src/cpu/pred/bpred_unit.cc b/src/cpu/pred/bpred_unit.cc
index 502b345..b1b4503 100644
--- a/src/cpu/pred/bpred_unit.cc
+++ b/src/cpu/pred/bpred_unit.cc
@@ -129,7 +129,7 @@
 
 bool
 BPredUnit::predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
-                   TheISA::PCState &pc, ThreadID tid)
+                   PCStateBase &pc, ThreadID tid)
 {
     // See if branch predictor predicts taken.
     // If so, get its target addr either from the BTB or the RAS.
@@ -137,7 +137,7 @@
     // up once it's done.
 
     bool pred_taken = false;
-    TheISA::PCState target = pc;
+    std::unique_ptr<PCStateBase> target(pc.clone());
 
     ++stats.lookups;
     ppBranches->notify(1);
@@ -179,19 +179,20 @@
             predict_record.wasReturn = true;
             // If it's a function return call, then look up the address
             // in the RAS.
-            TheISA::PCState rasTop = RAS[tid].top();
-            target = inst->buildRetPC(pc, rasTop)->as<TheISA::PCState>();
+            const PCStateBase *ras_top = RAS[tid].top();
+            if (ras_top)
+                set(target, inst->buildRetPC(pc, *ras_top));
 
             // Record the top entry of the RAS, and its index.
             predict_record.usedRAS = true;
             predict_record.RASIndex = RAS[tid].topIdx();
-            predict_record.RASTarget = rasTop;
+            set(predict_record.RASTarget, ras_top);
 
             RAS[tid].pop();
 
             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);
+                    tid, seqNum, pc, *target, predict_record.RASIndex);
         } else {
 
             if (inst->isCall()) {
@@ -214,14 +215,14 @@
                 if (BTB.valid(pc.instAddr(), tid)) {
                     ++stats.BTBHits;
                     // If it's not a return, use the BTB to get target addr.
-                    target = BTB.lookup(pc.instAddr(), tid);
+                    set(target, BTB.lookup(pc.instAddr(), tid));
                     DPRINTF(Branch,
                             "[tid:%i] [sn:%llu] Instruction %s predicted "
                             "target is %s\n",
-                            tid, seqNum, pc, target);
+                            tid, seqNum, pc, *target);
                 } else {
                     DPRINTF(Branch, "[tid:%i] [sn:%llu] BTB doesn't have a "
-                            "valid entry\n",tid,seqNum);
+                            "valid entry\n", tid, seqNum);
                     pred_taken = false;
                     predict_record.predTaken = pred_taken;
                     // The Direction of the branch predictor is altered
@@ -237,27 +238,25 @@
                         RAS[tid].pop();
                         predict_record.pushedRAS = false;
                     }
-                    inst->advancePC(target);
+                    inst->advancePC(*target);
                 }
             } else {
                 predict_record.wasIndirect = true;
                 ++stats.indirectLookups;
                 //Consult indirect predictor on indirect control
-                if (iPred->lookup(pc.instAddr(), target, tid)) {
+                if (iPred->lookup(pc.instAddr(), *target, tid)) {
                     // Indirect predictor hit
                     ++stats.indirectHits;
                     DPRINTF(Branch,
-                            "[tid:%i] [sn:%llu] "
-                            "Instruction %s predicted "
+                            "[tid:%i] [sn:%llu] Instruction %s predicted "
                             "indirect target is %s\n",
-                            tid, seqNum, pc, target);
+                            tid, seqNum, pc, *target);
                 } else {
                     ++stats.indirectMisses;
                     pred_taken = false;
                     predict_record.predTaken = pred_taken;
                     DPRINTF(Branch,
-                            "[tid:%i] [sn:%llu] "
-                            "Instruction %s no indirect "
+                            "[tid:%i] [sn:%llu] Instruction %s no indirect "
                             "target\n",
                             tid, seqNum, pc);
                     if (!inst->isCall() && !inst->isReturn()) {
@@ -266,21 +265,21 @@
                         RAS[tid].pop();
                         predict_record.pushedRAS = false;
                     }
-                    inst->advancePC(target);
+                    inst->advancePC(*target);
                 }
-                iPred->recordIndirect(pc.instAddr(), target.instAddr(), seqNum,
-                        tid);
+                iPred->recordIndirect(pc.instAddr(), target->instAddr(),
+                        seqNum, tid);
             }
         }
     } else {
         if (inst->isReturn()) {
            predict_record.wasReturn = true;
         }
-        inst->advancePC(target);
+        inst->advancePC(*target);
     }
-    predict_record.target = target.instAddr();
+    predict_record.target = target->instAddr();
 
-    pc = target;
+    set(pc, *target);
 
     if (iPred) {
         // Update the indirect predictor with the direction prediction
@@ -339,10 +338,10 @@
             DPRINTF(Branch, "[tid:%i] [squash sn:%llu]"
                     " Restoring top of RAS to: %i,"
                     " target: %s\n", tid, squashed_sn,
-                    pred_hist.front().RASIndex, pred_hist.front().RASTarget);
+                    pred_hist.front().RASIndex, *pred_hist.front().RASTarget);
 
             RAS[tid].restore(pred_hist.front().RASIndex,
-                             pred_hist.front().RASTarget);
+                             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"
@@ -371,7 +370,7 @@
 
 void
 BPredUnit::squash(const InstSeqNum &squashed_sn,
-                  const TheISA::PCState &corrTarget,
+                  const PCStateBase &corr_target,
                   bool actually_taken, ThreadID tid)
 {
     // Now that we know that a branch was mispredicted, we need to undo
@@ -391,7 +390,7 @@
     ppMisses->notify(1);
 
     DPRINTF(Branch, "[tid:%i] Squashing from sequence number %i, "
-            "setting target to %s\n", tid, squashed_sn, corrTarget);
+            "setting target to %s\n", tid, squashed_sn, corr_target);
 
     // Squash All Branches AFTER this mispredicted branch
     squash(squashed_sn, tid);
@@ -432,11 +431,11 @@
 
         // Remember the correct direction for the update at commit.
         pred_hist.front().predTaken = actually_taken;
-        pred_hist.front().target = corrTarget.instAddr();
+        pred_hist.front().target = corr_target.instAddr();
 
         update(tid, (*hist_it).pc, actually_taken,
                pred_hist.front().bpHistory, true, pred_hist.front().inst,
-               corrTarget.instAddr());
+               corr_target.instAddr());
 
         if (iPred) {
             iPred->changeDirectionPrediction(tid,
@@ -458,7 +457,7 @@
                 if (iPred) {
                     iPred->recordTarget(
                         hist_it->seqNum, pred_hist.front().indirectHistory,
-                        corrTarget, tid);
+                        corr_target, tid);
                 }
             } else {
                 DPRINTF(Branch,"[tid:%i] [squash sn:%llu] "
@@ -466,7 +465,7 @@
                         "PC %#x\n", tid, squashed_sn,
                         hist_it->seqNum, hist_it->pc);
 
-                BTB.update((*hist_it).pc, corrTarget, tid);
+                BTB.update(hist_it->pc, corr_target, tid);
             }
         } else {
            //Actually not Taken
@@ -479,8 +478,8 @@
                 DPRINTF(Branch,
                         "[tid:%i] [squash sn:%llu] Restoring top of RAS "
                         "to: %i, target: %s\n", tid, squashed_sn,
-                        hist_it->RASIndex, hist_it->RASTarget);
-                RAS[tid].restore(hist_it->RASIndex, hist_it->RASTarget);
+                        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
diff --git a/src/cpu/pred/bpred_unit.hh b/src/cpu/pred/bpred_unit.hh
index 0e1f5d3..e57f8e4 100644
--- a/src/cpu/pred/bpred_unit.hh
+++ b/src/cpu/pred/bpred_unit.hh
@@ -88,7 +88,7 @@
      * @return Returns if the branch is taken or not.
      */
     bool predict(const StaticInstPtr &inst, const InstSeqNum &seqNum,
-                 TheISA::PCState &pc, ThreadID tid);
+                 PCStateBase &pc, ThreadID tid);
 
     // @todo: Rename this function.
     virtual void uncondBranch(ThreadID tid, Addr pc, void * &bp_history) = 0;
@@ -119,7 +119,7 @@
      * @param tid The thread id.
      */
     void squash(const InstSeqNum &squashed_sn,
-                const TheISA::PCState &corr_target,
+                const PCStateBase &corr_target,
                 bool actually_taken, ThreadID tid);
 
     /**
@@ -155,11 +155,17 @@
     bool BTBValid(Addr instPC) { return BTB.valid(instPC, 0); }
 
     /**
-     * Looks up a given PC in the BTB to get the predicted target.
+     * Looks up a given PC in the BTB to get the predicted target. The PC may
+     * be changed or deleted in the future, so it needs to be used immediately,
+     * and/or copied for use later.
      * @param inst_PC The PC to look up.
      * @return The address of the target of the branch.
      */
-    TheISA::PCState BTBLookup(Addr instPC) { return BTB.lookup(instPC, 0); }
+    const PCStateBase *
+    BTBLookup(Addr inst_pc)
+    {
+        return BTB.lookup(inst_pc, 0);
+    }
 
     /**
      * Updates the BP with taken/not taken information.
@@ -183,7 +189,7 @@
      * @param target_PC The branch's target that will be added to the BTB.
      */
     void
-    BTBUpdate(Addr instPC, const TheISA::PCState &target)
+    BTBUpdate(Addr instPC, const PCStateBase &target)
     {
         BTB.update(instPC, target, 0);
     }
@@ -203,12 +209,21 @@
                          void *indirect_history, ThreadID _tid,
                          const StaticInstPtr & inst)
             : seqNum(seq_num), pc(instPC), bpHistory(bp_history),
-              indirectHistory(indirect_history), RASTarget(0), RASIndex(0),
-              tid(_tid), predTaken(pred_taken), usedRAS(0), pushedRAS(0),
-              wasCall(0), wasReturn(0), wasIndirect(0), target(MaxAddr),
-              inst(inst)
+              indirectHistory(indirect_history), tid(_tid),
+              predTaken(pred_taken), inst(inst)
         {}
 
+        PredictorHistory(const PredictorHistory &other) :
+            seqNum(other.seqNum), pc(other.pc), bpHistory(other.bpHistory),
+            indirectHistory(other.indirectHistory), RASIndex(other.RASIndex),
+            tid(other.tid), predTaken(other.predTaken), usedRAS(other.usedRAS),
+            pushedRAS(other.pushedRAS), wasCall(other.wasCall),
+            wasReturn(other.wasReturn), wasIndirect(other.wasIndirect),
+            target(other.target), inst(other.inst)
+        {
+            set(RASTarget, other.RASTarget);
+        }
+
         bool
         operator==(const PredictorHistory &entry) const
         {
@@ -225,15 +240,15 @@
          * predictor.  It is used to update or restore state of the
          * branch predictor.
          */
-        void *bpHistory;
+        void *bpHistory = nullptr;
 
-        void *indirectHistory;
+        void *indirectHistory = nullptr;
 
         /** The RAS target (only valid if a return). */
-        TheISA::PCState RASTarget;
+        std::unique_ptr<PCStateBase> RASTarget;
 
         /** The RAS index of the instruction (only valid if a call). */
-        unsigned RASIndex;
+        unsigned RASIndex = 0;
 
         /** The thread id. */
         ThreadID tid;
@@ -242,24 +257,24 @@
         bool predTaken;
 
         /** Whether or not the RAS was used. */
-        bool usedRAS;
+        bool usedRAS = false;
 
         /* Whether or not the RAS was pushed */
-        bool pushedRAS;
+        bool pushedRAS = false;
 
         /** Whether or not the instruction was a call. */
-        bool wasCall;
+        bool wasCall = false;
 
         /** Whether or not the instruction was a return. */
-        bool wasReturn;
+        bool wasReturn = false;
 
         /** Wether this instruction was an indirect branch */
-        bool wasIndirect;
+        bool wasIndirect = false;
 
         /** Target of the branch. First it is predicted, and fixed later
          *  if necessary
          */
-        Addr target;
+        Addr target = MaxAddr;
 
         /** The branch instrction */
         const StaticInstPtr inst;
diff --git a/src/cpu/pred/btb.cc b/src/cpu/pred/btb.cc
index a3950cd..71afd45 100644
--- a/src/cpu/pred/btb.cc
+++ b/src/cpu/pred/btb.cc
@@ -112,35 +112,35 @@
 // @todo Create some sort of return struct that has both whether or not the
 // address is valid, and also the address.  For now will just use addr = 0 to
 // represent invalid entry.
-TheISA::PCState
-DefaultBTB::lookup(Addr instPC, ThreadID tid)
+const PCStateBase *
+DefaultBTB::lookup(Addr inst_pc, ThreadID tid)
 {
-    unsigned btb_idx = getIndex(instPC, tid);
+    unsigned btb_idx = getIndex(inst_pc, tid);
 
-    Addr inst_tag = getTag(instPC);
+    Addr inst_tag = getTag(inst_pc);
 
     assert(btb_idx < numEntries);
 
     if (btb[btb_idx].valid
         && inst_tag == btb[btb_idx].tag
         && btb[btb_idx].tid == tid) {
-        return btb[btb_idx].target;
+        return btb[btb_idx].target.get();
     } else {
-        return TheISA::PCState(0);
+        return nullptr;
     }
 }
 
 void
-DefaultBTB::update(Addr instPC, const TheISA::PCState &target, ThreadID tid)
+DefaultBTB::update(Addr inst_pc, const PCStateBase &target, ThreadID tid)
 {
-    unsigned btb_idx = getIndex(instPC, tid);
+    unsigned btb_idx = getIndex(inst_pc, tid);
 
     assert(btb_idx < numEntries);
 
     btb[btb_idx].tid = tid;
     btb[btb_idx].valid = true;
-    btb[btb_idx].target = target;
-    btb[btb_idx].tag = getTag(instPC);
+    set(btb[btb_idx].target, target);
+    btb[btb_idx].tag = getTag(inst_pc);
 }
 
 } // namespace branch_prediction
diff --git a/src/cpu/pred/btb.hh b/src/cpu/pred/btb.hh
index e3c2f5f..ce1cb21 100644
--- a/src/cpu/pred/btb.hh
+++ b/src/cpu/pred/btb.hh
@@ -45,21 +45,17 @@
   private:
     struct BTBEntry
     {
-        BTBEntry()
-            : tag(0), target(0), valid(false)
-        {}
-
         /** The entry's tag. */
-        Addr tag;
+        Addr tag = 0;
 
         /** The entry's target. */
-        TheISA::PCState target;
+        std::unique_ptr<PCStateBase> target;
 
         /** The entry's thread id. */
         ThreadID tid;
 
         /** Whether or not the entry is valid. */
-        bool valid;
+        bool valid = false;
     };
 
   public:
@@ -79,7 +75,7 @@
      *  @param tid The thread id.
      *  @return Returns the target of the branch.
      */
-    TheISA::PCState lookup(Addr instPC, ThreadID tid);
+    const PCStateBase *lookup(Addr instPC, ThreadID tid);
 
     /** Checks if a branch is in the BTB.
      *  @param inst_PC The address of the branch to look up.
@@ -89,12 +85,11 @@
     bool valid(Addr instPC, ThreadID tid);
 
     /** Updates the BTB with the target of a branch.
-     *  @param inst_PC The address of the branch being updated.
-     *  @param target_PC The target address of the branch.
+     *  @param inst_pc The address of the branch being updated.
+     *  @param target_pc The target address of the branch.
      *  @param tid The thread id.
      */
-    void update(Addr instPC, const TheISA::PCState &targetPC,
-                ThreadID tid);
+    void update(Addr inst_pc, const PCStateBase &target_pc, ThreadID tid);
 
   private:
     /** Returns the index into the BTB, based on the branch's PC.
diff --git a/src/cpu/pred/indirect.hh b/src/cpu/pred/indirect.hh
index e744a1b..ee17d2c 100644
--- a/src/cpu/pred/indirect.hh
+++ b/src/cpu/pred/indirect.hh
@@ -52,7 +52,7 @@
     {
     }
 
-    virtual bool lookup(Addr br_addr, TheISA::PCState& br_target,
+    virtual bool lookup(Addr br_addr, PCStateBase& br_target,
                         ThreadID tid) = 0;
     virtual void recordIndirect(Addr br_addr, Addr tgt_addr,
                                 InstSeqNum seq_num, ThreadID tid) = 0;
@@ -60,7 +60,7 @@
                         void * indirect_history) = 0;
     virtual void squash(InstSeqNum seq_num, ThreadID tid) = 0;
     virtual void recordTarget(InstSeqNum seq_num, void * indirect_history,
-                              const TheISA::PCState& target, ThreadID tid) = 0;
+                              const PCStateBase& target, ThreadID tid) = 0;
     virtual void genIndirectInfo(ThreadID tid, void* & indirect_history) = 0;
     virtual void updateDirectionInfo(ThreadID tid, bool actually_taken) = 0;
     virtual void deleteIndirectInfo(ThreadID tid, void * indirect_history) = 0;
diff --git a/src/cpu/pred/ras.cc b/src/cpu/pred/ras.cc
index d2235e9..8d415b7 100644
--- a/src/cpu/pred/ras.cc
+++ b/src/cpu/pred/ras.cc
@@ -47,16 +47,14 @@
 {
     usedEntries = 0;
     tos = 0;
-    for (unsigned i = 0; i < numEntries; ++i)
-        addrStack[i].set(0);
 }
 
 void
-ReturnAddrStack::push(const TheISA::PCState &return_addr)
+ReturnAddrStack::push(const PCStateBase &return_addr)
 {
     incrTos();
 
-    addrStack[tos] = return_addr;
+    set(addrStack[tos], return_addr);
 
     if (usedEntries != numEntries) {
         ++usedEntries;
@@ -74,12 +72,11 @@
 }
 
 void
-ReturnAddrStack::restore(unsigned top_entry_idx,
-                         const TheISA::PCState &restored)
+ReturnAddrStack::restore(unsigned top_entry_idx, const PCStateBase *restored)
 {
     tos = top_entry_idx;
 
-    addrStack[tos] = restored;
+    set(addrStack[tos], restored);
 
     if (usedEntries != numEntries) {
         ++usedEntries;
diff --git a/src/cpu/pred/ras.hh b/src/cpu/pred/ras.hh
index 40c6dac..0b4b471 100644
--- a/src/cpu/pred/ras.hh
+++ b/src/cpu/pred/ras.hh
@@ -31,9 +31,8 @@
 
 #include <vector>
 
-#include "arch/pcstate.hh"
+#include "arch/generic/pcstate.hh"
 #include "base/types.hh"
-#include "config/the_isa.hh"
 
 namespace gem5
 {
@@ -58,13 +57,13 @@
     void reset();
 
     /** Returns the top address on the RAS. */
-    TheISA::PCState top() { return addrStack[tos]; }
+    const PCStateBase *top() { return addrStack[tos].get(); }
 
     /** Returns the index of the top of the RAS. */
     unsigned topIdx() { return tos; }
 
     /** Pushes an address onto the RAS. */
-    void push(const TheISA::PCState &return_addr);
+    void push(const PCStateBase &return_addr);
 
     /** Pops the top address from the RAS. */
     void pop();
@@ -74,7 +73,7 @@
      *  @param top_entry_idx The index of the RAS that will now be the top.
      *  @param restored The new target address of the new top of the RAS.
      */
-    void restore(unsigned top_entry_idx, const TheISA::PCState &restored);
+    void restore(unsigned top_entry_idx, const PCStateBase *restored);
 
     bool empty() { return usedEntries == 0; }
 
@@ -96,7 +95,7 @@
     }
 
     /** The RAS itself. */
-    std::vector<TheISA::PCState> addrStack;
+    std::vector<std::unique_ptr<PCStateBase>> addrStack;
 
     /** The number of entries in the RAS. */
     unsigned numEntries;
diff --git a/src/cpu/pred/simple_indirect.cc b/src/cpu/pred/simple_indirect.cc
index 7fd75f4..2a1fc7a 100644
--- a/src/cpu/pred/simple_indirect.cc
+++ b/src/cpu/pred/simple_indirect.cc
@@ -93,7 +93,7 @@
 }
 
 bool
-SimpleIndirectPredictor::lookup(Addr br_addr, TheISA::PCState& target,
+SimpleIndirectPredictor::lookup(Addr br_addr, PCStateBase& target,
     ThreadID tid)
 {
     Addr set_index = getSetIndex(br_addr, threadInfo[tid].ghr, tid);
@@ -105,8 +105,8 @@
     const auto &iset = targetCache[set_index];
     for (auto way = iset.begin(); way != iset.end(); ++way) {
         if (way->tag == tag) {
-            DPRINTF(Indirect, "Hit %x (target:%s)\n", br_addr, way->target);
-            target = way->target;
+            DPRINTF(Indirect, "Hit %x (target:%s)\n", br_addr, *way->target);
+            set(target, *way->target);
             return true;
         }
     }
@@ -177,7 +177,7 @@
 
 void
 SimpleIndirectPredictor::recordTarget(
-    InstSeqNum seq_num, void * indirect_history, const TheISA::PCState& target,
+    InstSeqNum seq_num, void * indirect_history, const PCStateBase& target,
     ThreadID tid)
 {
     ThreadInfo &t_info = threadInfo[tid];
@@ -200,7 +200,7 @@
         if (way->tag == tag) {
             DPRINTF(Indirect, "Updating Target (seq: %d br:%x set:%d target:"
                     "%s)\n", seq_num, hist_entry.pcAddr, set_index, target);
-            way->target = target;
+            set(way->target, target);
             return;
         }
     }
@@ -210,7 +210,7 @@
     // Did not find entry, random replacement
     auto &way = iset[rand() % numWays];
     way.tag = tag;
-    way.target = target;
+    set(way.target, target);
 }
 
 
diff --git a/src/cpu/pred/simple_indirect.hh b/src/cpu/pred/simple_indirect.hh
index 0949a76..8587047 100644
--- a/src/cpu/pred/simple_indirect.hh
+++ b/src/cpu/pred/simple_indirect.hh
@@ -47,13 +47,13 @@
   public:
     SimpleIndirectPredictor(const SimpleIndirectPredictorParams &params);
 
-    bool lookup(Addr br_addr, TheISA::PCState& br_target, ThreadID tid);
+    bool lookup(Addr br_addr, PCStateBase& br_target, ThreadID tid);
     void recordIndirect(Addr br_addr, Addr tgt_addr, InstSeqNum seq_num,
                         ThreadID tid);
     void commit(InstSeqNum seq_num, ThreadID tid, void * indirect_history);
     void squash(InstSeqNum seq_num, ThreadID tid);
     void recordTarget(InstSeqNum seq_num, void * indirect_history,
-                      const TheISA::PCState& target, ThreadID tid);
+                      const PCStateBase& target, ThreadID tid);
     void genIndirectInfo(ThreadID tid, void* & indirect_history);
     void updateDirectionInfo(ThreadID tid, bool actually_taken);
     void deleteIndirectInfo(ThreadID tid, void * indirect_history);
@@ -73,9 +73,8 @@
 
     struct IPredEntry
     {
-        IPredEntry() : tag(0), target(0) { }
-        Addr tag;
-        TheISA::PCState target;
+        Addr tag = 0;
+        std::unique_ptr<PCStateBase> target;
     };
 
     std::vector<std::vector<IPredEntry> > targetCache;
@@ -95,11 +94,9 @@
 
     struct ThreadInfo
     {
-        ThreadInfo() : headHistEntry(0), ghr(0) { }
-
         std::deque<HistoryEntry> pathHist;
-        unsigned headHistEntry;
-        unsigned ghr;
+        unsigned headHistEntry = 0;
+        unsigned ghr = 0;
     };
 
     std::vector<ThreadInfo> threadInfo;
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 38caaf5..7ddd100 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -371,9 +371,8 @@
         const InstSeqNum cur_sn(0);
         set(t_info.predPC, thread->pcState());
         const bool predict_taken(
-            branchPred->predict(curStaticInst, cur_sn,
-                                t_info.predPC->as<TheISA::PCState>(),
-                                curThread));
+            branchPred->predict(curStaticInst, cur_sn, *t_info.predPC,
+                curThread));
 
         if (predict_taken)
             ++t_info.execContextStats.numPredictedBranches;
@@ -489,7 +488,8 @@
             branchPred->update(cur_sn, curThread);
         } else {
             // Mis-predicted branch
-            branchPred->squash(cur_sn, thread->pcState(), branching, curThread);
+            branchPred->squash(cur_sn, thread->pcState(), branching,
+                    curThread);
             ++t_info.execContextStats.numBranchMispred;
         }
     }