Compare commits

...

8 Commits

Author SHA1 Message Date
_ d0f9014f03 📝 doc: improve error message 2023-09-30 10:09:37 -05:00
_ ae858ebe70 🐛 bug: patch loader 2023-09-30 10:08:13 -05:00
_ 46cf5837bc 🐛 bug: impl opcodes 2023-09-30 10:05:07 -05:00
_ e59dd85246 🐛 bug: impl opcodes 2023-09-30 10:01:30 -05:00
_ 1943f0a40b 🐛 bug: impl OP_ADDI 2023-09-30 09:57:51 -05:00
_ 81743108c3 🐛 bug: implement OP_MULK 2023-09-30 09:52:42 -05:00
_ 64384e7ca5 🐛 bug: fix loader using the old broken `parse_int` for instruction count 2023-09-30 09:49:36 -05:00
_ 9bfd3c64c3 tests: add failing benchmark
It doesn't even want to load the bytecode lol
2023-09-30 09:48:02 -05:00
4 changed files with 239 additions and 11 deletions

View File

@ -1,10 +1,13 @@
#[derive (Debug, PartialEq)] #[derive (Debug, PartialEq)]
pub enum Instruction { pub enum Instruction {
Add (u8, u8, u8), Add (u8, u8, u8),
AddI (u8, u8, i8),
Call (u8, u8, u8), Call (u8, u8, u8),
Closure (u8, u32), Closure (u8, u32),
Div (u8, u8, u8),
EqI (u8, i8, bool), EqI (u8, i8, bool),
// Equals Constant? // Equals Constant?
@ -51,6 +54,8 @@ pub enum Instruction {
// MetaMethod, Binary // MetaMethod, Binary
MmBin (u8, u8, u8), MmBin (u8, u8, u8),
MmBinI (u8, i8, u8, bool),
MmBinK (u8, u8, u8, bool), MmBinK (u8, u8, u8, bool),
ModK (u8, u8, u8), ModK (u8, u8, u8),
@ -59,6 +64,8 @@ pub enum Instruction {
Mul (u8, u8, u8), Mul (u8, u8, u8),
MulK (u8, u8, u8),
NewTable (u8), NewTable (u8),
Not (u8, u8), Not (u8, u8),
@ -79,9 +86,13 @@ pub enum Instruction {
SetTabUp (u8, u8, u8), SetTabUp (u8, u8, u8),
Sub (u8, u8, u8),
TailCall (u8, u8, u8, bool), TailCall (u8, u8, u8, bool),
Test (u8, bool), Test (u8, bool),
UnM (u8, u8),
VarArgPrep (i32), VarArgPrep (i32),
} }

View File

@ -71,6 +71,11 @@ fn i_sb (buf: [u8; 4]) -> Option <i8> {
i8::try_from (i32::try_from (b).ok ()? - 127).ok () i8::try_from (i32::try_from (b).ok ()? - 127).ok ()
} }
fn i_sc (buf: [u8; 4]) -> Option <i8> {
let c = buf [3];
i8::try_from (i32::try_from (c).ok ()? - 127).ok ()
}
pub fn parse_inst (buf: [u8; 4]) -> Option <Inst> pub fn parse_inst (buf: [u8; 4]) -> Option <Inst>
{ {
let opcode = buf [0] & 0x7f; let opcode = buf [0] & 0x7f;
@ -104,11 +109,17 @@ pub fn parse_inst (buf: [u8; 4]) -> Option <Inst>
0x11 => Inst::SetI (a, b, c, k), 0x11 => Inst::SetI (a, b, c, k),
0x12 => Inst::SetField (a, b, c, k), 0x12 => Inst::SetField (a, b, c, k),
0x13 => Inst::NewTable (a), 0x13 => Inst::NewTable (a),
0x15 => Inst::AddI (a, b, i_sc (buf)?),
0x18 => Inst::MulK (a, b, c),
0x19 => Inst::ModK (a, b, c), 0x19 => Inst::ModK (a, b, c),
0x22 => Inst::Add (a, b, c), 0x22 => Inst::Add (a, b, c),
0x23 => Inst::Sub (a, b, c),
0x24 => Inst::Mul (a, b, c), 0x24 => Inst::Mul (a, b, c),
0x27 => Inst::Div (a, b, c),
0x2e => Inst::MmBin (a, b, c), 0x2e => Inst::MmBin (a, b, c),
0x2f => Inst::MmBinI (a, i_sb (buf)?, c, k),
0x30 => Inst::MmBinK (a, b, c, k), 0x30 => Inst::MmBinK (a, b, c, k),
0x31 => Inst::UnM (a, b),
0x33 => Inst::Not (a, b), 0x33 => Inst::Not (a, b),
0x34 => Inst::Len (a, b), 0x34 => Inst::Len (a, b),
0x3c => Inst::EqK (a, b, k), 0x3c => Inst::EqK (a, b, k),
@ -219,7 +230,7 @@ pub fn parse_block <R: Read> (rdr: &mut R, blocks: &mut Vec <Block>)
parse_byte (rdr).unwrap (); // is_vararg parse_byte (rdr).unwrap (); // is_vararg
parse_byte (rdr).unwrap (); // maxstacksize, might be same as num slots? parse_byte (rdr).unwrap (); // maxstacksize, might be same as num slots?
let inst_count = parse_int (rdr).unwrap (); let inst_count = load_size (rdr);
let mut instructions = Vec::with_capacity (inst_count as usize); let mut instructions = Vec::with_capacity (inst_count as usize);
for _ in 0..inst_count { for _ in 0..inst_count {
@ -285,24 +296,27 @@ pub fn parse_block <R: Read> (rdr: &mut R, blocks: &mut Vec <Block>)
// I think this is delta line numbers, e.g. most instructions // I think this is delta line numbers, e.g. most instructions
// have 0, but when you go to a new source line it's 1+. // have 0, but when you go to a new source line it's 1+.
let lineinfo_count = parse_int (rdr).unwrap (); let lineinfo_count = load_size (rdr);
for _ in 0..lineinfo_count { for _ in 0..lineinfo_count {
parse_byte (rdr).unwrap (); parse_byte (rdr).unwrap ();
} }
// Absolute line info, didn't see that in my test files // Absolute line info, didn't see that in my test files
let abslineinfo_count = parse_int (rdr).unwrap (); let abslineinfo_count = load_size (rdr);
assert_eq! (abslineinfo_count, 0); for _ in 0..abslineinfo_count {
load_unsigned (rdr, usize::MAX);
let local_count = parse_int (rdr).unwrap (); load_unsigned (rdr, usize::MAX);
for _ in 0..local_count {
parse_string(rdr).unwrap ();
parse_int (rdr).unwrap ();
parse_int (rdr).unwrap ();
} }
let upvalue_count = parse_int (rdr).unwrap (); let local_count = load_size (rdr);
for _ in 0..local_count {
parse_string(rdr);
load_unsigned (rdr, usize::MAX);
load_unsigned (rdr, usize::MAX);
}
let upvalue_count = load_size (rdr);
for _ in 0..upvalue_count { for _ in 0..upvalue_count {
parse_string (rdr).unwrap (); parse_string (rdr).unwrap ();
} }

View File

@ -178,6 +178,20 @@ impl <'a> State <'a> {
*self.reg_mut (*a) = x; *self.reg_mut (*a) = x;
}, },
Instruction::AddI (a, b, s_c) => {
let v_b = self.reg (*b);
let x = if let Some (v_b) = v_b.as_int ()
{
Value::from (v_b + *s_c as i64)
}
else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
Value::from (v_b + f64::from (*s_c))
};
*self.reg_mut (*a) = x;
},
Instruction::Call (a, b, _c) => { Instruction::Call (a, b, _c) => {
let b = usize::from (*b); let b = usize::from (*b);
@ -269,6 +283,22 @@ impl <'a> State <'a> {
upvalues: new_upvalues, upvalues: new_upvalues,
}); });
}, },
Instruction::Div (a, b, c) => {
let v_b = self.reg (*b);
let v_c = self.reg (*c);
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
{
Value::from (v_b / v_c)
}
else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
let v_c = v_c.as_float ().unwrap_or_else (|| panic! ("{v_c}"));
Value::from (v_b / v_c)
};
*self.reg_mut (*a) = x;
},
Instruction::EqI (a, sb, k_flag) => { Instruction::EqI (a, sb, k_flag) => {
if (self.reg (*a).as_int ().unwrap () == *sb as i64) != *k_flag if (self.reg (*a).as_int ().unwrap () == *sb as i64) != *k_flag
{ {
@ -311,6 +341,7 @@ impl <'a> State <'a> {
}, },
Instruction::GetField (a, b, c) => { Instruction::GetField (a, b, c) => {
let t = match self.reg (*b) { let t = match self.reg (*b) {
Value::Nil => panic! ("R[B] must not be nil"),
Value::Table (t) => t, Value::Table (t) => t,
_ => panic! ("R[B] must be a table"), _ => panic! ("R[B] must be a table"),
}; };
@ -434,6 +465,9 @@ impl <'a> State <'a> {
panic! ("Not sure how to implememtn OP_MMBIN for these 2 values {a:?}, {b:?}"); panic! ("Not sure how to implememtn OP_MMBIN for these 2 values {a:?}, {b:?}");
} }
}, },
Instruction::MmBinI (_a, _s_b, _c, _k) => {
// Ignore
},
Instruction::MmBinK (_a, _b, _c, _k) => { Instruction::MmBinK (_a, _b, _c, _k) => {
// Ignore // Ignore
}, },
@ -465,6 +499,22 @@ impl <'a> State <'a> {
*self.reg_mut (*a) = x; *self.reg_mut (*a) = x;
}, },
Instruction::MulK (a, b, c) => {
let v_b = self.reg (*b);
let v_c = &k [usize::from (*c)];
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
{
Value::from (v_b * v_c)
}
else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
let v_c = v_c.as_float ().unwrap_or_else (|| panic! ("{v_c}"));
Value::from (v_b * v_c)
};
*self.reg_mut (*a) = x;
},
Instruction::NewTable (a) => { Instruction::NewTable (a) => {
*self.reg_mut (*a) = Value::Table (Default::default ()); *self.reg_mut (*a) = Value::Table (Default::default ());
}, },
@ -603,6 +653,22 @@ impl <'a> State <'a> {
} }
}, },
Instruction::SetTabUp (_a, _b, _c) => unimplemented! (), Instruction::SetTabUp (_a, _b, _c) => unimplemented! (),
Instruction::Sub (a, b, c) => {
let v_b = self.reg (*b);
let v_c = self.reg (*c);
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
{
Value::from (v_b - v_c)
}
else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
let v_c = v_c.as_float ().unwrap_or_else (|| panic! ("{v_c}"));
Value::from (v_b - v_c)
};
*self.reg_mut (*a) = x;
},
Instruction::TailCall (a, b, _c, k) => { Instruction::TailCall (a, b, _c, k) => {
assert! (!k, "closing over values in tail calls not implemented"); assert! (!k, "closing over values in tail calls not implemented");
@ -638,6 +704,20 @@ impl <'a> State <'a> {
next_pc += 1; next_pc += 1;
} }
}, },
Instruction::UnM (a, b) => {
let v_b = self.reg (*b);
let x = if let Some (v_b) = v_b.as_int ()
{
Value::from (-v_b)
}
else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}"));
Value::from (-v_b)
};
*self.reg_mut (*a) = x;
},
Instruction::VarArgPrep (_) => (), Instruction::VarArgPrep (_) => (),
} }

123
test_vectors/n_body.lua Normal file
View File

@ -0,0 +1,123 @@
-- The Computer Language Benchmarks Game
-- https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
-- contributed by Mike Pall
-- modified by Geoff Leyland
local sqrt = math.sqrt
local PI = 3.141592653589793
local SOLAR_MASS = 4 * PI * PI
local DAYS_PER_YEAR = 365.24
local bodies = {
{ -- Sun
x = 0,
y = 0,
z = 0,
vx = 0,
vy = 0,
vz = 0,
mass = SOLAR_MASS
},
{ -- Jupiter
x = 4.84143144246472090e+00,
y = -1.16032004402742839e+00,
z = -1.03622044471123109e-01,
vx = 1.66007664274403694e-03 * DAYS_PER_YEAR,
vy = 7.69901118419740425e-03 * DAYS_PER_YEAR,
vz = -6.90460016972063023e-05 * DAYS_PER_YEAR,
mass = 9.54791938424326609e-04 * SOLAR_MASS
},
{ -- Saturn
x = 8.34336671824457987e+00,
y = 4.12479856412430479e+00,
z = -4.03523417114321381e-01,
vx = -2.76742510726862411e-03 * DAYS_PER_YEAR,
vy = 4.99852801234917238e-03 * DAYS_PER_YEAR,
vz = 2.30417297573763929e-05 * DAYS_PER_YEAR,
mass = 2.85885980666130812e-04 * SOLAR_MASS
},
{ -- Uranus
x = 1.28943695621391310e+01,
y = -1.51111514016986312e+01,
z = -2.23307578892655734e-01,
vx = 2.96460137564761618e-03 * DAYS_PER_YEAR,
vy = 2.37847173959480950e-03 * DAYS_PER_YEAR,
vz = -2.96589568540237556e-05 * DAYS_PER_YEAR,
mass = 4.36624404335156298e-05 * SOLAR_MASS
},
{ -- Neptune
x = 1.53796971148509165e+01,
y = -2.59193146099879641e+01,
z = 1.79258772950371181e-01,
vx = 2.68067772490389322e-03 * DAYS_PER_YEAR,
vy = 1.62824170038242295e-03 * DAYS_PER_YEAR,
vz = -9.51592254519715870e-05 * DAYS_PER_YEAR,
mass = 5.15138902046611451e-05 * SOLAR_MASS
}
}
local function advance(bodies, nbody, dt)
for i=1,nbody do
local bi = bodies[i]
local bix, biy, biz, bimass = bi.x, bi.y, bi.z, bi.mass
local bivx, bivy, bivz = bi.vx, bi.vy, bi.vz
for j=i+1,nbody do
local bj = bodies[j]
local dx, dy, dz = bix-bj.x, biy-bj.y, biz-bj.z
local mag = sqrt(dx*dx + dy*dy + dz*dz)
mag = dt / (mag * mag * mag)
local bm = bj.mass*mag
bivx = bivx - (dx * bm)
bivy = bivy - (dy * bm)
bivz = bivz - (dz * bm)
bm = bimass*mag
bj.vx = bj.vx + (dx * bm)
bj.vy = bj.vy + (dy * bm)
bj.vz = bj.vz + (dz * bm)
end
bi.vx = bivx
bi.vy = bivy
bi.vz = bivz
bi.x = bix + dt * bivx
bi.y = biy + dt * bivy
bi.z = biz + dt * bivz
end
end
local function energy(bodies, nbody)
local e = 0
for i=1,nbody do
local bi = bodies[i]
local vx, vy, vz, bim = bi.vx, bi.vy, bi.vz, bi.mass
e = e + (0.5 * bim * (vx*vx + vy*vy + vz*vz))
for j=i+1,nbody do
local bj = bodies[j]
local dx, dy, dz = bi.x-bj.x, bi.y-bj.y, bi.z-bj.z
local distance = sqrt(dx*dx + dy*dy + dz*dz)
e = e - ((bim * bj.mass) / distance)
end
end
return e
end
local function offsetMomentum(b, nbody)
local px, py, pz = 0, 0, 0
for i=1,nbody do
local bi = b[i]
local bim = bi.mass
px = px + (bi.vx * bim)
py = py + (bi.vy * bim)
pz = pz + (bi.vz * bim)
end
b[1].vx = -px / SOLAR_MASS
b[1].vy = -py / SOLAR_MASS
b[1].vz = -pz / SOLAR_MASS
end
local N = tonumber(arg and arg[1]) or 1000
local nbody = #bodies
offsetMomentum(bodies, nbody)
io.write( string.format("%0.9f",energy(bodies, nbody)), "\n")
for i=1,N do advance(bodies, nbody, 0.01) end
io.write( string.format("%0.9f",energy(bodies, nbody)), "\n")