summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs32
-rw-r--r--tests/test.rs61
2 files changed, 74 insertions, 19 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 8891726..f199c92 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -33,11 +33,11 @@ impl Default for Opcode {
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum Opcode {
- // TODO: what kind of no-op/undefined are these exactly
- Purple,
- Cyan,
- Brown,
- White,
+ // Undefined opcode regions come from manual page 3:299.
+ Purple, // Reserved if PR[qp] = 1
+ Cyan, // Reserved if PR[qp] = 1
+ Brown, // Reserved
+ White, // Ignored; executes as nop (for hint space).
Addp4,
Adds,
@@ -1313,21 +1313,31 @@ impl yaxpeax_arch::Instruction for InstructionBundle {
// Rotation size cannot be larger than frame.
(sor << 3) <= sof &&
// Local size cannot be larger than frame.
- sol <= sof &&
- // Alloc cannot be predicated.
- insn.predicate() == 0
+ sol <= sof
};
for insn in &self.instructions {
match insn.opcode {
- // B8 family instructions cannot be predicated
- Opcode::Cover | Opcode::Clrrb | Opcode::Clrrb_pr | Opcode::Rfi | Opcode::Bsw_0 | Opcode::Bsw_1 | Opcode::Epc => {
+ // Table 5-5 lists the "unpredicatable-instructions" instruction class, which is:
+ // - the B2 instruction format for br.cloop, br.ctop, br.cexit
+ Opcode::Br_cloop | Opcode::Br_cexit | Opcode::Br_ctop |
+ // - the B6 and B7 instruction format for brp. Note however that B6 and B7 use the qp section of opcode
+ // to encode the prediction hint, so these are not included.
+ // - the B8 instruction format for bsw.0, bsw.1, clrrrb, clrrrb.pr, cover, epc, rfi, vmsw.0, vmsw.1
+ Opcode::Cover | Opcode::Clrrb | Opcode::Clrrb_pr | Opcode::Rfi | Opcode::Bsw_0 | Opcode::Bsw_1 | Opcode::Epc |
+ // - the M25 instruction format for flushrs, loadrs
+ Opcode::Flushrs | Opcode::Loadrs |
+ // - the M34 instruction format for alloc
+ Opcode::Alloc |
+ // - and br.ia.
+ Opcode::Br_ia => {
if insn.predicate() != 0 {
return false;
}
},
// Undefined opcode regions
- Opcode::Purple | Opcode::Cyan | Opcode::Brown | Opcode::White => {
+ // Because Opcode::White instructions are defined to execute as `nop`, they are well-defined.
+ Opcode::Purple | Opcode::Cyan | Opcode::Brown => {
return false;
},
_ => {},
diff --git a/tests/test.rs b/tests/test.rs
index 38b8060..d24fb90 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -2364,14 +2364,6 @@ fn test_alloc_restrictions() {
assert_eq!(format!("{}", inst), expected);
assert!(!inst.well_defined());
- // alloc cannot be predicated.
- let expected = "[MMI] (p02) alloc r34=ar.pfs,5,5,0; break.m 0x0; break.i 0x0";
- let data = [0x48, 0x10, 0x15, 0x0a, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
- let mut reader = U8Reader::new(&data[..]);
- let inst = decoder.decode(&mut reader).unwrap();
- assert_eq!(format!("{}", inst), expected);
- assert!(!inst.well_defined());
-
// alloc cannot be in slot 1 of a bundle type without a stop before it.
let expected = "[MMI] break.m 0x0; alloc r34=ar.pfs,5,5,0; break.i 0x0";
let data = [0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2a, 0x14, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00];
@@ -2393,6 +2385,28 @@ fn test_alloc_restrictions() {
fn test_predication_not_allowed() {
let decoder = InstDecoder::default();
+ // B2 instructions cannot be predicated
+ let expected = "[BBB] (p01) br.cloop.sptk.few $+0x0; break.b 0x0; break.b 0x0";
+ let data = [0x36, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
+ let expected = "[BBB] (p01) br.cexit.sptk.few $+0x0; break.b 0x0; break.b 0x0";
+ let data = [0x36, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
+ let expected = "[BBB] (p01) br.ctop.sptk.few $+0x0; break.b 0x0; break.b 0x0";
+ let data = [0x36, 0x38, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
// B8 instructions cannot be predicated
let expected = "[BBB] (p01) cover; break.b 0x0; break.b 0x0";
let data = [0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
@@ -2442,4 +2456,35 @@ fn test_predication_not_allowed() {
let inst = decoder.decode(&mut reader).unwrap();
assert_eq!(format!("{}", inst), expected);
assert!(!inst.well_defined());
+
+ // M25 instructions cannot be predicated.
+ let expected = "[MMI] (p01) flushrs; break.m 0x0; break.i 0x0";
+ let data = [0x28, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
+ let expected = "[MMI] (p01) loadrs; break.m 0x0; break.i 0x0";
+ let data = [0x28, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
+ // alloc cannot be predicated.
+ let expected = "[MMI] (p02) alloc r34=ar.pfs,5,5,0; break.m 0x0; break.i 0x0";
+ let data = [0x48, 0x10, 0x15, 0x0a, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
+
+ // br.ia cannot be predicated.
+ let expected = "[BBB] (p01) br.ia b0,0x0,0x0,0x0; break.b 0x0; break.b 0x0";
+ let data = [0x36, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
+ let mut reader = U8Reader::new(&data[..]);
+ let inst = decoder.decode(&mut reader).unwrap();
+ assert_eq!(format!("{}", inst), expected);
+ assert!(!inst.well_defined());
}