aboutsummaryrefslogtreecommitdiff
path: root/data/generate_opcode.py
diff options
context:
space:
mode:
Diffstat (limited to 'data/generate_opcode.py')
-rw-r--r--data/generate_opcode.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/data/generate_opcode.py b/data/generate_opcode.py
index e02785d..27eea11 100644
--- a/data/generate_opcode.py
+++ b/data/generate_opcode.py
@@ -6,6 +6,7 @@ class IsaData:
def __init__(self, data):
isa_extensions = isa_data['sets']
microarchitectures = isa_data['uarch']
+ self.instructions = isa_data['instructions']
loaded_exts = {}
for ext in isa_extensions:
@@ -15,6 +16,36 @@ class IsaData:
for arch in microarchitectures:
loaded_uarches[arch['name']] = arch
+ def validate_err(mnemonic, message):
+ raise Exception("inst={}, {}".format(mnemonic, message))
+
+ for (name, data) in self.instructions.items():
+ if "kind" not in data:
+ validate_err(name, "instruction is missing declared kind")
+ if "fault_causes" not in data:
+ validate_err(name, "instruction is missing declared fault causes")
+ if "deprecated" not in data:
+ validate_err(name, "instruction does not declare if it is deprecated")
+ if data['kind'] == "":
+ validate_err(name, "kind is not acutally... populated..")
+
+ for (name, ext) in loaded_exts.items():
+ if 'new' not in ext:
+ raise Exception("ext {} does not have a new instructions section".format(name))
+
+ def validate_instructions(setname, to_validate, insts):
+ for inst in to_validate:
+ # it's actually "include this set", not an instruction, so skip it.
+ # if there's another set with that name, we'll have covered it in iterating all extensions.
+ if inst.startswith("+"):
+ continue
+ if inst not in insts:
+ validate_err(inst, "instruction is in extension {} but not defined".format(setname))
+
+ validate_instructions(name, ext['new'], self.instructions)
+ if 'extended' in ext:
+ validate_instructions(name, ext['extended'], self.instructions)
+
self.exts = loaded_exts
self.uarches = loaded_uarches
self.referenced_sets = set([])
@@ -173,6 +204,8 @@ for root in ROOTS:
f = open("../src/generated/opcode.rs", "w")
f = Output(f)
+f.writeline("use crate::safer_unchecked::GetSaferUnchecked;")
+f.newline()
for annotation in OPCODE_ANNOTATIONS:
f.writeline(annotation)
f.begin_block("pub enum Opcode")
@@ -197,6 +230,17 @@ f.outdent()
f.writeline("];")
f.newline()
+f.begin_block("impl Opcode")
+f.begin_block("pub(crate) fn name(&self) -> &'static str")
+f.comment("safety: `MNEMONICS` and `Opcode` are generated together, where every entry in `Opcode` guarantees")
+f.comment(" a corresponding entry in `MNEMONICS`.")
+f.begin_block("unsafe")
+f.writeline("MNEMONICS.get_kinda_unchecked(*self as usize)")
+f.end_block()
+f.end_block()
+f.end_block()
+f.newline()
+
for root in ROOTS:
if root == "x86_generic":
continue
@@ -214,6 +258,22 @@ for root in ROOTS:
else:
f.writeline("{} = super::Opcode::{} as {},".format(str(inst).upper(), str(inst).upper(), OPCODE_REPR))
f.end_block()
+ f.newline()
+ f.begin_block("impl Opcode")
+
+ f.begin_block("pub fn to_generic(&self) -> super::Opcode")
+ f.comment("safety: each item in `Self` is defined with the same value in `super::Opcode`. `Self` is")
+ f.comment(" a subset of `super::Opcode` so casting to the more generic form is well-defined.")
+ f.writeline("unsafe { core::mem::transmute::<Self, super::Opcode>(*self) }")
+ f.end_block()
+
+ f.newline()
+
+ f.begin_block("fn nane(&self) -> &'static str")
+ f.writeline("self.to_generic().name()")
+ f.end_block()
+
+ f.end_block()
f.end_block()
f.newline()
@@ -235,6 +295,57 @@ f = Output(f)
# f.newline()
+f.writeline("use yaxpeax_arch::{Colorize, YaxColors};")
+f.writeline("use core::fmt;")
+f.writeline("use crate::generated::opcode::Opcode;")
+
+f.newline()
+
+f.begin_block("impl fmt::Display for Opcode")
+f.begin_block("fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result")
+f.writeline("f.write_str(self.name())")
+f.end_block()
+f.end_block()
+
+f.newline()
+
+f.begin_block("impl<T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode")
+f.begin_block("fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result")
+f.begin_block("match self")
+
+by_kind = {}
+for (inst, data) in isa_data.instructions.items():
+ if data['kind'] not in by_kind:
+ by_kind[data['kind']] = []
+ by_kind[data['kind']].append(inst)
+
+for (kind, insts) in by_kind.items():
+ insts = list(insts)
+ insts.sort()
+ suffix_needed = False
+ any_entries = False
+ for inst in insts:
+ if suffix_needed:
+ f.writeline("|")
+
+ if inst == "invalid":
+ f.write("Opcode::Invalid ")
+ else:
+ f.write("Opcode::{} ".format(inst.upper()))
+ suffix_needed = True
+ any_entries = True
+
+ f.writeline("=> {")
+ f.indent()
+ f.writeline("write!(out, \"{{}}\", colors.{}(self))".format(kind))
+ f.outdent()
+ f.writeline("}")
+
+f.end_block()
+f.end_block()
+f.end_block()
+
+f.newline()
for root in ROOTS:
if root == "x86_generic":
@@ -244,6 +355,9 @@ for root in ROOTS:
f.begin_block("pub(crate) mod {}".format(root))
f.writeline("use crate::generated::{}::Opcode;".format(root))
f.writeline("use crate::{}::{{InstDecoder, Instruction, DecodeError}};".format(root))
+ f.newline()
+ f.writeline("use yaxpeax_arch::{Colorize, YaxColors};")
+ f.writeline("use core::fmt;")
f.begin_block("impl InstDecoder")
for ext in arch['extensions']:
@@ -252,6 +366,18 @@ for root in ROOTS:
f.end_block()
f.end_block()
+ f.begin_block("impl<T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode")
+ f.begin_block("fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result")
+ f.writeline("self.to_generic().colorize(colors, out)")
+ f.end_block()
+ f.end_block()
+
+ f.begin_block("impl Opcode")
+ f.begin_block("pub(crate) fn name(&self) -> &'static str")
+ f.writeline("self.to_generic().name()")
+ f.end_block()
+ f.end_block()
+
f.begin_block("pub(crate) fn revise_instruction(decoder: &InstDecoder, inst: &mut Instruction) -> Result<(), DecodeError>")
f.begin_block("if inst.prefixes.evex().is_some()")