@@ -152,6 +152,45 @@ struct MgscHarness
152152 BTBMGSC::TestAccess::forceUseSC (mgsc) = true ;
153153 }
154154
155+ void
156+ setOnlyBwTable ()
157+ {
158+ BTBMGSC::TestAccess::enableBwTable (mgsc) = true ;
159+ BTBMGSC::TestAccess::enableLTable (mgsc) = false ;
160+ BTBMGSC::TestAccess::enableITable (mgsc) = false ;
161+ BTBMGSC::TestAccess::enableGTable (mgsc) = false ;
162+ BTBMGSC::TestAccess::enablePTable (mgsc) = false ;
163+ BTBMGSC::TestAccess::enableBiasTable (mgsc) = false ;
164+ BTBMGSC::TestAccess::enablePCThreshold (mgsc) = false ;
165+ BTBMGSC::TestAccess::forceUseSC (mgsc) = true ;
166+ }
167+
168+ void
169+ setOnlyITable ()
170+ {
171+ BTBMGSC::TestAccess::enableBwTable (mgsc) = false ;
172+ BTBMGSC::TestAccess::enableLTable (mgsc) = false ;
173+ BTBMGSC::TestAccess::enableITable (mgsc) = true ;
174+ BTBMGSC::TestAccess::enableGTable (mgsc) = false ;
175+ BTBMGSC::TestAccess::enablePTable (mgsc) = false ;
176+ BTBMGSC::TestAccess::enableBiasTable (mgsc) = false ;
177+ BTBMGSC::TestAccess::enablePCThreshold (mgsc) = false ;
178+ BTBMGSC::TestAccess::forceUseSC (mgsc) = true ;
179+ }
180+
181+ void
182+ setOnlyBiasTable ()
183+ {
184+ BTBMGSC::TestAccess::enableBwTable (mgsc) = false ;
185+ BTBMGSC::TestAccess::enableLTable (mgsc) = false ;
186+ BTBMGSC::TestAccess::enableITable (mgsc) = false ;
187+ BTBMGSC::TestAccess::enableGTable (mgsc) = false ;
188+ BTBMGSC::TestAccess::enablePTable (mgsc) = false ;
189+ BTBMGSC::TestAccess::enableBiasTable (mgsc) = true ;
190+ BTBMGSC::TestAccess::enablePCThreshold (mgsc) = false ;
191+ BTBMGSC::TestAccess::forceUseSC (mgsc) = true ;
192+ }
193+
155194 struct StepResult
156195 {
157196 bool predicted_taken{false };
@@ -227,6 +266,9 @@ struct MgscHarness
227266 FetchStream recover_stream;
228267 recover_stream.startPC = start_pc;
229268 recover_stream.predMetas [mgsc.getComponentIdx ()] = meta;
269+ recover_stream.resolved = true ;
270+ recover_stream.exeBranchInfo = entry;
271+ recover_stream.exeTaken = actual_taken;
230272
231273 mgsc.recoverHist (ghr, recover_stream, shamt, actual_taken);
232274 mgsc.recoverPHist (phr, recover_stream, 2 , actual_taken);
@@ -509,6 +551,151 @@ TEST(BTBMGSCTest, GTableLearnsAlternatingPattern)
509551 EXPECT_GE (acc, 0.80 ) << " Accuracy too low for alternating pattern: " << acc;
510552}
511553
554+ TEST (BTBMGSCTest, BwTableLearnsAlternatingPatternOnBackwardBranches)
555+ {
556+ MgscHarness h;
557+ h.setOnlyBwTable ();
558+
559+ const Addr start_pc = 0x1000 ;
560+ const Addr branch_pc = 0x1000 ;
561+ auto entry = makeCondBTBEntry (branch_pc);
562+ entry.target = branch_pc - 4 ; // backward branch so bw_taken == taken
563+
564+ const TageInfoForMGSC tage_info (
565+ /* tage_pred_taken=*/ false ,
566+ /* tage_main_taken=*/ false ,
567+ /* tage_pred_conf_high=*/ true ,
568+ /* tage_pred_conf_mid=*/ false ,
569+ /* tage_pred_conf_low=*/ false ,
570+ /* tage_pred_alt_diff=*/ false );
571+
572+ const int iters = 200 ;
573+ const int warmup = 100 ;
574+ int correct_after_warmup = 0 ;
575+ int total_after_warmup = 0 ;
576+ std::set<unsigned > seen_bw_indices;
577+
578+ for (int i = 0 ; i < iters; ++i) {
579+ bool actual_taken = (i % 2 ) == 0 ;
580+ auto step = h.step (start_pc, entry, tage_info, actual_taken);
581+
582+ if (!step.mgsc_pred .bwIndex .empty ()) {
583+ seen_bw_indices.insert (step.mgsc_pred .bwIndex [0 ]);
584+ }
585+
586+ if (i >= warmup) {
587+ total_after_warmup++;
588+ if (step.predicted_taken == actual_taken) {
589+ correct_after_warmup++;
590+ }
591+ }
592+ }
593+
594+ EXPECT_GE (seen_bw_indices.size (), 2u );
595+ double acc = static_cast <double >(correct_after_warmup) / static_cast <double >(total_after_warmup);
596+ EXPECT_GE (acc, 0.80 ) << " Accuracy too low for alternating backward branches: " << acc;
597+ }
598+
599+ TEST (BTBMGSCTest, ITableLearnsFixedTripCountLoop)
600+ {
601+ MgscHarness h;
602+ h.setOnlyITable ();
603+
604+ const Addr start_pc = 0x1000 ;
605+ const Addr branch_pc = 0x1000 ;
606+ auto entry = makeCondBTBEntry (branch_pc);
607+ entry.target = branch_pc - 4 ; // backward loop branch
608+
609+ const TageInfoForMGSC tage_info (
610+ /* tage_pred_taken=*/ false ,
611+ /* tage_main_taken=*/ false ,
612+ /* tage_pred_conf_high=*/ true ,
613+ /* tage_pred_conf_mid=*/ false ,
614+ /* tage_pred_conf_low=*/ false ,
615+ /* tage_pred_alt_diff=*/ false );
616+
617+ // Loop pattern: T, T, T, N, repeat. IMLI counter (consecutive backward-taken count) should separate phases.
618+ const int iters = 400 ;
619+ const int warmup = 200 ;
620+ int correct_after_warmup = 0 ;
621+ int total_after_warmup = 0 ;
622+ std::set<unsigned > seen_i_indices;
623+
624+ for (int i = 0 ; i < iters; ++i) {
625+ bool actual_taken = (i % 4 ) != 3 ;
626+ auto step = h.step (start_pc, entry, tage_info, actual_taken);
627+
628+ if (!step.mgsc_pred .iIndex .empty ()) {
629+ seen_i_indices.insert (step.mgsc_pred .iIndex [0 ]);
630+ }
631+
632+ if (i >= warmup) {
633+ total_after_warmup++;
634+ if (step.predicted_taken == actual_taken) {
635+ correct_after_warmup++;
636+ }
637+ }
638+ }
639+
640+ EXPECT_GE (seen_i_indices.size (), 3u );
641+ double acc = static_cast <double >(correct_after_warmup) / static_cast <double >(total_after_warmup);
642+ EXPECT_GE (acc, 0.85 ) << " Accuracy too low for fixed-trip loop: " << acc;
643+ }
644+
645+ TEST (BTBMGSCTest, BiasTableLearnsTwoTageContexts)
646+ {
647+ MgscHarness h;
648+ h.setOnlyBiasTable ();
649+
650+ const Addr start_pc = 0x1000 ;
651+ const Addr branch_pc = 0x1000 ;
652+ auto entry = makeCondBTBEntry (branch_pc);
653+
654+ // Two contexts keyed by (tage_main_taken, tage_pred_conf_low). Bias table should learn separate counters.
655+ const TageInfoForMGSC ctx_a (
656+ /* tage_pred_taken=*/ false ,
657+ /* tage_main_taken=*/ false ,
658+ /* tage_pred_conf_high=*/ false ,
659+ /* tage_pred_conf_mid=*/ false ,
660+ /* tage_pred_conf_low=*/ false ,
661+ /* tage_pred_alt_diff=*/ false );
662+ const TageInfoForMGSC ctx_b (
663+ /* tage_pred_taken=*/ false ,
664+ /* tage_main_taken=*/ true ,
665+ /* tage_pred_conf_high=*/ false ,
666+ /* tage_pred_conf_mid=*/ false ,
667+ /* tage_pred_conf_low=*/ true ,
668+ /* tage_pred_alt_diff=*/ false );
669+
670+ const int iters = 200 ;
671+ const int warmup = 100 ;
672+ int correct_after_warmup = 0 ;
673+ int total_after_warmup = 0 ;
674+ std::set<unsigned > seen_bias_indices;
675+
676+ for (int i = 0 ; i < iters; ++i) {
677+ bool use_a = (i % 2 ) == 0 ;
678+ const auto &tage_info = use_a ? ctx_a : ctx_b;
679+ bool actual_taken = use_a; // ctx_a => taken, ctx_b => not taken
680+
681+ auto step = h.step (start_pc, entry, tage_info, actual_taken);
682+ if (!step.mgsc_pred .biasIndex .empty ()) {
683+ seen_bias_indices.insert (step.mgsc_pred .biasIndex [0 ]);
684+ }
685+
686+ if (i >= warmup) {
687+ total_after_warmup++;
688+ if (step.predicted_taken == actual_taken) {
689+ correct_after_warmup++;
690+ }
691+ }
692+ }
693+
694+ EXPECT_GE (seen_bias_indices.size (), 2u );
695+ double acc = static_cast <double >(correct_after_warmup) / static_cast <double >(total_after_warmup);
696+ EXPECT_GE (acc, 0.90 ) << " Accuracy too low for two-context bias learning: " << acc;
697+ }
698+
512699} // namespace test
513700} // namespace btb_pred
514701} // namespace branch_prediction
0 commit comments