Skip to content

Split microtage align#727

Open
CJ362ff wants to merge 27 commits intoxs-devfrom
split-microtage-align
Open

Split microtage align#727
CJ362ff wants to merge 27 commits intoxs-devfrom
split-microtage-align

Conversation

@CJ362ff
Copy link
Collaborator

@CJ362ff CJ362ff commented Jan 23, 2026

Summary by CodeRabbit

  • Refactor

    • Reworked branch predictor integration and expanded the public configuration surface to fully expose MicroTAGE knobs and state.
  • New Features

    • Added a production-ready MicroTAGE branch predictor with prediction/update paths, history folding, bank-awareness, and detailed statistics.
  • Chores

    • Enabled MicroTAGE by default for the decoupled BPU-with-BTB configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

Cao Jiaming added 24 commits January 6, 2026 16:02
Change-Id: I8b6a4bda945564cc961251fc1297a6bacd8636cb
Change-Id: I44b6175022a3a593ed385407bd95ec0c40c74642
Change-Id: I16ce79a7d8488d9a138d0a26f5500576ae54132e
Change-Id: I8be037a1cdacd7151f4fe8e743a32cca90a85036
Change-Id: I6b9c92c18c574a12c19532ae0b894e64c1187342
Change-Id: I953965b8e6feb1c15a238ac832d65bc16b32f496
Change-Id: I39cd471d452aa343c3dd741a80fdfa7d126e3a9f
Change-Id: I3567ae93652aac218c5b4646003abadddaf7cf32
Change-Id: If7c9d3aa68a23c36dde74d8cf3a286c9c48f3e3c
Change-Id: I9b85fdca4602fdc28521250daec6b397361cd444
Change-Id: I886f0f6596105ea56ff167d406879277c751802c
Change-Id: Ifb354f91da3df909bcac50ebb5c683ea4c718bf1
Change-Id: I8c3e752daaa188deef4a6bb78abeb5c02a0aaca9
Change-Id: Ib9daaa3a60777c83fed779dd0169d17002a44d43
Change-Id: Ia5934e526e8d6bea03bd0711eb9cf6947eecc2aa
Change-Id: Ie3f6b39d8f6e989018fc477a7b55d3879657338b
Change-Id: I31aa12e8e2f6dd2b5421f9c4deab11dddcb53eda
Change-Id: I6c27be3fbd0db5110e0b1948ac3c39c1400b9b64
Change-Id: I21054d48efddcff13308e1164109dfbbc2d034e2
Change-Id: I84d82d8499186909ee5f79e398b8a9ff07d5bb72
Change-Id: Ie92f7106b798596ba7b0ed86cc9346fa3e0f9c38
@coderabbitai
Copy link

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Replaces a lightweight MicroTAGE stub with a full TimedBaseBTBPredictor-based MicroTAGE implementation, adds its sources to the build, updates DecoupledBPUWithBTB to use MicroTAGE*, and enables MicroTAGE in the KMHv3 config for the DecoupledBPUWithBTB path.

Changes

Cohort / File(s) Summary
Configuration
configs/example/kmhv3.py
Enables cpu.branchPred.microtage.enabled = True when bp_type == DecoupledBPUWithBTB.
Predictor Python API
src/cpu/pred/BranchPredictor.py
Replaces minimal MicroTAGE stub with a full MicroTAGE Param class (type, cxx_class, cxx_header) exposing many configuration knobs and constructs microtage via Param.MicroTAGE(...).
Build / SConscript
src/cpu/pred/SConscript
Adds btb/microtage.cc to sources and inserts MicroTAGE into the public BpType enum.
Decoupled BPU header
src/cpu/pred/btb/decoupled_bpred.hh
Changes member type microtage from BTBTAGE* to MicroTAGE* and adjusts includes for MicroTAGE.
MicroTAGE implementation & header
src/cpu/pred/btb/microtage.cc, src/cpu/pred/btb/microtage.hh
New comprehensive MicroTAGE predictor: table/index/tag computation, folded histories, prediction lookup, speculative/history updates, allocation/update logic, bank-conflict handling, LRU/aging, statistics, and UNIT_TEST constructors/APIs.

Sequence Diagram(s)

sequenceDiagram
    participant Fetch as Fetch Stage
    participant Micro as MicroTAGE
    participant Tables as TAGE Tables
    participant History as Folded History
    Fetch->>Micro: generateSinglePrediction(addr, BTBEntry)
    Micro->>History: compute folded indices/tags (getTageIndex/getTageTag)
    History-->>Micro: folded indices/tags
    Micro->>Tables: lookupHelper(query per-table indices/tags)
    Tables-->>Micro: per-table entries & tags
    Micro->>Micro: select main/alt prediction (matchTag, choose)
    Micro-->>Fetch: return prediction + meta
Loading
sequenceDiagram
    participant Execute as Execute/Retire Stage
    participant Micro as MicroTAGE
    participant History as Folded History
    participant Tables as TAGE Tables
    participant Stats as Statistics
    Execute->>Micro: update(FetchStream with actual outcome)
    Micro->>Micro: prepareUpdateEntries -> updatePredictorStateAndCheckAllocation
    Micro->>History: doUpdateHist / specUpdatePHist (speculative or commit)
    Micro->>Tables: update counters, useful bits, allocate entries if needed
    Micro->>Stats: record events (mispred, alloc, bank-conflict)
    Micro-->>Execute: update complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

align-kmhv3

Suggested reviewers

  • jensen-yan
  • Yakkhini

Poem

🐰 I hopped through tags and folded trails so fine,

Banks and counters, indices in a line,
I nibble history bits and stash a clue,
MicroTAGE hums — a branching dream anew,
Code carrots crunch — hop, predict, refine!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Split microtage align' is vague and does not clearly convey the main changes. It uses generic terms that don't meaningfully describe the PR's purpose. Clarify the title to reflect the main objective: consider 'Refactor MicroTAGE branch predictor implementation' or 'Implement comprehensive MicroTAGE BTB predictor' to better communicate the substantial changes across multiple files.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Change-Id: I914d05c0a29ce57989ba63bf2b46595c62cfcc0a
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/cpu/pred/btb/microtage.cc`:
- Around line 826-831: getBankId() can produce values >= numBanks when numBanks
is not a power of two because bankIdWidth = ceilLog2(numBanks); update getBankId
(or its callers) to ensure the returned bank ID is within [0, numBanks-1] —
either assert that numBanks is a power of two at initialization or clamp the
computed value using numBanks (e.g., id = ((pc >> bankBaseShift) & ((1 <<
bankIdWidth) - 1)); return std::min(id, numBanks - 1u)); and ensure references
to bankBaseShift, bankIdWidth, numBanks, and getBankId are the locations you
modify so per‑bank stats vectors never get indexed out of bounds.
- Around line 738-769: The mask creation in getTageTag and getTageIndex uses
(1ULL << tableTagBits[t]) - 1 and (1ULL << tableIndexBits[t]) - 1 which can
invoke shift-by-width UB if the bit counts are >= width of the type; change both
functions to compute a safe mask by bounding the shift amount against the target
width (e.g., if bits >= sizeof(Addr)*8 then set mask = ~Addr(0) else mask =
(Addr(1) << bits) - 1), and use tableTagBits[t] and tableIndexBits[t] in that
guarded computation so misconfiguration cannot cause undefined behavior.

In `@src/cpu/pred/btb/microtage.hh`:
- Around line 305-367: TageStats members are uninitialized in UNIT_TEST builds
causing UB (e.g., updateProviderNa++ reads garbage); fix by value-initializing
the global instance—replace the default-initialized declaration of TageStats
tageStats with a value-initialized instance (TageStats tageStats{}) so all
Scalar and int members start at zero; this avoids adding a constructor and fixes
issues in updateProviderNa, updateUseAlt, etc.
🧹 Nitpick comments (1)
src/cpu/pred/btb/microtage.cc (1)

330-335: Avoid double-counting stats across pipeline stages.

lookupHelper updates tageStats, but it’s called once per stage, so the same prediction can be counted multiple times. Consider caching the lookup once per cycle and reusing results for later stages.

Comment on lines +738 to +769
// Calculate TAGE tag with folded history - optimized version using bitwise operations
Addr
MicroTAGE::getTageTag(Addr pc, int t, uint64_t foldedHist, uint64_t altFoldedHist, Addr position)
{
// Create mask for tableTagBits[t] to limit result size
Addr mask = (1ULL << tableTagBits[t]) - 1;

// Extract lower bits of PC directly (remove instruction alignment bits)
Addr pcBits = (pc >> bankBaseShift) & mask;

// Extract and prepare folded history bits
Addr foldedBits = foldedHist & mask;

// Extract alt tag bits and shift left by 1
Addr altTagBits = (altFoldedHist << 1) & mask;

// XOR all components together, including position (like RTL)
return pcBits ^ foldedBits ^ position ^ altTagBits;
}

Addr
MicroTAGE::getTageIndex(Addr pc, int t, uint64_t foldedHist)
{
// Create mask for tableIndexBits[t] to limit result size
Addr mask = (1ULL << tableIndexBits[t]) - 1;

const unsigned pcShift = enableBankConflict ? indexShift : bankBaseShift;
Addr pcBits = (pc >> pcShift) & mask;
Addr foldedBits = foldedHist & mask;

return pcBits ^ foldedBits;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's confirm the code exists and check the file structure
cd src/cpu/pred/btb && ls -la | grep -i tage

Repository: OpenXiangShan/GEM5

Length of output: 439


🏁 Script executed:

# Look at the specific lines mentioned (738-769)
wc -l microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 105


🏁 Script executed:

# Read the getTageTag and getTageIndex functions to verify they match the snippet
sed -n '738,769p' microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 117


🏁 Script executed:

# Find where tableTagBits and tableIndexBits are defined/declared
grep -n "tableTagBits\|tableIndexBits" microtage.cc | head -20

Repository: OpenXiangShan/GEM5

Length of output: 107


🏁 Script executed:

# Check the class definition and member variable declarations
head -200 microtage.cc | grep -A 5 -B 5 "tableTagBits\|tableIndexBits"

Repository: OpenXiangShan/GEM5

Length of output: 133


🏁 Script executed:

# Look for any existing bounds checking or assertions related to these values
grep -n "assert\|check\|validate" microtage.cc | grep -i "tag\|index\|bit"

Repository: OpenXiangShan/GEM5

Length of output: 107


🏁 Script executed:

# Find the Addr typedef to confirm it's 64-bit
grep -r "typedef.*Addr" --include="*.hh" --include="*.h" | head -5

Repository: OpenXiangShan/GEM5

Length of output: 464


🏁 Script executed:

# Check if there's any configuration validation for these parameters
find . -name "*.py" -o -name "*.cc" | xargs grep -l "tableTagBits\|tableIndexBits" | head -5

Repository: OpenXiangShan/GEM5

Length of output: 424


🏁 Script executed:

# Read the specific lines from the file using full path
sed -n '738,769p' src/cpu/pred/btb/microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 1177


🏁 Script executed:

# Find where tableTagBits and tableIndexBits are defined
grep -n "tableTagBits\|tableIndexBits" src/cpu/pred/btb/microtage.cc | head -20

Repository: OpenXiangShan/GEM5

Length of output: 1010


🏁 Script executed:

# Check the header file for member variable declarations
cat src/cpu/pred/btb/microtage.hh | head -100

Repository: OpenXiangShan/GEM5

Length of output: 3412


🏁 Script executed:

# Look for Addr type definition in the codebase
grep -r "typedef.*Addr[^a-z]" --include="*.hh" --include="*.h" src/ | grep -v "Address\|Elf" | head -10

Repository: OpenXiangShan/GEM5

Length of output: 830


🏁 Script executed:

# Search for any bounds checking or assertions related to table bit sizes
grep -n "assert\|check\|validate" src/cpu/pred/btb/microtage.cc | grep -i "tag\|index\|bit" -A 2 -B 2

Repository: OpenXiangShan/GEM5

Length of output: 856


🏁 Script executed:

# Look at the constructor or initialization code for tableTagBits
grep -n "tableTagBits.*=" src/cpu/pred/btb/microtage.cc | head -10

Repository: OpenXiangShan/GEM5

Length of output: 119


🏁 Script executed:

# Find the Addr type definition in base/types.hh
cat src/base/types.hh | grep -A 5 -B 5 "typedef.*Addr"

Repository: OpenXiangShan/GEM5

Length of output: 388


🏁 Script executed:

# Look at what ceilLog2 returns and its maximum value
grep -n "ceilLog2" src/cpu/pred/btb/microtage.cc -A 2 -B 2

Repository: OpenXiangShan/GEM5

Length of output: 872


🏁 Script executed:

# Find ceilLog2 definition
find src -name "*.hh" -o -name "*.h" | xargs grep -l "ceilLog2" | head -3

Repository: OpenXiangShan/GEM5

Length of output: 293


🏁 Script executed:

# Check the parameters/definitions for MicroTAGE table sizes
grep -n "TTagBitSizes\|tableSizes" src/cpu/pred/btb/microtage.cc | head -20

Repository: OpenXiangShan/GEM5

Length of output: 399


🏁 Script executed:

# Look for any user configuration that might set these values
find src -name "*MicroTAGE*" -type f | head -10

Repository: OpenXiangShan/GEM5

Length of output: 44


🏁 Script executed:

# Check what are reasonable values for tableIndexBits when used with ceilLog2
grep -n "tableSizes\[" src/cpu/pred/btb/microtage.cc -B 5 -A 5

Repository: OpenXiangShan/GEM5

Length of output: 706


🏁 Script executed:

# Find and read ceilLog2 implementation
cat src/base/intmath.hh | grep -A 20 "ceilLog2"

Repository: OpenXiangShan/GEM5

Length of output: 443


🏁 Script executed:

# Check the parameter definitions for MicroTAGE
find src -name "*MicroTAGE.py" -type f

Repository: OpenXiangShan/GEM5

Length of output: 44


🏁 Script executed:

# Look for SConscript or parameter files that define MicroTAGE
find src -name "*.py" | xargs grep -l "MicroTAGE" | head -5

Repository: OpenXiangShan/GEM5

Length of output: 206


🏁 Script executed:

# Check what the maximum practical value for tableSizes could be
grep -n "tableSizes" src/cpu/pred/btb/microtage.cc | head -15

Repository: OpenXiangShan/GEM5

Length of output: 366


🏁 Script executed:

# Check if there's any validation of tableTagBits values at construction time
grep -n "tableTagBits" src/cpu/pred/btb/microtage.cc -B 3 -A 3 | head -50

Repository: OpenXiangShan/GEM5

Length of output: 1925


🏁 Script executed:

# Check if there's any validation in the parameter parsing or initialization
grep -n "TTagBitSizes\|TTagPcShifts" src/cpu/pred/BranchPredictor.py -B 3 -A 3

Repository: OpenXiangShan/GEM5

Length of output: 4258


🏁 Script executed:

# Look for any assertion or check that validates these values are < 64
grep -rn "assert.*tableTagBits\|assert.*tableIndexBits" src/cpu/pred/btb/

Repository: OpenXiangShan/GEM5

Length of output: 324


🏁 Script executed:

# Check if PathFoldedHist has any bounds on the bits parameter
grep -n "class PathFoldedHist" src/cpu/pred/btb/*.hh -A 20 | head -40

Repository: OpenXiangShan/GEM5

Length of output: 1086


🏁 Script executed:

# Check the FoldedHistBase constructor to see if there's validation
grep -n "class FoldedHistBase" src/cpu/pred/btb/folded_hist.hh -A 30 | head -50

Repository: OpenXiangShan/GEM5

Length of output: 1653


🏁 Script executed:

# Look for the FoldedHistBase implementation in the .cc file
find src/cpu/pred/btb -name "*.cc" | xargs grep -l "FoldedHistBase"

Repository: OpenXiangShan/GEM5

Length of output: 93


🏁 Script executed:

# Check if there's any validation in the constructor implementation
grep -n "FoldedHistBase::" src/cpu/pred/btb/folded_hist.cc -A 5 | head -40

Repository: OpenXiangShan/GEM5

Length of output: 729


🏁 Script executed:

# Verify that the shift operations are truly unguarded by checking if there are any prior checks in getTageTag/getTageIndex
sed -n '738,770p' src/cpu/pred/btb/microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 1178


🏁 Script executed:

# Confirm no validation happens before the shift operations
sed -n '740,770p' src/cpu/pred/btb/microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 1086


Guard against shift-by-width undefined behavior in mask creation.

(1ULL << tableTagBits[t]) - 1 and (1ULL << tableIndexBits[t]) - 1 invoke undefined behavior when shift amounts ≥ 64. Although in-practice values are small (8–16 bits), these parameters are user-configurable. Add defensive bounds checks to prevent UB if misconfigured.

🛠️ Suggested fix (safe mask creation)
-    Addr mask = (1ULL << tableTagBits[t]) - 1;
+    const unsigned tagBits = tableTagBits[t];
+    Addr mask = (tagBits >= (sizeof(Addr) * 8))
+        ? ~Addr(0)
+        : ((Addr(1) << tagBits) - 1);
...
-    Addr mask = (1ULL << tableIndexBits[t]) - 1;
+    const unsigned indexBits = tableIndexBits[t];
+    Addr mask = (indexBits >= (sizeof(Addr) * 8))
+        ? ~Addr(0)
+        : ((Addr(1) << indexBits) - 1);
🤖 Prompt for AI Agents
In `@src/cpu/pred/btb/microtage.cc` around lines 738 - 769, The mask creation in
getTageTag and getTageIndex uses (1ULL << tableTagBits[t]) - 1 and (1ULL <<
tableIndexBits[t]) - 1 which can invoke shift-by-width UB if the bit counts are
>= width of the type; change both functions to compute a safe mask by bounding
the shift amount against the target width (e.g., if bits >= sizeof(Addr)*8 then
set mask = ~Addr(0) else mask = (Addr(1) << bits) - 1), and use tableTagBits[t]
and tableIndexBits[t] in that guarded computation so misconfiguration cannot
cause undefined behavior.

Comment on lines +826 to +831
unsigned
MicroTAGE::getBankId(Addr pc) const
{
// Extract bank ID bits after removing instruction alignment
return (pc >> bankBaseShift) & ((1 << bankIdWidth) - 1);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate bank ID range for non‑power‑of‑two numBanks.

bankIdWidth = ceilLog2(numBanks) means getBankId() can return values ≥ numBanks if numBanks isn’t a power of two, which can go out-of-bounds on per‑bank stats vectors. Either enforce power‑of‑two or clamp.

🛠️ Suggested fix (assert power‑of‑two)
 unsigned
 MicroTAGE::getBankId(Addr pc) const
 {
+    assert(numBanks && (numBanks & (numBanks - 1)) == 0);
     // Extract bank ID bits after removing instruction alignment
     return (pc >> bankBaseShift) & ((1 << bankIdWidth) - 1);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
unsigned
MicroTAGE::getBankId(Addr pc) const
{
// Extract bank ID bits after removing instruction alignment
return (pc >> bankBaseShift) & ((1 << bankIdWidth) - 1);
}
unsigned
MicroTAGE::getBankId(Addr pc) const
{
assert(numBanks && (numBanks & (numBanks - 1)) == 0);
// Extract bank ID bits after removing instruction alignment
return (pc >> bankBaseShift) & ((1 << bankIdWidth) - 1);
}
🤖 Prompt for AI Agents
In `@src/cpu/pred/btb/microtage.cc` around lines 826 - 831, getBankId() can
produce values >= numBanks when numBanks is not a power of two because
bankIdWidth = ceilLog2(numBanks); update getBankId (or its callers) to ensure
the returned bank ID is within [0, numBanks-1] — either assert that numBanks is
a power of two at initialization or clamp the computed value using numBanks
(e.g., id = ((pc >> bankBaseShift) & ((1 << bankIdWidth) - 1)); return
std::min(id, numBanks - 1u)); and ensure references to bankBaseShift,
bankIdWidth, numBanks, and getBankId are the locations you modify so per‑bank
stats vectors never get indexed out of bounds.

Comment on lines +305 to +367
#ifdef UNIT_TEST
struct TageStats
{
#else
struct TageStats : public statistics::Group
{
#endif
Scalar predNoHitUseBim;
Scalar predUseAlt;
Scalar updateNoHitUseBim;
Scalar updateUseAlt;
Scalar updateUseAltCorrect;
Scalar updateUseAltWrong;
Scalar updateAltDiffers;
Scalar updateUseAltOnNaUpdated;
Scalar updateProviderNa;
Scalar updateUseNaCorrect;
Scalar updateUseNaWrong;
Scalar updateUseAltOnNaCorrect;
Scalar updateUseAltOnNaWrong;
Scalar updateAllocFailure;
Scalar updateAllocFailureNoValidTable;
Scalar updateAllocSuccess;
Scalar updateMispred;
Scalar updateResetU;

Scalar updateUtageHit;
Scalar updateUtageWrong;

// Bank conflict statistics
Scalar updateBankConflict; // Number of bank conflicts detected
Scalar updateDeferredDueToConflict; // Number of updates deferred due to bank conflict (retried later)

#ifndef UNIT_TEST
// Fine-grained per-bank statistics
statistics::Vector updateBankConflictPerBank; // Conflicts per bank
statistics::Vector updateAccessPerBank; // Update accesses per bank
statistics::Vector predAccessPerBank; // Prediction accesses per bank

statistics::Distribution predTableHits;
statistics::Distribution updateTableHits;

statistics::Vector updateTableMispreds;
#endif

Scalar condPredwrong;
Scalar condMissTakens;
Scalar condCorrect;
Scalar condMissNoTakens;
Scalar predHit;
Scalar predMiss;

int bankIdx;
int numPredictors;
int numBanks;

#ifndef UNIT_TEST
TageStats(statistics::Group* parent, int numPredictors, int numBanks);
#endif
void updateStatsWithTagePrediction(const TagePrediction &pred, bool when_pred);
} ;

TageStats tageStats;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's find the Scalar type definition
rg "class Scalar|struct Scalar|using Scalar|typedef.*Scalar" --type-list --type cpp -A 3

Repository: OpenXiangShan/GEM5

Length of output: 180


🏁 Script executed:

# Find where Scalar is used and defined
fd "\.h$|\.hh$|\.hpp$" | head -20 | xargs grep -l "class Scalar\|struct Scalar" 2>/dev/null | head -5

Repository: OpenXiangShan/GEM5

Length of output: 44


🏁 Script executed:

# Look at the actual structure of the file around the TageStats definition
cat -n src/cpu/pred/btb/microtage.hh | sed -n '300,370p'

Repository: OpenXiangShan/GEM5

Length of output: 2662


🏁 Script executed:

# Check if there are any initializations of tageStats elsewhere
rg "tageStats\s*=" src/cpu/pred/btb/microtage.hh src/cpu/pred/btb/microtage.cc 2>/dev/null

Repository: OpenXiangShan/GEM5

Length of output: 44


🏁 Script executed:

# Search for the Scalar type in the codebase
rg "^\\s*(class|struct|using|typedef)\\s+Scalar" -t cpp

Repository: OpenXiangShan/GEM5

Length of output: 4671


🏁 Script executed:

# Find the full context of Scalar typedef with the `#ifdef`
cat -n src/cpu/pred/btb/microtage.hh | sed -n '290,305p'

Repository: OpenXiangShan/GEM5

Length of output: 792


🏁 Script executed:

# Look for all Scalar definitions in the microtage.hh file
rg -B 5 "typedef.*Scalar" src/cpu/pred/btb/microtage.hh

Repository: OpenXiangShan/GEM5

Length of output: 349


🏁 Script executed:

# Check if there's a UNIT_TEST definition of Scalar elsewhere in the file
rg -B 3 -A 3 "ifdef UNIT_TEST" src/cpu/pred/btb/microtage.hh | head -40

Repository: OpenXiangShan/GEM5

Length of output: 1170


🏁 Script executed:

# Find where UNIT_TEST Scalar is defined
cat -n src/cpu/pred/btb/microtage.hh | sed -n '280,310p'

Repository: OpenXiangShan/GEM5

Length of output: 1466


🏁 Script executed:

# Check how tageStats is used - specifically in UNIT_TEST context
rg "tageStats\." src/cpu/pred/btb/microtage.hh src/cpu/pred/btb/microtage.cc | head -20

Repository: OpenXiangShan/GEM5

Length of output: 1611


🏁 Script executed:

# Look at the updateStatsWithTagePrediction method to see if it increments Scalars
rg -A 30 "void updateStatsWithTagePrediction" src/cpu/pred/btb/microtage.hh src/cpu/pred/btb/microtage.cc | head -50

Repository: OpenXiangShan/GEM5

Length of output: 1737


🏁 Script executed:

# Check how bankIdx, numPredictors, numBanks are used
rg "\.bankIdx|\.numPredictors|\.numBanks" src/cpu/pred/btb/microtage.cc | head -20

Repository: OpenXiangShan/GEM5

Length of output: 245


🏁 Script executed:

# Look at the entire TageStats constructor in non-UNIT_TEST mode
rg -A 20 "TageStats::TageStats" src/cpu/pred/btb/microtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 1947


🏁 Script executed:

# Check if there's any initialization of tageStats in the MicroTAGE constructor
rg -B 5 -A 15 "MicroTAGE::MicroTAGE" src/cpu/pred/btb/microtage.cc | head -40

Repository: OpenXiangShan/GEM5

Length of output: 1238


Zero-initialize TageStats for UNIT_TEST builds.

In UNIT_TEST, TageStats has no constructor, so Scalar (uint64_t) members are uninitialized. Operations like updateProviderNa++ then perform UB by reading uninitialized values. Use value-initialization to zero the members.

Suggested fix
-    TageStats tageStats;
+    TageStats tageStats{};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#ifdef UNIT_TEST
struct TageStats
{
#else
struct TageStats : public statistics::Group
{
#endif
Scalar predNoHitUseBim;
Scalar predUseAlt;
Scalar updateNoHitUseBim;
Scalar updateUseAlt;
Scalar updateUseAltCorrect;
Scalar updateUseAltWrong;
Scalar updateAltDiffers;
Scalar updateUseAltOnNaUpdated;
Scalar updateProviderNa;
Scalar updateUseNaCorrect;
Scalar updateUseNaWrong;
Scalar updateUseAltOnNaCorrect;
Scalar updateUseAltOnNaWrong;
Scalar updateAllocFailure;
Scalar updateAllocFailureNoValidTable;
Scalar updateAllocSuccess;
Scalar updateMispred;
Scalar updateResetU;
Scalar updateUtageHit;
Scalar updateUtageWrong;
// Bank conflict statistics
Scalar updateBankConflict; // Number of bank conflicts detected
Scalar updateDeferredDueToConflict; // Number of updates deferred due to bank conflict (retried later)
#ifndef UNIT_TEST
// Fine-grained per-bank statistics
statistics::Vector updateBankConflictPerBank; // Conflicts per bank
statistics::Vector updateAccessPerBank; // Update accesses per bank
statistics::Vector predAccessPerBank; // Prediction accesses per bank
statistics::Distribution predTableHits;
statistics::Distribution updateTableHits;
statistics::Vector updateTableMispreds;
#endif
Scalar condPredwrong;
Scalar condMissTakens;
Scalar condCorrect;
Scalar condMissNoTakens;
Scalar predHit;
Scalar predMiss;
int bankIdx;
int numPredictors;
int numBanks;
#ifndef UNIT_TEST
TageStats(statistics::Group* parent, int numPredictors, int numBanks);
#endif
void updateStatsWithTagePrediction(const TagePrediction &pred, bool when_pred);
} ;
TageStats tageStats;
`#ifdef` UNIT_TEST
struct TageStats
{
`#else`
struct TageStats : public statistics::Group
{
`#endif`
Scalar predNoHitUseBim;
Scalar predUseAlt;
Scalar updateNoHitUseBim;
Scalar updateUseAlt;
Scalar updateUseAltCorrect;
Scalar updateUseAltWrong;
Scalar updateAltDiffers;
Scalar updateUseAltOnNaUpdated;
Scalar updateProviderNa;
Scalar updateUseNaCorrect;
Scalar updateUseNaWrong;
Scalar updateUseAltOnNaCorrect;
Scalar updateUseAltOnNaWrong;
Scalar updateAllocFailure;
Scalar updateAllocFailureNoValidTable;
Scalar updateAllocSuccess;
Scalar updateMispred;
Scalar updateResetU;
Scalar updateUtageHit;
Scalar updateUtageWrong;
// Bank conflict statistics
Scalar updateBankConflict; // Number of bank conflicts detected
Scalar updateDeferredDueToConflict; // Number of updates deferred due to bank conflict (retried later)
`#ifndef` UNIT_TEST
// Fine-grained per-bank statistics
statistics::Vector updateBankConflictPerBank; // Conflicts per bank
statistics::Vector updateAccessPerBank; // Update accesses per bank
statistics::Vector predAccessPerBank; // Prediction accesses per bank
statistics::Distribution predTableHits;
statistics::Distribution updateTableHits;
statistics::Vector updateTableMispreds;
`#endif`
Scalar condPredwrong;
Scalar condMissTakens;
Scalar condCorrect;
Scalar condMissNoTakens;
Scalar predHit;
Scalar predMiss;
int bankIdx;
int numPredictors;
int numBanks;
`#ifndef` UNIT_TEST
TageStats(statistics::Group* parent, int numPredictors, int numBanks);
`#endif`
void updateStatsWithTagePrediction(const TagePrediction &pred, bool when_pred);
} ;
TageStats tageStats{};
🤖 Prompt for AI Agents
In `@src/cpu/pred/btb/microtage.hh` around lines 305 - 367, TageStats members are
uninitialized in UNIT_TEST builds causing UB (e.g., updateProviderNa++ reads
garbage); fix by value-initializing the global instance—replace the
default-initialized declaration of TageStats tageStats with a value-initialized
instance (TageStats tageStats{}) so all Scalar and int members start at zero;
this avoids adding a constructor and fixes issues in updateProviderNa,
updateUseAlt, etc.

@github-actions
Copy link

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.1981 -
This PR 2.1991 📈 +0.0009 (+0.04%)

✅ Difftest smoke test passed!

@XiangShanRobot
Copy link

[Generated by GEM5 Performance Robot]
commit: da0f916
workflow: gem5 Align BTB Performance Test(0.3c)

Align BTB Performance

Overall Score

PR Master Diff(%)
Score 17.55 17.64 -0.52 🔴

[Generated by GEM5 Performance Robot]
commit: da0f916
workflow: gem5 Align BTB Performance Test(0.3c)

Align BTB Performance

Overall Score

PR Previous Commit Diff(%)
Score 17.55 17.48 +0.41 🟢

Change-Id: Id4e6f99f3399aef5d06aa8abb7eb2e118632e4ea
@XiangShanRobot
Copy link

[Generated by GEM5 Performance Robot]
commit: 24c0665
workflow: gem5 Align BTB Performance Test(0.3c)

Align BTB Performance

Overall Score

PR Master Diff(%)
Score 17.55 17.64 -0.52 🔴

[Generated by GEM5 Performance Robot]
commit: 24c0665
workflow: gem5 Align BTB Performance Test(0.3c)

Align BTB Performance

Overall Score

PR Previous Commit Diff(%)
Score 17.55 17.55 -0.00

Change-Id: Iba1c0e49894e5662f12316054af294a52f338a06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/cpu/pred/BranchPredictor.py`:
- Around line 1074-1081: The vector parameter lengths for the MicroTAGE
configuration (tableSizes, TTagBitSizes, TTagPcShifts, histLengths) do not match
numPredictors and will trigger constructor asserts; update these so their
lengths equal numPredictors: either change numPredictors to 2 if you intend two
TAGE tables, or shrink tableSizes, TTagBitSizes, TTagPcShifts, and histLengths
to single-element vectors to match numPredictors = 1; locate and edit the
declarations of numPredictors, tableSizes, TTagBitSizes, TTagPcShifts, and
histLengths in the MicroTAGE class so the vector counts are consistent with the
constructor's predictor loop.
🧹 Nitpick comments (1)
src/cpu/pred/BranchPredictor.py (1)

1066-1091: Minor: Inconsistent spacing in parameter descriptions.

Several parameter definitions are missing spaces after commas/colons (e.g., [512]*2,"the TAGE..." vs the conventional [512]*2, "the TAGE..."). This is a minor style inconsistency compared to the rest of the file.

Comment on lines +1074 to +1081
# Keep vector parameters consistent with numPredictors to avoid constructor asserts.
numPredictors = Param.Unsigned(1, "Number of TAGE predictors")
tableSizes = VectorParam.Unsigned([512]*2,"the TAGE T0~Tn length")
TTagBitSizes = VectorParam.Unsigned([16]*2 ,"the T0~Tn entry's tag bit size")
TTagPcShifts = VectorParam.Unsigned([1]*2 ,"when the T0~Tn entry's tag generating, PC right shift")
blockSize = Param.Unsigned(32,"tage index function uses 32B aligned block address")

histLengths = VectorParam.Unsigned([9,18],"the BTB TAGE T0~Tn history length")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Extract MicroTAGE class definition from BranchPredictor.py
echo "=== MicroTAGE class (lines 1074-1081 area) ==="
sed -n '1066,1095p' src/cpu/pred/BranchPredictor.py

echo ""
echo "=== BTBTAGE class for comparison (lines 1047-1053 area) ==="
sed -n '1040,1055p' src/cpu/pred/BranchPredictor.py

Repository: OpenXiangShan/GEM5

Length of output: 3078


🏁 Script executed:

#!/bin/bash
# Find C++ constructor files for MicroTAGE
find src/cpu/pred -name "*microtage*" -o -name "*btb_tage*" | head -20

Repository: OpenXiangShan/GEM5

Length of output: 334


🏁 Script executed:

#!/bin/bash
# Search for numPredictors validation in C++ files
rg -n "numPredictors" src/cpu/pred --type cc -B 2 -A 5 2>/dev/null | head -100

Repository: OpenXiangShan/GEM5

Length of output: 44


🏁 Script executed:

#!/bin/bash
# Search for MicroTAGE constructor in C++ files
echo "=== MicroTAGE constructor in microtage.cc ==="
rg -n "MicroTAGE::" src/cpu/pred/btb/microtage.cc -A 30 | head -80

Repository: OpenXiangShan/GEM5

Length of output: 3049


🏁 Script executed:

#!/bin/bash
# Search for parameter size validation in constructor
echo "=== Size validation in microtage.cc ==="
rg -n "assert|size|numPredictors|tableSizes" src/cpu/pred/btb/microtage.cc -B 2 -A 2 | head -100

Repository: OpenXiangShan/GEM5

Length of output: 4110


🏁 Script executed:

#!/bin/bash
# Check the microtage.hh header file for constructor signature
echo "=== MicroTAGE header file ==="
cat -n src/cpu/pred/btb/microtage.hh | head -100

Repository: OpenXiangShan/GEM5

Length of output: 4142


Fix parameter size mismatch in MicroTAGE class definition.

The comment explicitly warns to "Keep vector parameters consistent with numPredictors to avoid constructor asserts," but the configuration violates this:

  • numPredictors = 1
  • tableSizes, TTagBitSizes, TTagPcShifts, histLengths all have 2 elements

Only index 0 of each vector is used in the constructor loop; index 1 is wasted. Either set numPredictors to 2 or reduce all vectors to 1 element. Comparing with BTBTAGE (lines 1047-1053), which has numPredictors = 8 with all vectors containing exactly 8 elements, shows the correct pattern.

Proposed fix: Either set numPredictors to 2, or reduce vectors to 1 element

Option A (if 2 TAGE tables are intended):

-    numPredictors = Param.Unsigned(1, "Number of TAGE predictors")
+    numPredictors = Param.Unsigned(2, "Number of TAGE predictors")

Option B (if 1 TAGE table is intended):

-    tableSizes = VectorParam.Unsigned([512]*2,"the TAGE T0~Tn length")
-    TTagBitSizes = VectorParam.Unsigned([16]*2 ,"the T0~Tn entry's tag bit size")
-    TTagPcShifts = VectorParam.Unsigned([1]*2 ,"when the T0~Tn entry's tag generating, PC right shift")
+    tableSizes = VectorParam.Unsigned([512],"the TAGE T0~Tn length")
+    TTagBitSizes = VectorParam.Unsigned([16],"the T0~Tn entry's tag bit size")
+    TTagPcShifts = VectorParam.Unsigned([1],"when the T0~Tn entry's tag generating, PC right shift")
     blockSize = Param.Unsigned(32,"tage index function uses 32B aligned block address")

-    histLengths = VectorParam.Unsigned([9,18],"the BTB TAGE T0~Tn history length")
+    histLengths = VectorParam.Unsigned([9],"the BTB TAGE T0~Tn history length")
🧰 Tools
🪛 Ruff (0.14.13)

1075-1075: Param may be undefined, or defined from star imports

(F405)


1076-1076: VectorParam may be undefined, or defined from star imports

(F405)


1077-1077: VectorParam may be undefined, or defined from star imports

(F405)


1078-1078: VectorParam may be undefined, or defined from star imports

(F405)


1079-1079: Param may be undefined, or defined from star imports

(F405)


1081-1081: VectorParam may be undefined, or defined from star imports

(F405)

🤖 Prompt for AI Agents
In `@src/cpu/pred/BranchPredictor.py` around lines 1074 - 1081, The vector
parameter lengths for the MicroTAGE configuration (tableSizes, TTagBitSizes,
TTagPcShifts, histLengths) do not match numPredictors and will trigger
constructor asserts; update these so their lengths equal numPredictors: either
change numPredictors to 2 if you intend two TAGE tables, or shrink tableSizes,
TTagBitSizes, TTagPcShifts, and histLengths to single-element vectors to match
numPredictors = 1; locate and edit the declarations of numPredictors,
tableSizes, TTagBitSizes, TTagPcShifts, and histLengths in the MicroTAGE class
so the vector counts are consistent with the constructor's predictor loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants