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)]
pub enum Instruction {
Add (u8, u8, u8),
AddI (u8, u8, i8),
Call (u8, u8, u8),
Closure (u8, u32),
Div (u8, u8, u8),
EqI (u8, i8, bool),
// Equals Constant?
@ -51,6 +54,8 @@ pub enum Instruction {
// MetaMethod, Binary
MmBin (u8, u8, u8),
MmBinI (u8, i8, u8, bool),
MmBinK (u8, u8, u8, bool),
ModK (u8, u8, u8),
@ -59,6 +64,8 @@ pub enum Instruction {
Mul (u8, u8, u8),
MulK (u8, u8, u8),
NewTable (u8),
Not (u8, u8),
@ -79,9 +86,13 @@ pub enum Instruction {
SetTabUp (u8, u8, u8),
Sub (u8, u8, u8),
TailCall (u8, u8, u8, bool),
Test (u8, bool),
UnM (u8, u8),
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 ()
}
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>
{
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),
0x12 => Inst::SetField (a, b, c, k),
0x13 => Inst::NewTable (a),
0x15 => Inst::AddI (a, b, i_sc (buf)?),
0x18 => Inst::MulK (a, b, c),
0x19 => Inst::ModK (a, b, c),
0x22 => Inst::Add (a, b, c),
0x23 => Inst::Sub (a, b, c),
0x24 => Inst::Mul (a, b, c),
0x27 => Inst::Div (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),
0x31 => Inst::UnM (a, b),
0x33 => Inst::Not (a, b),
0x34 => Inst::Len (a, b),
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 (); // 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);
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
// 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 {
parse_byte (rdr).unwrap ();
}
// Absolute line info, didn't see that in my test files
let abslineinfo_count = parse_int (rdr).unwrap ();
assert_eq! (abslineinfo_count, 0);
let local_count = parse_int (rdr).unwrap ();
for _ in 0..local_count {
parse_string(rdr).unwrap ();
parse_int (rdr).unwrap ();
parse_int (rdr).unwrap ();
let abslineinfo_count = load_size (rdr);
for _ in 0..abslineinfo_count {
load_unsigned (rdr, usize::MAX);
load_unsigned (rdr, usize::MAX);
}
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 {
parse_string (rdr).unwrap ();
}

View File

@ -178,6 +178,20 @@ impl <'a> State <'a> {
*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) => {
let b = usize::from (*b);
@ -269,6 +283,22 @@ impl <'a> State <'a> {
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) => {
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) => {
let t = match self.reg (*b) {
Value::Nil => panic! ("R[B] must not be nil"),
Value::Table (t) => t,
_ => 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:?}");
}
},
Instruction::MmBinI (_a, _s_b, _c, _k) => {
// Ignore
},
Instruction::MmBinK (_a, _b, _c, _k) => {
// Ignore
},
@ -465,6 +499,22 @@ impl <'a> State <'a> {
*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) => {
*self.reg_mut (*a) = Value::Table (Default::default ());
},
@ -603,6 +653,22 @@ impl <'a> State <'a> {
}
},
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) => {
assert! (!k, "closing over values in tail calls not implemented");
@ -638,6 +704,20 @@ impl <'a> State <'a> {
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 (_) => (),
}

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")