Skip to content

Commit

Permalink
Implement beqzl and bnezl pseudos
Browse files Browse the repository at this point in the history
  • Loading branch information
AngheloAlf committed Feb 23, 2025
1 parent 1a67b78 commit 1f912ed
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 9 deletions.
20 changes: 20 additions & 0 deletions src/rabbitizer/src/generated/array_opcodes.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/rabbitizer/src/generated/enum_opcode.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions src/rabbitizer/src/instr/instruction_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,50 @@ impl InstructionFlags {
self.with_decoding_flags(other)
}

#[must_use]
pub const fn pseudo_beqzl(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_beqzl)
}
pub fn set_pseudo_beqzl(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_beqzl);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_beqzl);
}
}
#[must_use]
pub const fn with_pseudo_beqzl(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_beqzl)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_beqzl.complement())
};
self.with_decoding_flags(other)
}

#[must_use]
pub const fn pseudo_bnezl(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_bnezl)
}
pub fn set_pseudo_bnezl(&mut self, turn_on: bool) {
if turn_on {
self.decoding_flags.insert(DecodingFlags::pseudo_bnezl);
} else {
self.decoding_flags.remove(DecodingFlags::pseudo_bnezl);
}
}
#[must_use]
pub const fn with_pseudo_bnezl(self, turn_on: bool) -> Self {
let other = if turn_on {
self.decoding_flags.union(DecodingFlags::pseudo_bnezl)
} else {
self.decoding_flags
.intersection(DecodingFlags::pseudo_bnezl.complement())
};
self.with_decoding_flags(other)
}

#[must_use]
pub const fn pseudo_b(&self) -> bool {
self.decoding_flags.contains(DecodingFlags::pseudo_b)
Expand Down
22 changes: 17 additions & 5 deletions src/rabbitizer/src/opcodes/decoding_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ bitflags! {
const enable_pseudos = 1 << 0;
const pseudo_beqz = 1 << 1;
const pseudo_bnez = 1 << 2;
const pseudo_b = 1 << 3;
const pseudo_bal = 1 << 4;
const pseudo_not = 1 << 5;
const pseudo_neg = 1 << 6;
const pseudo_negu = 1 << 7;
const pseudo_beqzl = 1 << 3;
const pseudo_bnezl = 1 << 4;
const pseudo_b = 1 << 5;
const pseudo_bal = 1 << 6;
const pseudo_not = 1 << 7;
const pseudo_neg = 1 << 8;
const pseudo_negu = 1 << 9;
}
}

Expand All @@ -29,6 +31,8 @@ impl DecodingFlags {
Self::enable_pseudos
.union(Self::pseudo_beqz)
.union(Self::pseudo_bnez)
.union(Self::pseudo_beqzl)
.union(Self::pseudo_bnezl)
.union(Self::pseudo_b)
.union(Self::pseudo_bal)
.union(Self::pseudo_not)
Expand All @@ -41,6 +45,8 @@ impl DecodingFlags {
self.insert(Self::enable_pseudos);
self.insert(Self::pseudo_beqz);
self.insert(Self::pseudo_bnez);
self.insert(Self::pseudo_beqzl);
self.insert(Self::pseudo_bnezl);
self.insert(Self::pseudo_b);
self.insert(Self::pseudo_bal);
self.insert(Self::pseudo_not);
Expand All @@ -50,6 +56,8 @@ impl DecodingFlags {
self.remove(Self::enable_pseudos);
self.remove(Self::pseudo_beqz);
self.remove(Self::pseudo_bnez);
self.remove(Self::pseudo_beqzl);
self.remove(Self::pseudo_bnezl);
self.remove(Self::pseudo_b);
self.remove(Self::pseudo_bal);
self.remove(Self::pseudo_not);
Expand All @@ -63,6 +71,8 @@ impl DecodingFlags {
self.union(Self::enable_pseudos)
.union(Self::pseudo_beqz)
.union(Self::pseudo_bnez)
.union(Self::pseudo_beqzl)
.union(Self::pseudo_bnezl)
.union(Self::pseudo_b)
.union(Self::pseudo_bal)
.union(Self::pseudo_not)
Expand All @@ -72,6 +82,8 @@ impl DecodingFlags {
self.intersection(Self::enable_pseudos.complement())
.intersection(Self::pseudo_beqz.complement())
.intersection(Self::pseudo_bnez.complement())
.intersection(Self::pseudo_beqzl.complement())
.intersection(Self::pseudo_bnezl.complement())
.intersection(Self::pseudo_b.complement())
.intersection(Self::pseudo_bal.complement())
.intersection(Self::pseudo_not.complement())
Expand Down
2 changes: 1 addition & 1 deletion src/rabbitizer/src/opcodes/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::operands::{Operand, OperandIterator, OPERAND_COUNT_MAX};
// Rust doesn't have a way to automatically get the larger value of an enum and
// I didn't want to have a `Opcode::MAX` value, so instead we manually maintain
// this constant.
pub(crate) const OPCODE_COUNT: usize = 885;
pub(crate) const OPCODE_COUNT: usize = 887;

impl Opcode {
#[must_use]
Expand Down
14 changes: 14 additions & 0 deletions src/rabbitizer/src/opcodes/opcode_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ impl OpcodeDecoder {
opcode = Opcode::core_bnez;
}
}
Opcode::core_beql => {
if EncodedFieldMask::rt.get_shifted(word) == 0 && flags
.contains(DecodingFlags::enable_pseudos.union(DecodingFlags::pseudo_beqzl)) {
opcode = Opcode::core_beqzl;
}
}
Opcode::core_bnel => {
if EncodedFieldMask::rt.get_shifted(word) == 0
&& flags
.contains(DecodingFlags::enable_pseudos.union(DecodingFlags::pseudo_bnezl))
{
opcode = Opcode::core_bnezl;
}
}
_ => {}
}

Expand Down
87 changes: 87 additions & 0 deletions src/rabbitizer/tests/instruction_tests_none.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,93 @@ fn check_none_instructions() {
opcode_str: "ctc2",
operands_str: [Some("$v0"), Some("$28"), None, None, None],
},
TestEntry {
instr: Instruction::new(
0x50850007,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_beqzl(true),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "beql $a0, $a1, . + 4 + (0x7 << 2)",
expected_opcode: Opcode::core_beql,
opcode_str: "beql",
operands_str: [Some("$a0"), Some("$a1"), Some(". + 4 + (0x7 << 2)"), None, None],
},
TestEntry {
instr: Instruction::new(
0x50800007,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_beqzl(true),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "beqzl $a0, . + 4 + (0x7 << 2)",
expected_opcode: Opcode::core_beqzl,
opcode_str: "beqzl",
operands_str: [Some("$a0"), Some(". + 4 + (0x7 << 2)"), None, None, None],
},
TestEntry {
instr: Instruction::new(
0x50800007,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_beqzl(false),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "beql $a0, $zero, . + 4 + (0x7 << 2)",
expected_opcode: Opcode::core_beql,
opcode_str: "beql",
operands_str: [Some("$a0"), Some("$zero"), Some(". + 4 + (0x7 << 2)"), None, None],
},
TestEntry {
instr: Instruction::new(
0x54850005,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_bnezl(true),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "bnel $a0, $a1, . + 4 + (0x5 << 2)",
expected_opcode: Opcode::core_bnel,
opcode_str: "bnel",
operands_str: [Some("$a0"), Some("$a1"), Some(". + 4 + (0x5 << 2)"), None, None],
},
TestEntry {
instr: Instruction::new(
0x54800005,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_bnezl(true),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "bnezl $a0, . + 4 + (0x5 << 2)",
expected_opcode: Opcode::core_bnezl,
opcode_str: "bnezl",
operands_str: [Some("$a0"), Some(". + 4 + (0x5 << 2)"), None, None, None],
},
TestEntry {
instr: Instruction::new(
0x54800005,
Vram::new(0x80000000),
InstructionFlags::new(IsaVersion::MIPS_III).with_pseudo_bnezl(false),
),
imm_override: None,
display_flags: InstructionDisplayFlags::default(),
valid: true,
expected: "bnel $a0, $zero, . + 4 + (0x5 << 2)",
expected_opcode: Opcode::core_bnel,
opcode_str: "bnel",
operands_str: [Some("$a0"), Some("$zero"), Some(". + 4 + (0x5 << 2)"), None, None],
},

// gnu_div

TestEntry {
instr: Instruction::new(
0x0085001A,
Expand Down
17 changes: 17 additions & 0 deletions tables/tables/opcodes/core/core_normal.inc
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,23 @@
is_branch: true
) // Branch on Not Equal Zero

RAB_DEF_OPCODE_PSEUDO(
core, beqzl, IsaVersion::MIPS_II, None,
operands: Operand::arr2(Operand::core_rs, Operand::core_branch_target_label),
instr_type: InstrType::I,
is_branch: true,
is_branch_likely: true,
reads_rs: true
) // Branch on EQual Zero Likely
RAB_DEF_OPCODE_PSEUDO(
core, bnezl, IsaVersion::MIPS_II, None,
operands: Operand::arr2(Operand::core_rs, Operand::core_branch_target_label),
instr_type: InstrType::I,
is_branch: true,
is_branch_likely: true,
reads_rs: true
) // Branch on Not Equal Zero Likely

RAB_DEF_OPCODE_REDIRECT(0x00, none, special)
RAB_DEF_OPCODE_REDIRECT(0x01, none, regimm)
RAB_DEF_OPCODE_REDIRECT(0x10, none, coprocessor0)
Expand Down
6 changes: 3 additions & 3 deletions todo.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Add these pseudos:
- beqzl
- bnezl
rsp:
- lwv


- Add `size_hint` to iterators

- Set properties to float registers

- Rename pseudos to aliases?
- A pseudo can expand to multiple instructions, but aliases can't

0 comments on commit 1f912ed

Please sign in to comment.