From 3223f76f605944d69ea5915e750b66e092097d65 Mon Sep 17 00:00:00 2001 From: Valeria Date: Tue, 6 Oct 2020 00:28:18 +0200 Subject: [PATCH] feat: Add bultins: i32/i64/f32/f64.add/sub/mul (#1484) Co-authored-by: Max Graey --- NOTICE | 1 + src/builtins.ts | 397 +++++++++++++++++++++++ std/assembly/builtins.ts | 60 ++++ std/assembly/index.d.ts | 30 ++ tests/compiler/builtins.optimized.wat | 98 ++++-- tests/compiler/builtins.ts | 49 ++- tests/compiler/builtins.untouched.wat | 449 +++++++++++++++++++++++--- 7 files changed, 1004 insertions(+), 80 deletions(-) diff --git a/NOTICE b/NOTICE index 198b982544..31569de6a1 100644 --- a/NOTICE +++ b/NOTICE @@ -26,6 +26,7 @@ under the licensing terms detailed in LICENSE: * ncave <777696+ncave@users.noreply.github.com> * Andrew Davis * Maƫl Nison +* Valeria Viana Gusmao Portions of this software are derived from third-party works licensed under the following terms: diff --git a/src/builtins.ts b/src/builtins.ts index 7abdf6eb2e..eb6e4f60f6 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -141,6 +141,9 @@ export namespace BuiltinNames { export const isManaged = "~lib/builtins/isManaged"; export const isVoid = "~lib/builtins/isVoid"; + export const add = "~lib/builtins/add"; + export const sub = "~lib/builtins/sub"; + export const mul = "~lib/builtins/mul"; export const clz = "~lib/builtins/clz"; export const ctz = "~lib/builtins/ctz"; export const popcnt = "~lib/builtins/popcnt"; @@ -234,6 +237,19 @@ export namespace BuiltinNames { export const f32_trunc = "~lib/builtins/f32.trunc"; export const f64_trunc = "~lib/builtins/f64.trunc"; + export const i32_add = "~lib/builtins/i32.add"; + export const i64_add = "~lib/builtins/i64.add"; + export const f32_add = "~lib/builtins/f32.add"; + export const f64_add = "~lib/builtins/f64.add"; + export const i32_sub = "~lib/builtins/i32.sub"; + export const i64_sub = "~lib/builtins/i64.sub"; + export const f32_sub = "~lib/builtins/f32.sub"; + export const f64_sub = "~lib/builtins/f64.sub"; + export const i32_mul = "~lib/builtins/i32.mul"; + export const i64_mul = "~lib/builtins/i64.mul"; + export const f32_mul = "~lib/builtins/f32.mul"; + export const f64_mul = "~lib/builtins/f64.mul"; + export const i32_load8_s = "~lib/builtins/i32.load8_s"; export const i32_load8_u = "~lib/builtins/i32.load8_u"; export const i32_load16_s = "~lib/builtins/i32.load16_s"; @@ -2056,6 +2072,279 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.store, builtin_store); +// add(left: T, right: T) -> T +function builtin_add(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) + return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression( + left, + typeArguments[0], + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (type.isValue) { + let arg1: ExpressionRef; + if (!typeArguments && left.isNumericLiteral) { + // prefer right type + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.MUST_WRAP + ); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression( + left, + (type = compiler.currentType), + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + } else { + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.AddI32, arg0, arg1), + type + ); + } + case TypeKind.I32: + case TypeKind.U32: + { + op = BinaryOp.AddI32; + break; + } + case TypeKind.I64: + case TypeKind.U64: { + op = BinaryOp.AddI64; + break; + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32; + break; + } + case TypeKind.F32: { + op = BinaryOp.AddF32; + break; + } + case TypeKind.F64: { + op = BinaryOp.AddF64; + break; + } + } + if (op != -1) { + return module.binary(op, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, + "add", + type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.add, builtin_add); + +// sub(left: T, right: T) -> T +function builtin_sub(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) + return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression( + left, + typeArguments[0], + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (type.isValue) { + let arg1: ExpressionRef; + if (!typeArguments && left.isNumericLiteral) { + // prefer right type + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.MUST_WRAP + ); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression( + left, + (type = compiler.currentType), + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + } else { + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.SubI32, arg0, arg1), + type + ); + } + case TypeKind.I32: + case TypeKind.U32: + { + op = BinaryOp.SubI32; + break; + } + case TypeKind.I64: + case TypeKind.U64: { + op = BinaryOp.SubI64; + break; + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 ? BinaryOp.SubI64 : BinaryOp.SubI32; + break; + } + case TypeKind.F32: { + op = BinaryOp.SubF32; + break; + } + case TypeKind.F64: { + op = BinaryOp.SubF64; + break; + } + } + if (op != -1) { + return module.binary(op, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, + "sub", + type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.sub, builtin_sub); + +// mul(left: T, right: T) -> T +function builtin_mul(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if (checkTypeOptional(ctx, true) | checkArgsRequired(ctx, 2)) + return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression( + left, + typeArguments[0], + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (type.isValue) { + let arg1: ExpressionRef; + if (!typeArguments && left.isNumericLiteral) { + // prefer right type + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.MUST_WRAP + ); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression( + left, + (type = compiler.currentType), + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + } else { + arg1 = compiler.compileExpression( + operands[1], + type, + Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP + ); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.MulI32, arg0, arg1), + type + ); + } + case TypeKind.I32: + case TypeKind.U32: + { + op = BinaryOp.MulI32; + break; + } + case TypeKind.I64: + case TypeKind.U64: { + op = BinaryOp.MulI64; + break; + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + op = compiler.options.isWasm64 ? BinaryOp.MulI64 : BinaryOp.MulI32; + break; + } + case TypeKind.F32: { + op = BinaryOp.MulF32; + break; + } + case TypeKind.F64: { + op = BinaryOp.MulF64; + break; + } + } + if (op != -1) { + return module.binary(op, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, + "mul", + type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.mul, builtin_mul); + // === Atomics ================================================================================ // atomic.load(offset: usize, immOffset?: usize) -> T* @@ -5580,6 +5869,114 @@ function builtin_f64_trunc(ctx: BuiltinContext): ExpressionRef { } builtins.set(BuiltinNames.f64_trunc, builtin_f64_trunc); +// i32.add -> add +function builtin_i32_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_add(ctx); +} +builtins.set(BuiltinNames.i32_add, builtin_i32_add); + +// i64.add -> add +function builtin_i64_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_add(ctx); +} +builtins.set(BuiltinNames.i64_add, builtin_i64_add); + +// i32.sub -> sub +function builtin_i32_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_sub(ctx); +} +builtins.set(BuiltinNames.i32_sub, builtin_i32_sub); + +// i64.sub -> sub +function builtin_i64_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_sub(ctx); +} +builtins.set(BuiltinNames.i64_sub, builtin_i64_sub); + +// i32.mul -> mul +function builtin_i32_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_mul(ctx); +} +builtins.set(BuiltinNames.i32_mul, builtin_i32_mul); + +// i64.mul -> mul +function builtin_i64_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_mul(ctx); +} +builtins.set(BuiltinNames.i64_mul, builtin_i64_mul); + +// f32.add -> add +function builtin_f32_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_add(ctx); +} +builtins.set(BuiltinNames.f32_add, builtin_f32_add); + +// f64.add -> add +function builtin_f64_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_add(ctx); +} +builtins.set(BuiltinNames.f64_add, builtin_f64_add); + +// f32.sub -> sub +function builtin_f32_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_sub(ctx); +} +builtins.set(BuiltinNames.f32_sub, builtin_f32_sub); + +// f64.sub -> sub +function builtin_f64_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_sub(ctx); +} +builtins.set(BuiltinNames.f64_sub, builtin_f64_sub); + +// f32.mul -> mul +function builtin_f32_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_mul(ctx); +} +builtins.set(BuiltinNames.f32_mul, builtin_f32_mul); + +// f64.mul -> mul +function builtin_f64_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_mul(ctx); +} +builtins.set(BuiltinNames.f64_mul, builtin_f64_mul); + // i32.load8_s -> load function builtin_i32_load8_s(ctx: BuiltinContext): ExpressionRef { checkTypeAbsent(ctx); diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index 1e33ddf7db..0638f842cb 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -120,6 +120,18 @@ export declare function sqrt(value: T): T; @builtin export declare function trunc(value: T): T; +// @ts-ignore: decorator +@builtin +export declare function add(left: T, right: T): T; + +// @ts-ignore: decorator +@builtin +export declare function sub(left: T, right: T): T; + +// @ts-ignore: decorator +@builtin +export declare function mul(left: T, right: T): T; + // @ts-ignore: decorator @unsafe @builtin export declare function load(ptr: usize, immOffset?: usize, immAlign?: usize): T; @@ -290,6 +302,18 @@ export namespace i32 { @builtin export declare function popcnt(value: i32): i32; + // @ts-ignore: decorator + @builtin + export declare function add(left: i32, right:i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function sub(left: i32, right:i32): i32; + + // @ts-ignore: decorator + @builtin + export declare function mul(left: i32, right:i32): i32; + // @ts-ignore: decorator @builtin export declare function rotl(value: i32, shift: i32): i32; @@ -481,6 +505,18 @@ export namespace i64 { @builtin export declare function ctz(value: i64): i64; + // @ts-ignore: decorator + @builtin + export declare function add(left: i64, right:i64): i64; + + // @ts-ignore: decorator + @builtin + export declare function sub(left: i64, right:i64): i64; + + // @ts-ignore: decorator + @builtin + export declare function mul(left: i64, right:i64): i64; + // @ts-ignore: decorator @builtin export declare function load8_s(ptr: usize, immOffset?: usize, immAlign?: usize): i64; @@ -905,6 +941,18 @@ export namespace f32 { // @ts-ignore: decorator @builtin export declare function trunc(value: f32): f32; + + // @ts-ignore: decorator + @builtin + export declare function add(left: f32, right: f32): f32; + + // @ts-ignore: decorator + @builtin + export declare function sub(left: f32, right: f32): f32; + + // @ts-ignore: decorator + @builtin + export declare function mul(left: f32, right: f32): f32; } // @ts-ignore: decorator @@ -996,6 +1044,18 @@ export namespace f64 { // @ts-ignore: decorator @builtin export declare function trunc(value: f64): f64; + + // @ts-ignore: decorator + @builtin + export declare function add(left: f64, right: f64): f64; + + // @ts-ignore: decorator + @builtin + export declare function sub(left: f64, right: f64): f64; + + // @ts-ignore: decorator + @builtin + export declare function mul(left: f64, right: f64): f64; } // @ts-ignore: decorator diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index f281cfb769..3b7ed7f76a 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -119,6 +119,12 @@ declare function select(ifTrue: T, ifFalse: T, condition: bool): T; declare function sqrt(value: T): T; /** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */ declare function trunc(value: T): T; +/** Computes sum of two integers or floats. */ +declare function add(left: T, right: T): T; +/** Computes difference of two integers or floats. */ +declare function sub(left: T, right: T): T; +/** Computes product of two integers or floats. */ +declare function mul(left: T, right: T): T; /** Loads a value of the specified type from memory. Equivalent to dereferncing a pointer in other languages. */ declare function load(ptr: usize, immOffset?: usize, immAlign?: usize): T; /** Stores a value of the specified type to memory. Equivalent to dereferencing a pointer in other languages when assigning a value. */ @@ -276,6 +282,12 @@ declare namespace i32 { export function store16(ptr: usize, value: i32, immOffset?: usize, immAlign?: usize): void; /** Stores a 32-bit integer value to memory. */ export function store(ptr: usize, value: i32, immOffset?: usize, immAlign?: usize): void; + /** Computes sum of two 32-bit integers */ + export function add(left: i32, right: i32): i32; + /** Computes difference of two 32-bit integers */ + export function sub(left: i32, right: i32): i32; + /** Computes product of two 32-bit integers */ + export function mul(left: i32, right: i32): i32; /** Atomic 32-bit integer operations. */ export namespace atomic { /** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 32-bit integer. */ @@ -374,6 +386,12 @@ declare namespace i64 { export function store32(ptr: usize, value: i64, immOffset?: usize, immAlign?: usize): void; /** Stores a 64-bit integer value to memory. */ export function store(ptr: usize, value: i64, immOffset?: usize, immAlign?: usize): void; + /** Computes sum of two 64-bit integers */ + export function add(left: i64, right: i64): i64; + /** Computes difference of two 64-bit integers */ + export function sub(left: i64, right: i64): i64; + /** Computes product of two 64-bit integers */ + export function mul(left: i64, right: i64): i64; /** Atomic 64-bit integer operations. */ export namespace atomic { /** Atomically loads an 8-bit unsigned integer value from memory and returns it as a 64-bit integer. */ @@ -533,6 +551,12 @@ declare namespace f32 { export function load(ptr: usize, immOffset?: usize, immAlign?: usize): f32; /** Stores a 32-bit float to memory. */ export function store(ptr: usize, value: f32, immOffset?: usize, immAlign?: usize): void; + /** Computes sum of two 32-bit floats */ + export function add(left: f32, right: f32): f32; + /** Computes difference of two 32-bit floats */ + export function sub(left: f32, right: f32): f32; + /** Computes product of two 32-bit floats */ + export function mul(left: f32, right: f32): f32; } /** Converts any other numeric value to a 64-bit float. */ declare function f64(value: any): f64; @@ -559,6 +583,12 @@ declare namespace f64 { export function load(ptr: usize, immOffset?: usize, immAlign?: usize): f64; /** Stores a 64-bit float to memory. */ export function store(ptr: usize, value: f64, immOffset?: usize, immAlign?: usize): void; + /** Computes sum of two 64-bit floats */ + export function add(left: f64, right: f64): f64; + /** Computes difference of two 64-bit floats */ + export function sub(left: f64, right: f64): f64; + /** Computes product of two 64-bit floats */ + export function mul(left: f64, right: f64): f64; } /** Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants. */ declare function v128(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; diff --git a/tests/compiler/builtins.optimized.wat b/tests/compiler/builtins.optimized.wat index 1067470f8e..e522385f05 100644 --- a/tests/compiler/builtins.optimized.wat +++ b/tests/compiler/builtins.optimized.wat @@ -203,6 +203,12 @@ global.set $builtins/i i32.const 1 global.set $builtins/i + i32.const 3 + global.set $builtins/i + i32.const 1 + global.set $builtins/i + i32.const 6 + global.set $builtins/i i64.const 63 global.set $builtins/I i64.const 0 @@ -219,6 +225,12 @@ global.set $builtins/I i64.const 1 global.set $builtins/I + i64.const 3 + global.set $builtins/I + i64.const 1 + global.set $builtins/I + i64.const 6 + global.set $builtins/I f32.const nan:0x400000 global.set $builtins/f f32.const inf @@ -231,6 +243,12 @@ global.set $builtins/f f32.const 1 global.set $builtins/f + f32.const 4 + global.set $builtins/f + f32.const 1 + global.set $builtins/f + f32.const 3 + global.set $builtins/f f32.const 2.5 global.set $builtins/f f32.const 1.25 @@ -253,6 +271,12 @@ global.set $builtins/F f64.const 1 global.set $builtins/F + f64.const 4 + global.set $builtins/F + f64.const 1 + global.set $builtins/F + f64.const 3 + global.set $builtins/F f64.const 2.5 global.set $builtins/F f64.const 1.25 @@ -267,6 +291,18 @@ global.set $builtins/F f32.const 1 global.set $builtins/f + f64.const 1.5 + global.set $builtins/F + f32.const 1 + global.set $builtins/f + f64.const 1 + global.set $builtins/F + f32.const 1 + global.set $builtins/f + f64.const 2 + global.set $builtins/F + f32.const 2 + global.set $builtins/f i32.const 8 i32.load global.set $builtins/i @@ -467,7 +503,7 @@ if i32.const 0 i32.const 1088 - i32.const 265 + i32.const 294 i32.const 1 call $~lib/builtins/abort unreachable @@ -482,7 +518,7 @@ if i32.const 0 i32.const 1088 - i32.const 266 + i32.const 295 i32.const 1 call $~lib/builtins/abort unreachable @@ -494,7 +530,7 @@ if i32.const 0 i32.const 1088 - i32.const 267 + i32.const 296 i32.const 1 call $~lib/builtins/abort unreachable @@ -506,7 +542,7 @@ if i32.const 0 i32.const 1088 - i32.const 270 + i32.const 299 i32.const 1 call $~lib/builtins/abort unreachable @@ -585,7 +621,7 @@ if i32.const 0 i32.const 1088 - i32.const 432 + i32.const 475 i32.const 1 call $~lib/builtins/abort unreachable @@ -597,7 +633,7 @@ if i32.const 0 i32.const 1088 - i32.const 433 + i32.const 476 i32.const 1 call $~lib/builtins/abort unreachable @@ -609,7 +645,7 @@ if i32.const 0 i32.const 1088 - i32.const 434 + i32.const 477 i32.const 1 call $~lib/builtins/abort unreachable @@ -619,7 +655,7 @@ if i32.const 0 i32.const 1088 - i32.const 435 + i32.const 478 i32.const 1 call $~lib/builtins/abort unreachable @@ -631,7 +667,7 @@ if i32.const 0 i32.const 1088 - i32.const 436 + i32.const 479 i32.const 1 call $~lib/builtins/abort unreachable @@ -641,7 +677,7 @@ if i32.const 0 i32.const 1088 - i32.const 437 + i32.const 480 i32.const 1 call $~lib/builtins/abort unreachable @@ -651,7 +687,7 @@ if i32.const 0 i32.const 1088 - i32.const 438 + i32.const 481 i32.const 1 call $~lib/builtins/abort unreachable @@ -671,7 +707,7 @@ if i32.const 0 i32.const 1088 - i32.const 455 + i32.const 498 i32.const 3 call $~lib/builtins/abort unreachable @@ -683,7 +719,7 @@ if i32.const 0 i32.const 1088 - i32.const 456 + i32.const 499 i32.const 3 call $~lib/builtins/abort unreachable @@ -695,7 +731,7 @@ if i32.const 0 i32.const 1088 - i32.const 457 + i32.const 500 i32.const 3 call $~lib/builtins/abort unreachable @@ -707,7 +743,7 @@ if i32.const 0 i32.const 1088 - i32.const 458 + i32.const 501 i32.const 3 call $~lib/builtins/abort unreachable @@ -719,7 +755,7 @@ if i32.const 0 i32.const 1088 - i32.const 459 + i32.const 502 i32.const 3 call $~lib/builtins/abort unreachable @@ -731,7 +767,7 @@ if i32.const 0 i32.const 1088 - i32.const 460 + i32.const 503 i32.const 3 call $~lib/builtins/abort unreachable @@ -743,7 +779,7 @@ if i32.const 0 i32.const 1088 - i32.const 461 + i32.const 504 i32.const 3 call $~lib/builtins/abort unreachable @@ -755,7 +791,7 @@ if i32.const 0 i32.const 1088 - i32.const 462 + i32.const 505 i32.const 3 call $~lib/builtins/abort unreachable @@ -767,7 +803,7 @@ if i32.const 0 i32.const 1088 - i32.const 463 + i32.const 506 i32.const 3 call $~lib/builtins/abort unreachable @@ -779,7 +815,7 @@ if i32.const 0 i32.const 1088 - i32.const 464 + i32.const 507 i32.const 3 call $~lib/builtins/abort unreachable @@ -791,7 +827,7 @@ if i32.const 0 i32.const 1088 - i32.const 465 + i32.const 508 i32.const 3 call $~lib/builtins/abort unreachable @@ -803,7 +839,7 @@ if i32.const 0 i32.const 1088 - i32.const 466 + i32.const 509 i32.const 3 call $~lib/builtins/abort unreachable @@ -815,7 +851,7 @@ if i32.const 0 i32.const 1088 - i32.const 467 + i32.const 510 i32.const 3 call $~lib/builtins/abort unreachable @@ -827,7 +863,7 @@ if i32.const 0 i32.const 1088 - i32.const 468 + i32.const 511 i32.const 3 call $~lib/builtins/abort unreachable @@ -839,7 +875,7 @@ if i32.const 0 i32.const 1088 - i32.const 469 + i32.const 512 i32.const 3 call $~lib/builtins/abort unreachable @@ -851,7 +887,7 @@ if i32.const 0 i32.const 1088 - i32.const 470 + i32.const 513 i32.const 3 call $~lib/builtins/abort unreachable @@ -863,7 +899,7 @@ if i32.const 0 i32.const 1088 - i32.const 471 + i32.const 514 i32.const 3 call $~lib/builtins/abort unreachable @@ -875,7 +911,7 @@ if i32.const 0 i32.const 1088 - i32.const 472 + i32.const 515 i32.const 3 call $~lib/builtins/abort unreachable @@ -887,7 +923,7 @@ if i32.const 0 i32.const 1088 - i32.const 473 + i32.const 516 i32.const 3 call $~lib/builtins/abort unreachable @@ -899,7 +935,7 @@ if i32.const 0 i32.const 1088 - i32.const 474 + i32.const 517 i32.const 3 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/builtins.ts b/tests/compiler/builtins.ts index 5df24b334d..0f5217de42 100644 --- a/tests/compiler/builtins.ts +++ b/tests/compiler/builtins.ts @@ -46,6 +46,12 @@ assert(!isDefined(c)); assert(isConstant(1)); assert(!isConstant(b)); +// small integers +var l: i8; +l = add(1, 2); assert(l == 3); +l = sub(2, 1); assert(l == 1); +l = mul(1, 2); assert(l == 2); + // integers var i: i32; @@ -58,6 +64,9 @@ rotr(1, 1); abs(-42); max(1, 2); min(1, 2); +add(1, 2); +sub(2, 1); +mul(1, 2); i = clz(1); i = ctz(1); @@ -67,7 +76,9 @@ i = rotr(1, 1); i = abs(-42); assert(i == 42); i = max(1, 2); assert(i == 2); i = min(1, 2); assert(i == 1); - +i = add(1, 2); assert(i == 3); +i = sub(2, 1); assert(i == 1); +i = mul(2, 3); assert(i == 6); var I: i64; clz(1); @@ -84,7 +95,10 @@ I = rotl(1, 1); I = rotr(1, 1); I = abs(-42); assert(I == 42); I = max(1, 2); assert(I == 2); -I = min(1, 2); assert(i == 1); +I = min(1, 2); assert(I == 1); +I = add(1, 2); assert(I == 3); +I = sub(2, 1); assert(I == 1); +I = mul(2, 3); assert(I == 6); // floats @@ -114,7 +128,10 @@ f = abs(1.25); f = ceil(1.25); f = copysign(1.25, 2.5); f = floor(1.25); -f = max(1.25, 2.5); +f = add(1.5, 2.5); assert(f == 4.0); +f = sub(2.5, 1.5); assert(f == 1.0); +f = mul(1.5, 2.0); assert(f == 3.0); +f = max(1.25, 2.5); assert(f == 2.5); f = min(1.25, 2.5); f = nearest(1.25); f = sqrt(1.25); @@ -132,6 +149,9 @@ abs(1.25); ceil(1.25); copysign(1.25, 2.5); floor(1.25); +add(1.5, 2.5); +sub(2.5, 1.5); +mul(1.5, 2.0); max(1.25, 2.5); min(1.25, 2.5); nearest(1.25); @@ -150,6 +170,9 @@ F = abs(1.25); F = ceil(1.25); F = copysign(1.25, 2.5); F = floor(1.25); +F = add(1.5, 2.5); assert(F == 4.0); +F = sub(2.5, 1.5); assert(F == 1.0); +F = mul(1.5, 2.0); assert(F == 3.0); F = max(1.25, 2.5); F = min(1.25, 2.5); F = nearest(1.25); @@ -162,6 +185,12 @@ b = isFinite(1.25); F = min(0, 1.0); f = max(0, f); +F = add(0, 1.5); +f = add(0, f); +F = sub(2, 1.0); +f = sub(2, f); +F = mul(2, 1.0); +f = mul(2, f); // load and store @@ -381,6 +410,13 @@ f64.nearest(1.0); i32.popcnt(1); i64.popcnt(1); +i32.add(1, 2); +i64.add(1, 2); +i32.sub(2, 1); +i64.sub(2, 1); +i32.mul(2, 1); +i64.mul(2, 1); + i32.load8_s(8); i32.load8_u(8); i32.load16_s(8); @@ -396,6 +432,13 @@ i64.load(8); f32.load(8); f64.load(8); +f32.add(1.0, 2.0); +f64.add(1.0, 2.0); +f32.sub(2.0, 1.0); +f64.sub(2.0, 1.0); +f32.mul(1.0, 2.0); +f64.mul(1.0, 2.0); + f32.max(1.0, 2.0); f64.max(1.0, 2.0); diff --git a/tests/compiler/builtins.untouched.wat b/tests/compiler/builtins.untouched.wat index 9573100c47..481b988d19 100644 --- a/tests/compiler/builtins.untouched.wat +++ b/tests/compiler/builtins.untouched.wat @@ -39,6 +39,7 @@ (table $0 4 funcref) (elem (i32.const 1) $start:builtins~anonymous|0 $start:builtins~anonymous|1 $start:builtins~anonymous|2) (global $builtins/b (mut i32) (i32.const 0)) + (global $builtins/l (mut i32) (i32.const 0)) (global $builtins/i (mut i32) (i32.const 0)) (global $builtins/I (mut i64) (i64.const 0)) (global $builtins/f (mut f32) (f32.const 0)) @@ -444,6 +445,62 @@ i32.eqz drop i32.const 1 + i32.const 2 + i32.add + i32.const 24 + i32.shl + i32.const 24 + i32.shr_s + global.set $builtins/l + global.get $builtins/l + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 51 + i32.const 20 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + i32.const 1 + i32.sub + i32.const 24 + i32.shl + i32.const 24 + i32.shr_s + global.set $builtins/l + global.get $builtins/l + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 52 + i32.const 20 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + i32.const 2 + i32.mul + global.set $builtins/l + global.get $builtins/l + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 53 + i32.const 20 + call $~lib/builtins/abort + unreachable + end + i32.const 1 i32.clz drop i32.const 1 @@ -489,6 +546,18 @@ select drop i32.const 1 + i32.const 2 + i32.add + drop + i32.const 2 + i32.const 1 + i32.sub + drop + i32.const 1 + i32.const 2 + i32.mul + drop + i32.const 1 i32.clz global.set $builtins/i i32.const 1 @@ -522,7 +591,7 @@ if i32.const 0 i32.const 80 - i32.const 67 + i32.const 76 i32.const 20 call $~lib/builtins/abort unreachable @@ -543,7 +612,7 @@ if i32.const 0 i32.const 80 - i32.const 68 + i32.const 77 i32.const 21 call $~lib/builtins/abort unreachable @@ -564,7 +633,55 @@ if i32.const 0 i32.const 80 - i32.const 69 + i32.const 78 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i32.const 1 + i32.const 2 + i32.add + global.set $builtins/i + global.get $builtins/i + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 79 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + i32.const 1 + i32.sub + global.set $builtins/i + global.get $builtins/i + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 80 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i32.const 2 + i32.const 3 + i32.mul + global.set $builtins/i + global.get $builtins/i + i32.const 6 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 81 i32.const 21 call $~lib/builtins/abort unreachable @@ -630,7 +747,7 @@ if i32.const 0 i32.const 80 - i32.const 85 + i32.const 96 i32.const 20 call $~lib/builtins/abort unreachable @@ -651,7 +768,7 @@ if i32.const 0 i32.const 80 - i32.const 86 + i32.const 97 i32.const 21 call $~lib/builtins/abort unreachable @@ -665,14 +782,62 @@ i64.lt_s select global.set $builtins/I - global.get $builtins/i - i32.const 1 - i32.eq + global.get $builtins/I + i64.const 1 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 98 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i64.const 1 + i64.const 2 + i64.add + global.set $builtins/I + global.get $builtins/I + i64.const 3 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 99 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i64.const 2 + i64.const 1 + i64.sub + global.set $builtins/I + global.get $builtins/I + i64.const 1 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 100 + i32.const 21 + call $~lib/builtins/abort + unreachable + end + i64.const 2 + i64.const 3 + i64.mul + global.set $builtins/I + global.get $builtins/I + i64.const 6 + i64.eq i32.eqz if i32.const 0 i32.const 80 - i32.const 87 + i32.const 101 i32.const 21 call $~lib/builtins/abort unreachable @@ -779,10 +944,70 @@ f32.const 1.25 f32.floor global.set $builtins/f + f32.const 1.5 + f32.const 2.5 + f32.add + global.set $builtins/f + global.get $builtins/f + f32.const 4 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 131 + i32.const 25 + call $~lib/builtins/abort + unreachable + end + f32.const 2.5 + f32.const 1.5 + f32.sub + global.set $builtins/f + global.get $builtins/f + f32.const 1 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 132 + i32.const 25 + call $~lib/builtins/abort + unreachable + end + f32.const 1.5 + f32.const 2 + f32.mul + global.set $builtins/f + global.get $builtins/f + f32.const 3 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 133 + i32.const 25 + call $~lib/builtins/abort + unreachable + end f32.const 1.25 f32.const 2.5 f32.max global.set $builtins/f + global.get $builtins/f + f32.const 2.5 + f32.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 134 + i32.const 26 + call $~lib/builtins/abort + unreachable + end f32.const 1.25 f32.const 2.5 f32.min @@ -829,6 +1054,18 @@ f64.const 1.25 f64.floor drop + f64.const 1.5 + f64.const 2.5 + f64.add + drop + f64.const 2.5 + f64.const 1.5 + f64.sub + drop + f64.const 1.5 + f64.const 2 + f64.mul + drop f64.const 1.25 f64.const 2.5 f64.max @@ -914,6 +1151,54 @@ f64.const 1.25 f64.floor global.set $builtins/F + f64.const 1.5 + f64.const 2.5 + f64.add + global.set $builtins/F + global.get $builtins/F + f64.const 4 + f64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 173 + i32.const 25 + call $~lib/builtins/abort + unreachable + end + f64.const 2.5 + f64.const 1.5 + f64.sub + global.set $builtins/F + global.get $builtins/F + f64.const 1 + f64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 174 + i32.const 25 + call $~lib/builtins/abort + unreachable + end + f64.const 1.5 + f64.const 2 + f64.mul + global.set $builtins/F + global.get $builtins/F + f64.const 3 + f64.eq + i32.eqz + if + i32.const 0 + i32.const 80 + i32.const 175 + i32.const 25 + call $~lib/builtins/abort + unreachable + end f64.const 1.25 f64.const 2.5 f64.max @@ -951,6 +1236,30 @@ global.get $builtins/f f32.max global.set $builtins/f + f64.const 0 + f64.const 1.5 + f64.add + global.set $builtins/F + f32.const 0 + global.get $builtins/f + f32.add + global.set $builtins/f + f64.const 2 + f64.const 1 + f64.sub + global.set $builtins/F + f32.const 2 + global.get $builtins/f + f32.sub + global.set $builtins/f + f64.const 2 + f64.const 1 + f64.mul + global.set $builtins/F + f32.const 2 + global.get $builtins/f + f32.mul + global.set $builtins/f i32.const 8 i32.load global.set $builtins/i @@ -1208,7 +1517,7 @@ if i32.const 0 i32.const 80 - i32.const 265 + i32.const 294 i32.const 1 call $~lib/builtins/abort unreachable @@ -1224,7 +1533,7 @@ if i32.const 0 i32.const 80 - i32.const 266 + i32.const 295 i32.const 1 call $~lib/builtins/abort unreachable @@ -1238,7 +1547,7 @@ if i32.const 0 i32.const 80 - i32.const 267 + i32.const 296 i32.const 1 call $~lib/builtins/abort unreachable @@ -1251,7 +1560,7 @@ if i32.const 0 i32.const 80 - i32.const 268 + i32.const 297 i32.const 1 call $~lib/builtins/abort unreachable @@ -1264,7 +1573,7 @@ if i32.const 0 i32.const 80 - i32.const 269 + i32.const 298 i32.const 1 call $~lib/builtins/abort unreachable @@ -1278,7 +1587,7 @@ if i32.const 0 i32.const 80 - i32.const 270 + i32.const 299 i32.const 1 call $~lib/builtins/abort unreachable @@ -1621,6 +1930,30 @@ i64.const 1 i64.popcnt drop + i32.const 1 + i32.const 2 + i32.add + drop + i64.const 1 + i64.const 2 + i64.add + drop + i32.const 2 + i32.const 1 + i32.sub + drop + i64.const 2 + i64.const 1 + i64.sub + drop + i32.const 2 + i32.const 1 + i32.mul + drop + i64.const 2 + i64.const 1 + i64.mul + drop i32.const 8 i32.load8_s drop @@ -1665,6 +1998,30 @@ drop f32.const 1 f32.const 2 + f32.add + drop + f64.const 1 + f64.const 2 + f64.add + drop + f32.const 2 + f32.const 1 + f32.sub + drop + f64.const 2 + f64.const 1 + f64.sub + drop + f32.const 1 + f32.const 2 + f32.mul + drop + f64.const 1 + f64.const 2 + f64.mul + drop + f32.const 1 + f32.const 2 f32.max drop f64.const 1 @@ -1754,7 +2111,7 @@ if i32.const 0 i32.const 80 - i32.const 432 + i32.const 475 i32.const 1 call $~lib/builtins/abort unreachable @@ -1767,7 +2124,7 @@ if i32.const 0 i32.const 80 - i32.const 433 + i32.const 476 i32.const 1 call $~lib/builtins/abort unreachable @@ -1780,7 +2137,7 @@ if i32.const 0 i32.const 80 - i32.const 434 + i32.const 477 i32.const 1 call $~lib/builtins/abort unreachable @@ -1793,7 +2150,7 @@ if i32.const 0 i32.const 80 - i32.const 435 + i32.const 478 i32.const 1 call $~lib/builtins/abort unreachable @@ -1806,7 +2163,7 @@ if i32.const 0 i32.const 80 - i32.const 436 + i32.const 479 i32.const 1 call $~lib/builtins/abort unreachable @@ -1819,7 +2176,7 @@ if i32.const 0 i32.const 80 - i32.const 437 + i32.const 480 i32.const 1 call $~lib/builtins/abort unreachable @@ -1832,7 +2189,7 @@ if i32.const 0 i32.const 80 - i32.const 438 + i32.const 481 i32.const 1 call $~lib/builtins/abort unreachable @@ -1867,7 +2224,7 @@ if i32.const 288 i32.const 80 - i32.const 448 + i32.const 491 i32.const 3 call $~lib/builtins/abort unreachable @@ -1879,7 +2236,7 @@ if i32.const 0 i32.const 80 - i32.const 449 + i32.const 492 i32.const 3 call $~lib/builtins/abort unreachable @@ -1891,7 +2248,7 @@ if i32.const 0 i32.const 80 - i32.const 450 + i32.const 493 i32.const 3 call $~lib/builtins/abort unreachable @@ -1903,7 +2260,7 @@ if i32.const 0 i32.const 80 - i32.const 451 + i32.const 494 i32.const 3 call $~lib/builtins/abort unreachable @@ -1915,7 +2272,7 @@ if i32.const 0 i32.const 80 - i32.const 455 + i32.const 498 i32.const 3 call $~lib/builtins/abort unreachable @@ -1927,7 +2284,7 @@ if i32.const 0 i32.const 80 - i32.const 456 + i32.const 499 i32.const 3 call $~lib/builtins/abort unreachable @@ -1939,7 +2296,7 @@ if i32.const 0 i32.const 80 - i32.const 457 + i32.const 500 i32.const 3 call $~lib/builtins/abort unreachable @@ -1951,7 +2308,7 @@ if i32.const 0 i32.const 80 - i32.const 458 + i32.const 501 i32.const 3 call $~lib/builtins/abort unreachable @@ -1963,7 +2320,7 @@ if i32.const 0 i32.const 80 - i32.const 459 + i32.const 502 i32.const 3 call $~lib/builtins/abort unreachable @@ -1975,7 +2332,7 @@ if i32.const 0 i32.const 80 - i32.const 460 + i32.const 503 i32.const 3 call $~lib/builtins/abort unreachable @@ -1987,7 +2344,7 @@ if i32.const 0 i32.const 80 - i32.const 461 + i32.const 504 i32.const 3 call $~lib/builtins/abort unreachable @@ -1999,7 +2356,7 @@ if i32.const 0 i32.const 80 - i32.const 462 + i32.const 505 i32.const 3 call $~lib/builtins/abort unreachable @@ -2011,7 +2368,7 @@ if i32.const 0 i32.const 80 - i32.const 463 + i32.const 506 i32.const 3 call $~lib/builtins/abort unreachable @@ -2023,7 +2380,7 @@ if i32.const 0 i32.const 80 - i32.const 464 + i32.const 507 i32.const 3 call $~lib/builtins/abort unreachable @@ -2035,7 +2392,7 @@ if i32.const 0 i32.const 80 - i32.const 465 + i32.const 508 i32.const 3 call $~lib/builtins/abort unreachable @@ -2047,7 +2404,7 @@ if i32.const 0 i32.const 80 - i32.const 466 + i32.const 509 i32.const 3 call $~lib/builtins/abort unreachable @@ -2059,7 +2416,7 @@ if i32.const 0 i32.const 80 - i32.const 467 + i32.const 510 i32.const 3 call $~lib/builtins/abort unreachable @@ -2071,7 +2428,7 @@ if i32.const 0 i32.const 80 - i32.const 468 + i32.const 511 i32.const 3 call $~lib/builtins/abort unreachable @@ -2083,7 +2440,7 @@ if i32.const 0 i32.const 80 - i32.const 469 + i32.const 512 i32.const 3 call $~lib/builtins/abort unreachable @@ -2095,7 +2452,7 @@ if i32.const 0 i32.const 80 - i32.const 470 + i32.const 513 i32.const 3 call $~lib/builtins/abort unreachable @@ -2107,7 +2464,7 @@ if i32.const 0 i32.const 80 - i32.const 471 + i32.const 514 i32.const 3 call $~lib/builtins/abort unreachable @@ -2119,7 +2476,7 @@ if i32.const 0 i32.const 80 - i32.const 472 + i32.const 515 i32.const 3 call $~lib/builtins/abort unreachable @@ -2131,7 +2488,7 @@ if i32.const 0 i32.const 80 - i32.const 473 + i32.const 516 i32.const 3 call $~lib/builtins/abort unreachable @@ -2143,7 +2500,7 @@ if i32.const 0 i32.const 80 - i32.const 474 + i32.const 517 i32.const 3 call $~lib/builtins/abort unreachable