Skip to content
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