Skip to content

Add bultins: i32/i64/f32/f64.add/sub/mul #1484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ under the licensing terms detailed in LICENSE:
* ncave <[email protected]>
* Andrew Davis <[email protected]>
* Maël Nison <[email protected]>
* Valeria Viana Gusmao <[email protected]>

Portions of this software are derived from third-party works licensed under
the following terms:
Expand Down
140 changes: 140 additions & 0 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ export namespace BuiltinNames {
export const instantiate = "~lib/builtins/instantiate";
export const idof = "~lib/builtins/idof";

export const add = "~lib/builtins/add";

export const i8 = "~lib/builtins/i8";
export const i16 = "~lib/builtins/i16";
export const i32 = "~lib/builtins/i32";
Expand Down Expand Up @@ -234,6 +236,11 @@ 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_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";
Expand Down Expand Up @@ -2056,6 +2063,103 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
}
builtins.set(BuiltinNames.store, builtin_store);

// add<T?>(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.I32:
case TypeKind.U8:
case TypeKind.U16:
case TypeKind.U32:
case TypeKind.BOOL: {
op = BinaryOp.AddI32;
break;
}
case TypeKind.I64:
case TypeKind.U64: {
op = BinaryOp.AddI64;
break;
}
case TypeKind.ISIZE: {
op = compiler.options.isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32;
break;
}
case TypeKind.USIZE: {
op = compiler.options.isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32;
break;
}
case TypeKind.F32:
return module.binary(BinaryOp.AddF32, arg0, arg1);
case TypeKind.F64:
return module.binary(BinaryOp.AddF64, arg0, arg1);
}
if (op != -1) {
let flow = compiler.currentFlow;
let nativeType = type.toNativeType();
let temp1 = flow.getTempLocal(type);
flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED);
let temp2 = flow.getTempLocal(type);
flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED);
let ret = module.binary(
op,
module.local_get(temp1.index, nativeType),
module.local_get(temp2.index, nativeType)
);
flow.freeTempLocal(temp2);
flow.freeTempLocal(temp1);
return ret;
}
}
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);

// === Atomics ================================================================================

// atomic.load<T!>(offset: usize, immOffset?: usize) -> T*
Expand Down Expand Up @@ -5580,6 +5684,42 @@ function builtin_f64_trunc(ctx: BuiltinContext): ExpressionRef {
}
builtins.set(BuiltinNames.f64_trunc, builtin_f64_trunc);

// f32.add -> add<f32>
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<f64>
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);

// i32.add -> add<i32>
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<i64>
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.load8_s -> <i32>load<i8>
function builtin_i32_load8_s(ctx: BuiltinContext): ExpressionRef {
checkTypeAbsent(ctx);
Expand Down
20 changes: 20 additions & 0 deletions std/assembly/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ export declare function sqrt<T>(value: T): T;
@builtin
export declare function trunc<T>(value: T): T;

// @ts-ignore: decorator
@builtin
export declare function add<T>(left: T, right: T): T;

// @ts-ignore: decorator
@unsafe @builtin
export declare function load<T>(ptr: usize, immOffset?: usize, immAlign?: usize): T;
Expand Down Expand Up @@ -290,6 +294,10 @@ 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 rotl(value: i32, shift: i32): i32;
Expand Down Expand Up @@ -481,6 +489,10 @@ 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 load8_s(ptr: usize, immOffset?: usize, immAlign?: usize): i64;
Expand Down Expand Up @@ -905,6 +917,10 @@ 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
Expand Down Expand Up @@ -996,6 +1012,10 @@ 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
Expand Down
2 changes: 2 additions & 0 deletions std/assembly/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;
declare function sqrt<T = f32 | f64>(value: T): T;
/** Rounds to the nearest integer towards zero of a 32-bit or 64-bit float. */
declare function trunc<T = f32 | f64>(value: T): T;
/** Computes sum of two integers or floats. */
declare function add<T = i32 | i64 | f32 | f64>(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<T>(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. */
Expand Down
Loading