work
This commit is contained in:
+188
-8
@@ -1,14 +1,28 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
|
||||
use super::*;
|
||||
use crate::backend::{LibImport, LinkedProgram, SymImport, SymTable, Symbol};
|
||||
use util::*;
|
||||
use crate::backend::{Body, LibImport, LinkedProgram, SymImport, SymTable, Symbol, VarId};
|
||||
|
||||
pub struct Encoder<'a> {
|
||||
pub code: Code,
|
||||
pub sym_tab: SymTable<u64>,
|
||||
pub sym_refs: HashMap<Symbol, Vec<usize>>,
|
||||
pub program: &'a Program<X86_64>,
|
||||
pub vars: VarMap,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VarUse {
|
||||
pos: usize,
|
||||
reg: Option<Reg>,
|
||||
}
|
||||
pub type VarUses = HashMap<VarId, VecDeque<VarUse>>;
|
||||
pub type RegUses = [VecDeque<usize>; 16];
|
||||
|
||||
impl VarUse {
|
||||
pub fn min(self, other: Self) -> Self {
|
||||
if self.pos <= other.pos { self } else { other }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
||||
@@ -19,7 +33,14 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
||||
for f in &p.funcs {
|
||||
let addr = encoder.code.bytes.len();
|
||||
encoder.sym_tab.insert(f.sym, addr as u64);
|
||||
for instr in &f.instrs {
|
||||
let mut segments = Vec::new();
|
||||
calc_uses(&mut segments, &f.body);
|
||||
}
|
||||
|
||||
for f in &p.funcs {
|
||||
let addr = encoder.code.bytes.len();
|
||||
encoder.sym_tab.insert(f.sym, addr as u64);
|
||||
for instr in &f.body {
|
||||
encoder.compile_instr(instr)?;
|
||||
}
|
||||
}
|
||||
@@ -60,24 +81,183 @@ pub fn compile(p: &Program<X86_64>) -> Result<LinkedProgram<u64>, CompilerMsg> {
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SegUses {
|
||||
var: VarUses,
|
||||
reg: RegUses,
|
||||
}
|
||||
|
||||
pub fn calc_uses(segments: &mut Vec<SegUses>, body: &Body<X86_64>) -> (usize, usize) {
|
||||
let mut pos = 0;
|
||||
let seg_i = segments.len();
|
||||
segments.push(Default::default());
|
||||
let mut vars = VarUses::default();
|
||||
let mut regs = RegUses::default();
|
||||
let volatile = [
|
||||
rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15,
|
||||
]
|
||||
.map(|r| r.reg());
|
||||
macro_rules! push {
|
||||
($var:ident) => {
|
||||
push!($var, VarUse { pos: 0, reg: None })
|
||||
};
|
||||
($var:ident, $pos:expr) => {
|
||||
vars.entry($var.clone()).or_default().push_back(VarUse {
|
||||
pos: $pos.pos + pos,
|
||||
reg: $pos.reg,
|
||||
})
|
||||
};
|
||||
}
|
||||
for instr in body {
|
||||
match instr {
|
||||
BInstr::Set { dst, src: _ } => push!(dst),
|
||||
BInstr::Call { dst, f, args } => {
|
||||
push!(dst);
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
push!(arg);
|
||||
if i < 8 {
|
||||
regs[i].push_back(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
BInstr::Copy { dst, src } => {
|
||||
push!(dst);
|
||||
push!(src);
|
||||
}
|
||||
BInstr::Add { dst, src1, src2 } => {
|
||||
push!(dst);
|
||||
push!(src1);
|
||||
push!(src2);
|
||||
}
|
||||
BInstr::If { cond, then, else_ } => {
|
||||
push!(cond);
|
||||
pos += 1;
|
||||
let (seg_i1, len1) = calc_uses(segments, then);
|
||||
let (seg_i2, len2) = calc_uses(segments, else_);
|
||||
// insert closest usages
|
||||
for (var, poss1) in &segments[seg_i1].var {
|
||||
if let Some(poss2) = segments[seg_i2].var.get(var) {
|
||||
push!(var, poss1[0].min(poss2[0]));
|
||||
} else {
|
||||
push!(var, poss1[0]);
|
||||
}
|
||||
}
|
||||
for (var, poss2) in &segments[seg_i2].var {
|
||||
if !segments[seg_i1].var.contains_key(var) {
|
||||
push!(var, poss2[0]);
|
||||
}
|
||||
}
|
||||
pos += len1.max(len2);
|
||||
continue;
|
||||
}
|
||||
BInstr::Loop(instrs) => {
|
||||
let (seg_i2, len) = calc_uses(segments, instrs);
|
||||
// insert closest usages
|
||||
for (var, poss) in &segments[seg_i2].var {
|
||||
push!(var, poss[0]);
|
||||
}
|
||||
// during register allocation, want to insert the first use of each var
|
||||
// at len + use, because if it jumps back up, that will be the next
|
||||
// usage rather than if the loop exits; pad ensures there is room so
|
||||
// the insertions are always before the rest of the usages (after loop)
|
||||
let pad = (len * 2).saturating_sub(pos);
|
||||
pos += len + pad;
|
||||
continue;
|
||||
}
|
||||
BInstr::Break(var) => {
|
||||
if let Some(var) = var {
|
||||
push!(var);
|
||||
}
|
||||
}
|
||||
BInstr::Return(var) => {
|
||||
if let Some(var) = var {
|
||||
push!(var);
|
||||
}
|
||||
}
|
||||
BInstr::Asm(asm) => {
|
||||
for &(reg, var) in &asm.args {
|
||||
push!(
|
||||
var,
|
||||
VarUse {
|
||||
pos: 0,
|
||||
reg: Some(reg)
|
||||
}
|
||||
);
|
||||
regs[reg as usize].push_back(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
segments[seg_i].var = vars;
|
||||
segments[seg_i].reg = regs;
|
||||
return (seg_i, pos);
|
||||
}
|
||||
|
||||
type BInstr = crate::backend::Instr<X86_64>;
|
||||
impl<'a> Encoder<'a> {
|
||||
fn compile_instr(&mut self, instr: &BInstr) -> Result<(), CompilerMsg> {
|
||||
fn compile_instr(&mut self, instr: &BInstr) -> EncodeRes {
|
||||
match instr {
|
||||
BInstr::Asm(asm) => {
|
||||
self.code.extend(asm);
|
||||
}
|
||||
BInstr::Asm(asm) => self.asm(asm)?,
|
||||
_ => todo!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn asm(&mut self, asm: &Asm) -> EncodeRes {
|
||||
let mut used = HashSet::default();
|
||||
let mut vars = HashSet::default();
|
||||
for &instr in &asm.instrs {
|
||||
if let Some(regw) = instr.regw_set() {
|
||||
used.insert(regw.reg());
|
||||
}
|
||||
for var in instr.vars() {
|
||||
vars.insert(var);
|
||||
}
|
||||
}
|
||||
let overlap = used.intersection(&self.vars.active.values());
|
||||
for var in &vars {
|
||||
if let Some(reg) = self.vars.active.get(var)
|
||||
&& used.contains(reg)
|
||||
{}
|
||||
}
|
||||
for &instr in &asm.instrs {
|
||||
match instr {
|
||||
Instr::Mov { dst, src } => self.code.mov(dst, src)?,
|
||||
Instr::Push(rvmi) => todo!(),
|
||||
Instr::Pop(rvm) => todo!(),
|
||||
Instr::Lea { dst, src } => todo!(),
|
||||
Instr::Int(code) => self.code.int(code),
|
||||
Instr::Syscall => self.code.syscall(),
|
||||
Instr::Call(sym) => self.code.call(sym),
|
||||
Instr::CallAt(sym) => self.code.call_mem(sym),
|
||||
Instr::Ret => self.code.ret(),
|
||||
Instr::Add { dst, src } => todo!(),
|
||||
Instr::Sub { dst, src } => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(program: &'a Program<X86_64>) -> Self {
|
||||
Self {
|
||||
code: Code::default(),
|
||||
sym_tab: SymTable::new(program.sym_count()),
|
||||
sym_refs: Default::default(),
|
||||
vars: VarMap::default(),
|
||||
program,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VarMap {
|
||||
active: HashMap<VarId, Reg>,
|
||||
}
|
||||
|
||||
impl Default for VarMap {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
active: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use crate::backend::Symbol;
|
||||
|
||||
type ERes = Result<(), CompilerMsg>;
|
||||
pub type EncodeRes = Result<(), CompilerMsg>;
|
||||
|
||||
/// machine code
|
||||
#[derive(Default)]
|
||||
@@ -11,7 +11,7 @@ pub struct Code {
|
||||
}
|
||||
|
||||
impl Code {
|
||||
pub fn mov(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes {
|
||||
pub fn mov(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||
let src = src.into();
|
||||
match dst.kind() {
|
||||
RegMemKind::Reg(mut dst) => match src {
|
||||
@@ -92,7 +92,7 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push(&mut self, reg: impl Into<RegMemImm>) -> ERes {
|
||||
pub fn push(&mut self, reg: impl Into<RegMemImm>) -> EncodeRes {
|
||||
match reg.into() {
|
||||
RegMemImm::Reg(reg) => match reg.width() {
|
||||
Width::B64 => {
|
||||
@@ -120,7 +120,7 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self, reg: Reg) -> ERes {
|
||||
pub fn pop(&mut self, reg: RegW) -> EncodeRes {
|
||||
match reg.width() {
|
||||
Width::B64 | Width::B16 => (),
|
||||
_ => return Err("register must be 64 or 16 bit".into()),
|
||||
@@ -133,7 +133,7 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lea(&mut self, dst: Reg, sym: Symbol) -> ERes {
|
||||
pub fn lea(&mut self, dst: RegW, sym: Symbol) -> EncodeRes {
|
||||
self.rex(1, dst, 0, 0)?;
|
||||
self.bytes.push(0x8d);
|
||||
self.modrm(dst, sym);
|
||||
@@ -162,7 +162,7 @@ impl Code {
|
||||
self.bytes.push(0xc3);
|
||||
}
|
||||
|
||||
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> ERes {
|
||||
fn add_sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>, ext: u8) -> EncodeRes {
|
||||
match src.into() {
|
||||
RegMemImm::Reg(src) => {
|
||||
if src.width() != dst.width() {
|
||||
@@ -219,11 +219,11 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes {
|
||||
pub fn add(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||
self.add_sub(dst, src, 0)
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> ERes {
|
||||
pub fn sub(&mut self, dst: impl RegMem, src: impl Into<RegMemImm>) -> EncodeRes {
|
||||
self.add_sub(dst, src, 5)
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ impl Code {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) -> ERes {
|
||||
fn rex(&mut self, w: impl RexW, r: impl RexBit, x: u8, b: impl RexBit) -> EncodeRes {
|
||||
if r.req() && b.req_no() || r.req_no() && b.req() {
|
||||
return Err("registers incompatible (REX)".into());
|
||||
}
|
||||
|
||||
@@ -20,9 +20,15 @@ pub struct X86_64;
|
||||
|
||||
impl Arch for X86_64 {
|
||||
const NAME: &str = "x86_64";
|
||||
type Asm = Code;
|
||||
type Asm = Asm;
|
||||
type Addr = u64;
|
||||
type CallConv = CallConv;
|
||||
fn compile(p: &Program<Self>) -> Result<LinkedProgram<Self::Addr>, CompilerMsg> {
|
||||
compile(p)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallConv {
|
||||
volatile: Vec<Reg>,
|
||||
nonvolatile: Vec<Reg>,
|
||||
}
|
||||
|
||||
@@ -36,13 +36,13 @@ pub fn imms() -> impl Iterator<Item = i128> {
|
||||
IMMS.iter().cloned()
|
||||
}
|
||||
|
||||
pub fn regs() -> impl Iterator<Item = Reg> {
|
||||
Reg::IMPORTANT.iter().cloned()
|
||||
pub fn regs() -> impl Iterator<Item = RegW> {
|
||||
RegW::IMPORTANT.iter().cloned()
|
||||
}
|
||||
|
||||
pub fn mems() -> impl Iterator<Item = Mem> {
|
||||
gen move {
|
||||
for ® in Reg::IMPORTANT {
|
||||
for ® in RegW::IMPORTANT {
|
||||
for &disp in DISPS {
|
||||
for &width in WIDTHS {
|
||||
yield mem(reg, disp, width);
|
||||
|
||||
@@ -8,13 +8,13 @@ pub trait RegMem: RexBit + RexW + ModRMRM + Copy + MaybeMem {
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RegMemKind {
|
||||
Reg(Reg),
|
||||
Reg(RegW),
|
||||
Mem(Mem),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RegMemImm {
|
||||
Reg(Reg),
|
||||
Reg(RegW),
|
||||
Imm(Imm),
|
||||
Mem(Mem),
|
||||
}
|
||||
@@ -23,7 +23,7 @@ pub trait MaybeMem {
|
||||
fn mem(&self) -> Option<Mem>;
|
||||
}
|
||||
|
||||
impl RegMem for Reg {
|
||||
impl RegMem for RegW {
|
||||
fn width(&self) -> Width {
|
||||
self.width()
|
||||
}
|
||||
@@ -32,7 +32,7 @@ impl RegMem for Reg {
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeMem for Reg {
|
||||
impl MaybeMem for RegW {
|
||||
fn mem(&self) -> Option<Mem> {
|
||||
None
|
||||
}
|
||||
@@ -54,14 +54,14 @@ impl MaybeMem for Mem {
|
||||
}
|
||||
|
||||
// fromrot
|
||||
impl From<Reg> for RegMemImm {
|
||||
fn from(value: Reg) -> Self {
|
||||
impl From<RegW> for RegMemImm {
|
||||
fn from(value: RegW) -> Self {
|
||||
Self::Reg(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Reg> for RegMemKind {
|
||||
fn from(value: Reg) -> Self {
|
||||
impl From<RegW> for RegMemKind {
|
||||
fn from(value: RegW) -> Self {
|
||||
Self::Reg(value)
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ pub enum EffAddr {
|
||||
None,
|
||||
}
|
||||
|
||||
impl ModRMRM for Reg {
|
||||
impl ModRMRM for RegW {
|
||||
fn rm(&self) -> u8 {
|
||||
self.base()
|
||||
}
|
||||
@@ -171,7 +171,7 @@ impl ModRMReg for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
impl ModRMReg for Reg {
|
||||
impl ModRMReg for RegW {
|
||||
fn val(&self) -> u8 {
|
||||
self.base()
|
||||
}
|
||||
@@ -207,7 +207,7 @@ impl RexBit for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
impl RexBit for Reg {
|
||||
impl RexBit for RegW {
|
||||
fn rex(&self) -> bool {
|
||||
self.gt8()
|
||||
}
|
||||
@@ -238,7 +238,7 @@ impl RexW for Width {
|
||||
}
|
||||
}
|
||||
|
||||
impl RexW for Reg {
|
||||
impl RexW for RegW {
|
||||
fn rexw(&self) -> bool {
|
||||
self.width().rexw()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
use super::*;
|
||||
use crate::backend::{Symbol, VarId};
|
||||
|
||||
pub struct Asm {
|
||||
pub args: Vec<(Reg, VarId)>,
|
||||
pub instrs: Vec<Instr>,
|
||||
}
|
||||
|
||||
pub enum Instr {
|
||||
Mov { dst: Rvm, src: Rvmi },
|
||||
Push(Rvmi),
|
||||
Pop(Rvm),
|
||||
Lea { dst: Rv, src: Symbol },
|
||||
Int(u8),
|
||||
Syscall,
|
||||
Call(Symbol),
|
||||
CallAt(Symbol),
|
||||
Ret,
|
||||
Add { dst: Rvm, src: Rvmi },
|
||||
Sub { dst: Rvm, src: Rvmi },
|
||||
}
|
||||
|
||||
impl Instr {
|
||||
pub fn regw_set(&self) -> Option<RegW> {
|
||||
match self {
|
||||
Instr::Mov { dst, src: _ } => dst.reg(),
|
||||
Instr::Push(_) => None,
|
||||
Instr::Pop(dst) => dst.reg(),
|
||||
Instr::Lea { dst, src: _ } => dst.reg(),
|
||||
Instr::Int(_) => None,
|
||||
Instr::Syscall => None,
|
||||
Instr::Call(_) => None,
|
||||
Instr::CallAt(_) => None,
|
||||
Instr::Ret => None,
|
||||
Instr::Add { dst, src: _ } => dst.reg(),
|
||||
Instr::Sub { dst, src: _ } => dst.reg(),
|
||||
}
|
||||
}
|
||||
pub fn vars(&self) -> impl Iterator<Item = VarId> {
|
||||
let mut vars = (None, None);
|
||||
match self {
|
||||
Instr::Mov { dst, src } => vars = (dst.var(), src.var()),
|
||||
Instr::Push(src) => vars.0 = src.var(),
|
||||
Instr::Pop(dst) => vars.0 = dst.var(),
|
||||
Instr::Lea { dst, .. } => vars.0 = dst.var(),
|
||||
Instr::Int(_) => (),
|
||||
Instr::Syscall => (),
|
||||
Instr::Call(_) => (),
|
||||
Instr::CallAt(_) => (),
|
||||
Instr::Ret => (),
|
||||
Instr::Add { dst, src } => vars = (dst.var(), src.var()),
|
||||
Instr::Sub { dst, src } => vars = (dst.var(), src.var()),
|
||||
}
|
||||
vars.0.into_iter().chain(vars.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Rv {
|
||||
Reg(RegW),
|
||||
Var(VarId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Rvm {
|
||||
Reg(RegW),
|
||||
Var(VarId),
|
||||
Mem(Mem),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Rvmi {
|
||||
Reg(RegW),
|
||||
Var(VarId),
|
||||
Mem(Mem),
|
||||
Imm(Imm),
|
||||
}
|
||||
|
||||
impl Rv {
|
||||
pub fn reg(&self) -> Option<RegW> {
|
||||
if let &Self::Reg(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn var(&self) -> Option<VarId> {
|
||||
if let &Self::Var(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rvm {
|
||||
pub fn reg(&self) -> Option<RegW> {
|
||||
if let &Self::Reg(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn var(&self) -> Option<VarId> {
|
||||
if let &Self::Var(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rvmi {
|
||||
pub fn reg(&self) -> Option<RegW> {
|
||||
if let &Self::Reg(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn var(&self) -> Option<VarId> {
|
||||
if let &Self::Var(v) = self {
|
||||
Some(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ use super::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Mem {
|
||||
pub reg: Reg,
|
||||
pub reg: RegW,
|
||||
pub disp: i32,
|
||||
pub width: Width,
|
||||
}
|
||||
|
||||
pub fn mem(reg: Reg, disp: i32, width: Width) -> Mem {
|
||||
pub fn mem(reg: RegW, disp: i32, width: Width) -> Mem {
|
||||
Mem { reg, disp, width }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
mod arg;
|
||||
mod asm;
|
||||
mod imm;
|
||||
mod mem;
|
||||
mod reg;
|
||||
mod width;
|
||||
|
||||
pub use arg::*;
|
||||
pub use asm::*;
|
||||
pub use imm::*;
|
||||
pub use mem::*;
|
||||
pub use reg::*;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use super::Width;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub struct Reg {
|
||||
val: u8,
|
||||
pub struct RegW {
|
||||
reg: Reg,
|
||||
high: bool,
|
||||
width: Width,
|
||||
}
|
||||
|
||||
def_regs! {
|
||||
pub type Reg = u8;
|
||||
|
||||
def_regs! { RegW;
|
||||
0b0000 : rax eax ax al,
|
||||
0b0001 : rcx ecx cx cl !_,
|
||||
0b0010 : rdx edx dx dl,
|
||||
@@ -28,16 +30,20 @@ def_regs! {
|
||||
0b1111 : r15 r15d r15w r15b,
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
impl RegW {
|
||||
pub fn reg(&self) -> u8 {
|
||||
self.reg
|
||||
}
|
||||
|
||||
pub fn base(&self) -> u8 {
|
||||
self.val & 0b111
|
||||
self.reg & 0b111
|
||||
}
|
||||
/// checks if register is not one of the first 8 (0-7)
|
||||
pub fn gt8(&self) -> bool {
|
||||
self.val >= 0b1000
|
||||
self.reg >= 0b1000
|
||||
}
|
||||
pub fn gt4(&self) -> bool {
|
||||
self.val >= 0b0100
|
||||
self.reg >= 0b0100
|
||||
}
|
||||
|
||||
pub fn width(&self) -> Width {
|
||||
@@ -65,12 +71,12 @@ impl Reg {
|
||||
|| (self.gt4() && self.width == Width::B8 && !self.high)
|
||||
}
|
||||
|
||||
pub fn incompatible(&self, other: &Reg) -> bool {
|
||||
pub fn incompatible(&self, other: &RegW) -> bool {
|
||||
(self.requires_rex() && other.high) || (self.high && other.requires_rex())
|
||||
}
|
||||
|
||||
const fn new(val: u8, width: Width, high: bool) -> Self {
|
||||
Self { val, high, width }
|
||||
const fn new(reg: u8, width: Width, high: bool) -> Self {
|
||||
Self { reg, high, width }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,30 +123,30 @@ macro_rules! filter {
|
||||
use filter;
|
||||
|
||||
macro_rules! def_regs {
|
||||
($($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => {
|
||||
($reg:ident; $($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => {
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $B64: Reg = Reg::new($val, Width::B64, false);
|
||||
pub const $B64: $reg = $reg::new($val, Width::B64, false);
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $B32: Reg = Reg::new($val, Width::B32, false);
|
||||
pub const $B32: $reg = $reg::new($val, Width::B32, false);
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $B16: Reg = Reg::new($val, Width::B16, false);
|
||||
pub const $B16: $reg = $reg::new($val, Width::B16, false);
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $B8 : Reg = Reg::new($val, Width::B8 , false);
|
||||
pub const $B8 : $reg = $reg::new($val, Width::B8 , false);
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $B8H: Reg = Reg::new($val, Width::B8, true);
|
||||
pub const $B8H: $reg = $reg::new($val, Width::B8, true);
|
||||
)?
|
||||
)*
|
||||
|
||||
impl Reg {
|
||||
impl $reg {
|
||||
// #[cfg(test)]
|
||||
// pub const ALL: &[Reg] = &[
|
||||
// pub const ALL: &[$reg] = &[
|
||||
// $( $B64, $B32, $B16, $B8, $($B8H,)? )*
|
||||
// ];
|
||||
|
||||
#[cfg(test)]
|
||||
pub const IMPORTANT: &[Reg] = &
|
||||
pub const IMPORTANT: &[$reg] = &
|
||||
filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* )
|
||||
;
|
||||
|
||||
@@ -159,7 +165,7 @@ macro_rules! def_regs {
|
||||
})
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Reg {
|
||||
impl std::fmt::Display for $reg {
|
||||
#[allow(non_upper_case_globals)]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", match *self {
|
||||
|
||||
@@ -9,8 +9,8 @@ pub enum Width {
|
||||
B64 = 3,
|
||||
}
|
||||
|
||||
impl From<Reg> for Width {
|
||||
fn from(value: Reg) -> Self {
|
||||
impl From<RegW> for Width {
|
||||
fn from(value: RegW) -> Self {
|
||||
value.width()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user