fix(disasm): PPCBUG-640+650 fmt_bc spurious condition suffix on bdnz/bdz
PPCBUG-640: For BO=16 (bdnz: decrement CTR, branch if non-zero, ignore CR)
and BO=18 (bdz: same with branch-if-zero), `fmt_bc` fell through to the
`if decr` block and computed `cond_name_opt` from the don't-care BI=0 /
cond_true=false pair, yielding `Some("ge")`. The output was therefore
`bdnzge` / `bdzge` — a CTR-only branch with a spurious CR-derived suffix.
PPCBUG-650 (companion): the golden fixture pinned the wrong output, so
the regression had no detection signal until now.
`fmt_bclr` already had the correct `if decr && uncond` guard at line 872
producing `bdnzlr` / `bdzlr`. `fmt_bc` lacked the equivalent.
Fix: gate the condition string on `!uncond` inside the `if decr` block.
For BO=16/18 (uncond bit set), the condition suffix is now empty.
Tests: extended_mnemonics.json fixture rows for bdnz/bdz now expect the
correct `ext_mnemonic: "bdnz"` / `"bdz"`.
Impact: every analysis-DB query for `bdnz` loops (common in pixel-shader
and vertex processing) was returning zero rows; matches stored as `bdnzge`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -828,7 +828,10 @@ fn fmt_bc(instr: &DecodedInstr) -> DisasmText {
|
|||||||
|
|
||||||
if decr {
|
if decr {
|
||||||
let z = if bo & 0x02 != 0 { "z" } else { "nz" };
|
let z = if bo & 0x02 != 0 { "z" } else { "nz" };
|
||||||
let cond_str = cond_name_opt.unwrap_or("");
|
// BO bit 4 (uncond) means CR is ignored — pure CTR-decrement branch.
|
||||||
|
// Without this guard, bdnz/bdz would emit a spurious `ge` suffix derived
|
||||||
|
// from the don't-care BI=0 / cond_true=false pair (PPCBUG-640).
|
||||||
|
let cond_str = if uncond { "" } else { cond_name_opt.unwrap_or("") };
|
||||||
let ext_mnem = format!("bd{z}{cond_str}{a}{l}");
|
let ext_mnem = format!("bd{z}{cond_str}{a}{l}");
|
||||||
let ext_ops = format!("{cr}0x{target:08X}");
|
let ext_ops = format!("{cr}0x{target:08X}");
|
||||||
with_ext(&base_mnem, base_ops, 8, &ext_mnem, ext_ops, 8)
|
with_ext(&base_mnem, base_ops, 8, &ext_mnem, ext_ops, 8)
|
||||||
|
|||||||
@@ -366,7 +366,7 @@
|
|||||||
"addr": "0x82000000",
|
"addr": "0x82000000",
|
||||||
"mnemonic": "bc",
|
"mnemonic": "bc",
|
||||||
"operands": "16, lt, 0x82000040",
|
"operands": "16, lt, 0x82000040",
|
||||||
"ext_mnemonic": "bdnzge",
|
"ext_mnemonic": "bdnz",
|
||||||
"ext_operands": "0x82000040",
|
"ext_operands": "0x82000040",
|
||||||
"branch_target": "0x82000040"
|
"branch_target": "0x82000040"
|
||||||
},
|
},
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
"addr": "0x82000000",
|
"addr": "0x82000000",
|
||||||
"mnemonic": "bc",
|
"mnemonic": "bc",
|
||||||
"operands": "18, lt, 0x82000040",
|
"operands": "18, lt, 0x82000040",
|
||||||
"ext_mnemonic": "bdzge",
|
"ext_mnemonic": "bdz",
|
||||||
"ext_operands": "0x82000040",
|
"ext_operands": "0x82000040",
|
||||||
"branch_target": "0x82000040"
|
"branch_target": "0x82000040"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user