Skip to content

Commit

Permalink
fixed some encoding issues
Browse files Browse the repository at this point in the history
  • Loading branch information
AjaniBilby committed Jun 9, 2024
1 parent c3e05b5 commit 0fb4337
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 92 deletions.
1 change: 0 additions & 1 deletion source/compiler/codegen/expression/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export function InlineClamp(ctx: Context, type: IntrinsicType, min: number | nul
}

const x = ctx.scope.register.allocate(type.bitcode);

if (min !== null) {
ctx.block.push(Instruction.local.tee(x.ref));
ctx.block.push(scope.const(min));
Expand Down
58 changes: 36 additions & 22 deletions source/compiler/codegen/expression/infix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,45 +130,59 @@ function CoerceToFloat(ctx: Context, type: IntrinsicType, goal: IntrinsicType) {
}

function CoerceToInt(ctx: Context, type: IntrinsicType, goal: IntrinsicType) {
// Is the value on the stack already in the right bitcode?
let corrected = false;

// Encoding conversions
if (type === f32) {
if (goal.bitcode === WasmTypes.Intrinsic.i32) {
if (goal.signed) ctx.block.push(Instruction.f32.convert_i32_s());
else ctx.block.push(Instruction.f32.convert_i32_u());
if (goal.signed) {
ctx.block.push(Instruction.f32.convert_i32_s());
type = i32;
} else {
ctx.block.push(Instruction.f32.convert_i32_u());
type = u32;
}
} else {
if (goal.signed) ctx.block.push(Instruction.f32.convert_i64_s());
else ctx.block.push(Instruction.f32.convert_i64_u());
if (goal.signed) {
ctx.block.push(Instruction.f32.convert_i64_s());
type = i64;
} else {
ctx.block.push(Instruction.f32.convert_i64_u());
type = u64;
}
}
corrected = true;
} else if (type === f64) {
if (goal.bitcode === WasmTypes.Intrinsic.i32) {
if (goal.signed) ctx.block.push(Instruction.f64.convert_i32_s());
else ctx.block.push(Instruction.f64.convert_i32_u());
if (goal.signed) {
ctx.block.push(Instruction.f64.convert_i32_s());
goal = i32;
} else {
ctx.block.push(Instruction.f64.convert_i32_u());
type = u32;
}
} else {
if (goal.signed) ctx.block.push(Instruction.f64.convert_i64_s());
else ctx.block.push(Instruction.f64.convert_i64_u());
if (goal.signed) {
ctx.block.push(Instruction.f64.convert_i64_s());
type = i64;
}
else {
ctx.block.push(Instruction.f64.convert_i64_u());
type = u64;
}
}
corrected = true;
} else {
corrected = type.bitcode === goal.bitcode;
}


// Bound the value to the correct size for the target
if (goal.effectiveSize() < type.effectiveSize()) {
const max = Math.pow(2, goal.effectiveSize());
const min = goal.signed
? Math.pow(2, goal.size-1)
if (goal.tciBitDepth() < type.tciBitDepth()) {
const max = Math.pow(2, goal.tciBitDepth()) + ( (goal.signed && type.signed) ? -1 : 0 );
const min = (goal.signed && type.signed)
? -Math.pow(2, goal.tciBitDepth())
: 0;
InlineClamp(ctx, type, min, max);
}

if (!corrected) {
if (goal === i32) {
if (type.signed) { /* how */ }
if (type.bitcode != goal.bitcode) {
if (goal.bitcode == WasmTypes.Intrinsic.i32) {
if (type.signed) ctx.block.push(Instruction.i32.warp_i64());
else ctx.block.push(Instruction.i32.warp_i64());
}
else {
Expand Down
6 changes: 3 additions & 3 deletions source/compiler/intrinsic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ export class IntrinsicType {
return this.bitcode;
}

effectiveSize() {
if (this.signed) return this.size - 1;
else return this.size;
tciBitDepth() {
if (this.signed) return this.size*8 - 1;
else return this.size*8;
}
}

Expand Down
12 changes: 7 additions & 5 deletions source/wasm/instruction/constant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions
import { EncodeF32, EncodeF64, EncodeI32, EncodeI64 } from "~/wasm/type.ts";
import { EncodeF32, EncodeF64, EncodeI32, EncodeI64, EncodeU32, EncodeU64 } from "~/wasm/type.ts";
import { LatentOffset, LatentValue, Byte } from "~/helper.ts";


Expand All @@ -25,22 +25,24 @@ export class Constant {
}

toBinary(): Byte[] {
const val = this.read();

switch (this.type) {
case Type.i32: return [
this.type,
...EncodeI32(this.read())
...(val < 0 ? EncodeI32(val) : EncodeU32(val))
];
case Type.i64: return [
this.type,
...EncodeI64(this.read())
...(val < 0 ? EncodeI64(val) : EncodeU64(val))
];
case Type.f32: return [
this.type,
...EncodeF32(this.read())
...EncodeF32(val)
];
case Type.f64: return [
this.type,
...EncodeF64(this.read())
...EncodeF64(val)
];
}

Expand Down
11 changes: 5 additions & 6 deletions source/wasm/instruction/numeric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ const wrapper = {
trunc_f64_s : () => i32trunc_f64_s,
trunc_f64_u : () => i32trunc_f64_u,

extend8_s : () => i32extend8_s,
extend16_s : () => i32extend16_s,
extend_8_s : () => i32extend8_s,
extend_16_s : () => i32extend16_s,
reinterpret_f32 : () => i32reinterpret_f32,
},
i64: {
Expand Down Expand Up @@ -228,6 +228,9 @@ const wrapper = {
rotl: () => i64rotl,
rotr: () => i64rotr,

extend_8_s: ()=> i64extend8_s,
extend_16_s: () => i64extend16_s,
extend_32_s: () => i64extend32_s,
extend_i32_s: () => i64extend_i32_s,
extend_i32_u: () => i64extend_i32_u,
trunc_f32_s: () => i64trunc_f32_s,
Expand All @@ -236,10 +239,6 @@ const wrapper = {
trunc_f64_u: () => i64trunc_f64_u,

reinterpret_f64: () => i64reinterpret_f64,

extend8_s: ()=> i64extend8_s,
extend16_s: () => i64extend16_s,
extend32_s: () => i64extend32_s,
},
f32: {
eq : () => f32eq ,
Expand Down
36 changes: 13 additions & 23 deletions source/wasm/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ export function EncodeLimitType(min: number, max?: number): Byte[] {


export function EncodeF32(val: number): Byte[] {
let buffer = new ArrayBuffer(4);
let view = new DataView(buffer);
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setFloat32(0, val, true);

return [...(new Uint8Array(buffer))];
}

export function EncodeF64(val: number): Byte[] {
let buffer = new ArrayBuffer(8);
let view = new DataView(buffer);
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setFloat64(0, val, true);

return [...(new Uint8Array(buffer))];
Expand All @@ -67,7 +67,7 @@ export function EncodeSignedLEB(val: number): Byte[] {
if (val % 1 !== 0)
throw new Error(`Requested u32 encode for non integer value ${val}`);

let result: Byte[] = [];
const result: Byte[] = [];

// LEB128 encoding: https://en.wikipedia.org/wiki/LEB128#Encode_signed_32-bit_integer
while (true) {
Expand All @@ -86,10 +86,8 @@ export function EncodeSignedLEB(val: number): Byte[] {
return result;
}
export function EncodeUnsignedLEB(val: number): Byte[] {
if (val % 1 !== 0)
throw new Error(`Requested u32 encode for non integer value ${val}`);
if (val < 0)
throw new Error(`Requested u32 encode for signed integer value ${val}`);
if (val % 1 !== 0) throw new Error(`Requested u32 encode for non integer value ${val}`);
if (val < 0) throw new Error(`Requested u32 encode for signed integer value ${val}`);

// LEB128 encoding: https://en.wikipedia.org/wiki/LEB128#Encode_unsigned_32-bit_integer
const result: Byte[] = [];
Expand All @@ -102,32 +100,24 @@ export function EncodeUnsignedLEB(val: number): Byte[] {
byte |= 0b10000000;
}
result.push(byte);
} while(val !== 0);
} while(val > 0);
return result;
}

export function EncodeU32(val: number) {
if (val > 2**32)
throw new Error(`Requested to encode an u32 with too large a number ${val}`);

// if (val > 2**32) throw new Error(`Requested to encode an u32 with too large a number ${val}`);
return EncodeUnsignedLEB(val);
}
export function EncodeI32(val: number) {
if (Math.abs(val) > 2**31)
throw new Error(`Requested to encode an i32 with too large a number ${val}`);

// if (Math.abs(val) > 2**31) throw new Error(`Requested to encode an i32 with too large a number ${val}`);
return EncodeSignedLEB(val);
}

export function EncodeU64(val: number) {
if (val > 2**64)
throw new Error(`Requested to encode an u64 with too large a number ${val}`);

// if (val > 2**64) throw new Error(`Requested to encode an u64 with too large a number ${val}`);
return EncodeUnsignedLEB(val);
}
export function EncodeI64(val: number) {
if (Math.abs(val) > 2**63)
throw new Error(`Requested to encode an i64 with too large a number ${val}`);

return EncodeUnsignedLEB(val);
// if (Math.abs(val) > 2**63) throw new Error(`Requested to encode an i64 with too large a number ${val}`);
return EncodeSignedLEB(val);
}
65 changes: 35 additions & 30 deletions tests/conversion.test.sa
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ fn maxI16(): i16 {
return 32_767;
}
fn maxU16(): u16 {
return 65535;
return 65_535;
}
fn maxU32(): u32 {
return 2_147_483_647;
return 4_294_967_295;
}
fn maxI32(): i32 {
return 4_294_967_295;
return 2_147_483_647;
}
fn maxI64(): i64 {
return 9_223_372_036_854_775_807;
Expand All @@ -23,42 +23,47 @@ fn maxU64(): u64 {
return 18_446_744_073_709_551_615;
}

// test "Constant Saturation" {
// let t = 300 as u8;
// Stop auto type cohersion
fn int(val: i64): i64 {
return val;
}

// if (300 as u8) != maxU8() { return false; };
// if (16 as u8) != 16 { return false; };
// if (200 as i8) != maxI8() { return false; };
// if (120 as i8) != 120 { return false; };
test "Constant Saturation" {
if (int(300) as u8) != maxU8() { return false; };
if (int(16) as u8) != 16 { return false; };
if (int(200) as i8) != maxI8() { return false; };
if (int(120) as i8) != 120 { return false; };


// if (66_000 as u16) != maxU16() { return false; };
// if (65_534 as u16) != 65_534 { return false; };
// if (34_767 as i16) != maxI16() { return false; };
// if (32_000 as i16) != 32_000 { return false; };
if (int(66_000) as u16) != maxU16() { return false; };
if (int(65_534) as u16) != 65_534 { return false; };
if (int(34_767) as i16) != maxI16() { return false; };
if (int(32_000) as i16) != 32_000 { return false; };

// if (300 as u32) != maxU32() { return false; };
// if (116 as u32) != 116 { return false; };
// if (200 as i32) != maxI32() { return false; };
// if (120 as i32) != 120 { return false; };
// Cannot do big integers (+31bits) because JS moment
// if (int(17179869184) as u32) != maxU32() { return false; };
// if (int(116) as u32) != 116 { return false; };
// if (int(17179869184) as i32) != maxI32() { return false; };
// if (int(120) as i32) != 120 { return false; };

// return true;
// }
return true;
}

// test "Runtime Saturation" {
// let bigInt = maxU64();
test "Runtime Saturation" {
let bigInt = maxU32();

// if (bigInt as u8) != maxU8() { return false; };
// if (bigInt as i8) != maxI8() { return false; };
if (bigInt as u8) != maxU8() { return false; };
if (bigInt as i8) != maxI8() { return false; };


// if (bigInt as u16) != maxU16() { return false; };
// if (bigInt as i16) != maxI16() { return false; };
if (bigInt as u16) != maxU16() { return false; };
if (bigInt as i16) != maxI16() { return false; };

// if (bigInt as u32) != maxU32() { return false; };
// if (bigInt as i32) != maxI32() { return false; };
if (bigInt as u32) != maxU32() { return false; };
if (bigInt as i32) != maxI32() { return false; };

// if (bigInt as i64) != maxI64() { return false; };
// Cannot do big integers (+31bits) because JS moment
// if (bigInt as i64) != maxI64() { return false; };

// return true;
// }
return true;
}
2 changes: 0 additions & 2 deletions tests/time.test.sa
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ fn main(): none {
return;
}

fish

// test "Valid Epoch" {
// let t = DateTimeFromUnix(0);
// if ( t.date.day != 0
Expand Down

0 comments on commit 0fb4337

Please sign in to comment.