workaround for ADCS

This commit is contained in:
lifning 2021-10-27 01:39:01 -07:00
parent dde398ad5f
commit 573541bea7
1 changed files with 41 additions and 12 deletions

View File

@ -1,3 +1,5 @@
use std::mem::size_of;
use yaxpeax_arm::armv8::a64::{Opcode, Operand, SizeCode, ShiftStyle, Instruction};
use lightning_sys::{JitWord, JitState, Reg};
@ -5,13 +7,25 @@ use lightning_sys::{JitWord, JitState, Reg};
use crate::ext_lightning::{ExtJitState, OperandHelpers, ToLightning};
use crate::Result;
// baker's 32. need a spare for ARM's barrel shifter. (possibly more later)
const GP_REGS: usize = 33;
// baker's 32. need spares for:
// - ARM's barrel shifter
// - intermediate sum in ADCS so we can set status & carry simultaneously (glightning limitation)
// (possibly more later)
const TEMP_REGS: usize = 2;
const GP_REGS: usize = 32;
pub(crate) fn make_ext_jitstate<'a>(js: JitState<'a>) -> ExtJitState<'a> {
ExtJitState::new(js, GP_REGS)
// currently don't know how to support 64-bit data on 32-bit host in GNU Lightning
assert_eq!(size_of::<JitWord>(), size_of::<u64>());
ExtJitState::new(js, GP_REGS + TEMP_REGS)
}
const REG_BARREL_TMP: usize = 32; // index in array
// "register number" indeces above the last gp reg in the actual ISA
const REG_PSTATE: usize = GP_REGS; // TODO: how to most efficiently represent N/Z/C/V in glightning?
const REG_BARREL_TMP: usize = GP_REGS + 1;
const REG_CARRY_TMP: usize = GP_REGS + 2;
const REG_32_SRC1_TMP: usize = GP_REGS + 3;
const REG_32_SRC2_TMP: usize = GP_REGS + 4;
impl OperandHelpers for Operand {
fn reg_id(&self) -> Result<usize> {
@ -33,18 +47,33 @@ impl OperandHelpers for Operand {
}
}
// TODO: shift to set carry correctly for 32-bit?
// TODO: actually implement to the spec
// TODO: support (extended register)
fn add(ejs: &mut ExtJitState, operands: &[Operand; 4], carry: bool, status: bool) -> Result<()> {
let [dest_orig, src1_orig, src2_orig, _] = operands;
let mut add_reg: fn(&mut ExtJitState, Reg, Reg, Reg);
let mut add_imm: fn(&mut ExtJitState, Reg, Reg, JitWord);
add_reg = |ejs, dest, src1, src2| { ejs.addr(dest, src1, src2); };
add_imm = |ejs, dest, src1, src2| { ejs.addi(dest, src1, src2); };
if carry {
let add_reg: fn(&mut ExtJitState, Reg, Reg, Reg);
let add_imm: fn(&mut ExtJitState, Reg, Reg, JitWord);
if carry && status {
add_reg = |ejs, dest, src1, src2| {
let tmp = ejs.reg(REG_CARRY_TMP).unwrap();
ejs.addxi(tmp, src1, 0);
ejs.addcr(dest, tmp, src2);
};
add_imm = |ejs, dest, src1, src2| {
let tmp = ejs.reg(REG_CARRY_TMP).unwrap();
ejs.addxi(tmp, src1, 0);
ejs.addci(dest, tmp, src2);
};
} else if carry {
add_reg = |ejs, dest, src1, src2| { ejs.addxr(dest, src1, src2); };
add_imm = |ejs, dest, src1, src2| { ejs.addxi(dest, src1, src2); };
} else if status {
add_reg = |ejs, dest, src1, src2| { ejs.addcr(dest, src1, src2); };
add_imm = |ejs, dest, src1, src2| { ejs.addci(dest, src1, src2); };
}
if status {
todo!();
} else {
add_reg = |ejs, dest, src1, src2| { ejs.addr(dest, src1, src2); };
add_imm = |ejs, dest, src1, src2| { ejs.addi(dest, src1, src2); };
}
let src1 = ejs.reg(src1_orig.reg_id()?)?;
// we decode dest last for correctness in super-scarce register situations where