Currently we use macros to define the shape of each of the
instruction building methods. This works while all of the
instructions share the same fields, but is really hard to get
working when they're an enum with different shapes. This is an
incremental step toward a bigger refactor of changing the Insn
from a struct to an enum.
This commit is contained in:
Kevin Newton 2022-08-17 12:56:23 -04:00 коммит произвёл Takashi Kokubun
Родитель 1cf9f56c55
Коммит b735eb5ef3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 6FFC433B12EE23DD
3 изменённых файлов: 246 добавлений и 197 удалений

Просмотреть файл

@ -228,17 +228,17 @@ impl Assembler
Op::And | Op::Or | Op::Xor => {
match (opnds[0], opnds[1]) {
(Opnd::Reg(_), Opnd::Reg(_)) => {
asm.push_insn(insn.op, vec![opnds[0], opnds[1]], insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, vec![opnds[0], opnds[1]], insn.target, insn.text, insn.pos_marker);
},
(reg_opnd @ Opnd::Reg(_), other_opnd) |
(other_opnd, reg_opnd @ Opnd::Reg(_)) => {
let opnd1 = split_bitmask_immediate(asm, other_opnd);
asm.push_insn(insn.op, vec![reg_opnd, opnd1], insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, vec![reg_opnd, opnd1], insn.target, insn.text, insn.pos_marker);
},
_ => {
let opnd0 = split_load_operand(asm, opnds[0]);
let opnd1 = split_bitmask_immediate(asm, opnds[1]);
asm.push_insn(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
}
}
},
@ -284,7 +284,7 @@ impl Assembler
}
}).collect();
asm.push_insn(insn.op, new_opnds, insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, new_opnds, insn.target, insn.text, insn.pos_marker);
},
Op::IncrCounter => {
// We'll use LDADD later which only works with registers
@ -403,7 +403,7 @@ impl Assembler
asm.test(opnd0, opnd1);
},
_ => {
asm.push_insn(insn.op, opnds, insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, opnds, insn.target, insn.text, insn.pos_marker);
}
};

Просмотреть файл

@ -466,23 +466,15 @@ impl Assembler
}
}
/// Append an instruction to the list
pub(super) fn push_insn(
&mut self,
op: Op,
opnds: Vec<Opnd>,
target: Option<Target>,
text: Option<String>,
pos_marker: Option<PosMarkerFn>
) -> Opnd
{
/// Append an instruction onto the current list of instructions.
pub(super) fn push_insn(&mut self, mut insn: Insn) -> Opnd {
// Index of this instruction
let insn_idx = self.insns.len();
// If we find any InsnOut from previous instructions, we're going to
// update the live range of the previous instruction to point to this
// one.
for opnd in &opnds {
for opnd in &insn.opnds {
match opnd {
Opnd::InsnOut{ idx, .. } => {
self.live_ranges[*idx] = insn_idx;
@ -496,7 +488,7 @@ impl Assembler
let mut out_num_bits: u8 = 0;
for opnd in &opnds {
for opnd in &insn.opnds {
match *opnd {
Opnd::InsnOut{ num_bits, .. } |
Opnd::Mem(Mem { num_bits, .. }) |
@ -518,15 +510,7 @@ impl Assembler
// Operand for the output of this instruction
let out_opnd = Opnd::InsnOut{ idx: insn_idx, num_bits: out_num_bits };
let insn = Insn {
op,
text,
opnds,
out: out_opnd,
target,
pos_marker,
};
insn.out = out_opnd;
self.insns.push(insn);
self.live_ranges.push(insn_idx);
@ -535,40 +519,25 @@ impl Assembler
out_opnd
}
/// Add a comment at the current position
pub fn comment(&mut self, text: &str)
/// Append an instruction to the list by creating a new instruction from the
/// component parts given to this function.
pub(super) fn push_insn_parts(
&mut self,
op: Op,
opnds: Vec<Opnd>,
target: Option<Target>,
text: Option<String>,
pos_marker: Option<PosMarkerFn>
) -> Opnd
{
let insn = Insn {
op: Op::Comment,
text: Some(text.to_owned()),
opnds: vec![],
self.push_insn(Insn {
op,
text,
opnds,
out: Opnd::None,
target: None,
pos_marker: None,
};
self.insns.push(insn);
self.live_ranges.push(self.insns.len());
}
/// Bake a string at the current position
pub fn bake_string(&mut self, text: &str)
{
let insn = Insn {
op: Op::BakeString,
text: Some(text.to_owned()),
opnds: vec![],
out: Opnd::None,
target: None,
pos_marker: None,
};
self.insns.push(insn);
self.live_ranges.push(self.insns.len());
}
/// Load an address relative to the given label.
#[must_use]
pub fn lea_label(&mut self, target: Target) -> Opnd {
self.push_insn(Op::LeaLabel, vec![], Some(target), None, None)
target,
pos_marker,
})
}
/// Create a new label instance that we can jump to
@ -735,7 +704,7 @@ impl Assembler
}
).collect();
asm.push_insn(insn.op, reg_opnds, insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, reg_opnds, insn.target, insn.text, insn.pos_marker);
// Set the output register for this instruction
let num_insns = asm.insns.len();
@ -777,16 +746,6 @@ impl Assembler
pub fn into_lookback_iter(self) -> AssemblerLookbackIterator {
AssemblerLookbackIterator::new(self)
}
pub fn ccall(&mut self, fptr: *const u8, opnds: Vec<Opnd>) -> Opnd {
let target = Target::FunPtr(fptr);
self.push_insn(Op::CCall, opnds, Some(target), None, None)
}
// pub fn pos_marker<F: FnMut(CodePtr)>(&mut self, marker_fn: F)
pub fn pos_marker(&mut self, marker_fn: impl Fn(CodePtr) + 'static) {
self.push_insn(Op::PosMarker, vec![], None, None, Some(Box::new(marker_fn)));
}
}
/// A struct that allows iterating through an assembler's instructions and
@ -898,134 +857,224 @@ impl fmt::Debug for Assembler {
}
}
macro_rules! def_push_jcc {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
pub fn $op_name(&mut self, target: Target)
{
self.push_insn($opcode, vec![], Some(target), None, None);
}
}
};
}
macro_rules! def_push_0_opnd {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
impl Assembler {
#[must_use]
pub fn $op_name(&mut self) -> Opnd
{
self.push_insn($opcode, vec![], None, None, None)
}
}
};
pub fn add(&mut self, left: Opnd, right: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Add, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None })
}
macro_rules! def_push_0_opnd_no_out {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
pub fn $op_name(&mut self)
{
self.push_insn($opcode, vec![], None, None, None);
}
}
};
}
macro_rules! def_push_1_opnd {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
#[must_use]
pub fn $op_name(&mut self, opnd0: Opnd) -> Opnd
{
self.push_insn($opcode, vec![opnd0], None, None, None)
}
}
};
pub fn and(&mut self, left: Opnd, right: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::And, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None })
}
macro_rules! def_push_1_opnd_no_out {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
pub fn $op_name(&mut self, opnd0: Opnd)
{
self.push_insn($opcode, vec![opnd0], None, None, None);
}
}
};
pub fn bake_string(&mut self, text: &str) {
self.push_insn(Insn { op: Op::BakeString, opnds: vec![], out: Opnd::None, text: Some(text.to_string()), target: None, pos_marker: None });
}
pub fn breakpoint(&mut self) {
self.push_insn(Insn { op: Op::Breakpoint, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None });
}
macro_rules! def_push_2_opnd {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
#[must_use]
pub fn $op_name(&mut self, opnd0: Opnd, opnd1: Opnd) -> Opnd
{
self.push_insn($opcode, vec![opnd0, opnd1], None, None, None)
}
}
};
pub fn ccall(&mut self, fptr: *const u8, opnds: Vec<Opnd>) -> Opnd {
self.push_insn(Insn { op: Op::CCall, opnds, out: Opnd::None, text: None, target: Some(Target::FunPtr(fptr)), pos_marker: None })
}
macro_rules! def_push_2_opnd_no_out {
($op_name:ident, $opcode:expr) => {
impl Assembler
{
pub fn $op_name(&mut self, opnd0: Opnd, opnd1: Opnd)
{
self.push_insn($opcode, vec![opnd0, opnd1], None, None, None);
}
}
};
pub fn cmp(&mut self, left: Opnd, right: Opnd) {
self.push_insn(Insn { op: Op::Cmp, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None });
}
def_push_1_opnd_no_out!(jmp_opnd, Op::JmpOpnd);
def_push_jcc!(jmp, Op::Jmp);
def_push_jcc!(je, Op::Je);
def_push_jcc!(jne, Op::Jne);
def_push_jcc!(jl, Op::Jl);
def_push_jcc!(jbe, Op::Jbe);
def_push_jcc!(jz, Op::Jz);
def_push_jcc!(jnz, Op::Jnz);
def_push_jcc!(jo, Op::Jo);
def_push_2_opnd!(add, Op::Add);
def_push_2_opnd!(sub, Op::Sub);
def_push_2_opnd!(and, Op::And);
def_push_2_opnd!(or, Op::Or);
def_push_2_opnd!(xor, Op::Xor);
def_push_1_opnd!(not, Op::Not);
def_push_2_opnd!(lshift, Op::LShift);
def_push_2_opnd!(rshift, Op::RShift);
def_push_2_opnd!(urshift, Op::URShift);
def_push_1_opnd_no_out!(cpush, Op::CPush);
def_push_0_opnd!(cpop, Op::CPop);
def_push_1_opnd_no_out!(cpop_into, Op::CPopInto);
def_push_0_opnd_no_out!(cpush_all, Op::CPushAll);
def_push_0_opnd_no_out!(cpop_all, Op::CPopAll);
def_push_1_opnd_no_out!(cret, Op::CRet);
def_push_1_opnd!(load, Op::Load);
def_push_1_opnd!(load_sext, Op::LoadSExt);
def_push_1_opnd!(lea, Op::Lea);
def_push_1_opnd!(live_reg_opnd, Op::LiveReg);
def_push_2_opnd_no_out!(store, Op::Store);
def_push_2_opnd_no_out!(mov, Op::Mov);
def_push_2_opnd_no_out!(cmp, Op::Cmp);
def_push_2_opnd_no_out!(test, Op::Test);
def_push_0_opnd_no_out!(breakpoint, Op::Breakpoint);
def_push_2_opnd_no_out!(incr_counter, Op::IncrCounter);
def_push_2_opnd!(csel_z, Op::CSelZ);
def_push_2_opnd!(csel_nz, Op::CSelNZ);
def_push_2_opnd!(csel_e, Op::CSelE);
def_push_2_opnd!(csel_ne, Op::CSelNE);
def_push_2_opnd!(csel_l, Op::CSelL);
def_push_2_opnd!(csel_le, Op::CSelLE);
def_push_2_opnd!(csel_g, Op::CSelG);
def_push_2_opnd!(csel_ge, Op::CSelGE);
def_push_0_opnd_no_out!(frame_setup, Op::FrameSetup);
def_push_0_opnd_no_out!(frame_teardown, Op::FrameTeardown);
pub fn comment(&mut self, text: &str) {
self.push_insn(Insn { op: Op::Comment, opnds: vec![], out: Opnd::None, text: Some(text.to_string()), target: None, pos_marker: None });
}
pub fn cpop(&mut self) -> Opnd {
self.push_insn(Insn { op: Op::CPop, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None })
}
pub fn cpop_all(&mut self) {
self.push_insn(Insn { op: Op::CPopAll, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn cpop_into(&mut self, opnd: Opnd) {
self.push_insn(Insn { op: Op::CPopInto, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn cpush(&mut self, opnd: Opnd) {
self.push_insn(Insn { op: Op::CPush, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn cpush_all(&mut self) {
self.push_insn(Insn { op: Op::CPushAll, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn cret(&mut self, opnd: Opnd) {
self.push_insn(Insn { op: Op::CRet, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None });
}
#[must_use]
pub fn csel_e(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelE, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_g(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelG, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_ge(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelGE, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_l(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelL, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_le(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelLE, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_ne(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelNE, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_nz(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelNZ, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn csel_z(&mut self, truthy: Opnd, falsy: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::CSelZ, opnds: vec![truthy, falsy], out: Opnd::None, text: None, target: None, pos_marker: None })
}
pub fn frame_setup(&mut self) {
self.push_insn(Insn { op: Op::FrameSetup, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn frame_teardown(&mut self) {
self.push_insn(Insn { op: Op::FrameTeardown, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn incr_counter(&mut self, mem: Opnd, value: Opnd) {
self.push_insn(Insn { op: Op::IncrCounter, opnds: vec![mem, value], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn jbe(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jbe, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn je(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Je, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jl(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jl, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jmp(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jmp, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jmp_opnd(&mut self, opnd: Opnd) {
self.push_insn(Insn { op: Op::JmpOpnd, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None });
}
pub fn jne(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jne, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jnz(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jnz, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jo(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jo, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
pub fn jz(&mut self, target: Target) {
self.push_insn(Insn { op: Op::Jz, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None });
}
#[must_use]
pub fn lea(&mut self, opnd: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Lea, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn lea_label(&mut self, target: Target) -> Opnd {
self.push_insn(Insn { op: Op::LeaLabel, opnds: vec![], out: Opnd::None, text: None, target: Some(target), pos_marker: None })
}
#[must_use]
pub fn live_reg_opnd(&mut self, opnd: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::LiveReg, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn load(&mut self, opnd: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Load, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn load_sext(&mut self, opnd: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::LoadSExt, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn lshift(&mut self, opnd: Opnd, shift: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::LShift, opnds: vec![opnd, shift], out: Opnd::None, text: None, target: None, pos_marker: None })
}
pub fn mov(&mut self, dest: Opnd, src: Opnd) {
self.push_insn(Insn { op: Op::Mov, opnds: vec![dest, src], out: Opnd::None, text: None, target: None, pos_marker: None });
}
#[must_use]
pub fn not(&mut self, opnd: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Not, opnds: vec![opnd], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn or(&mut self, left: Opnd, right: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Or, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None })
}
//pub fn pos_marker<F: FnMut(CodePtr)>(&mut self, marker_fn: F)
pub fn pos_marker(&mut self, marker_fn: impl Fn(CodePtr) + 'static) {
self.push_insn(Insn { op: Op::PosMarker, opnds: vec![], out: Opnd::None, text: None, target: None, pos_marker: Some(Box::new(marker_fn)) });
}
#[must_use]
pub fn rshift(&mut self, opnd: Opnd, shift: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::RShift, opnds: vec![opnd, shift], out: Opnd::None, text: None, target: None, pos_marker: None })
}
pub fn store(&mut self, dest: Opnd, src: Opnd) {
self.push_insn(Insn { op: Op::Store, opnds: vec![dest, src], out: Opnd::None, text: None, target: None, pos_marker: None });
}
#[must_use]
pub fn sub(&mut self, left: Opnd, right: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Sub, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None })
}
pub fn test(&mut self, left: Opnd, right: Opnd) {
self.push_insn(Insn { op: Op::Test, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None });
}
#[must_use]
pub fn urshift(&mut self, opnd: Opnd, shift: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::URShift, opnds: vec![opnd, shift], out: Opnd::None, text: None, target: None, pos_marker: None })
}
#[must_use]
pub fn xor(&mut self, left: Opnd, right: Opnd) -> Opnd {
self.push_insn(Insn { op: Op::Xor, opnds: vec![left, right], out: Opnd::None, text: None, target: None, pos_marker: None })
}
}

Просмотреть файл

@ -174,7 +174,7 @@ impl Assembler
_ => (opnds[0], opnds[1])
};
asm.push_insn(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
},
// These instructions modify their input operand in-place, so we
// may need to load the input value to preserve it
@ -195,7 +195,7 @@ impl Assembler
_ => (opnds[0], opnds[1])
};
asm.push_insn(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, vec![opnd0, opnd1], insn.target, insn.text, insn.pos_marker);
},
Op::CSelZ | Op::CSelNZ | Op::CSelE | Op::CSelNE |
Op::CSelL | Op::CSelLE | Op::CSelG | Op::CSelGE => {
@ -206,7 +206,7 @@ impl Assembler
}
}).collect();
asm.push_insn(insn.op, new_opnds, insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, new_opnds, insn.target, insn.text, insn.pos_marker);
},
Op::Mov => {
match (opnds[0], opnds[1]) {
@ -260,7 +260,7 @@ impl Assembler
asm.not(opnd0);
},
_ => {
asm.push_insn(insn.op, opnds, insn.target, insn.text, insn.pos_marker);
asm.push_insn_parts(insn.op, opnds, insn.target, insn.text, insn.pos_marker);
}
};