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

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

Merged
merged 17 commits into from
Oct 5, 2020
Merged
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 <777696+ncave@users.noreply.github.com>
* Andrew Davis <pulpdrew@gmail.com>
* Maël Nison <nison.mael@gmail.com>
* Valeria Viana Gusmao <valeria.viana.gusmao@gmail.com>

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

export const add = "~lib/builtins/add";
export const clz = "~lib/builtins/clz";
export const ctz = "~lib/builtins/ctz";
export const popcnt = "~lib/builtins/popcnt";
Expand Down Expand Up @@ -234,6 +235,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 +2062,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;
}
ValeriaVG marked this conversation as resolved.
Show resolved Hide resolved
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 +5683,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];
MaxGraey marked this conversation as resolved.
Show resolved Hide resolved
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];
MaxGraey marked this conversation as resolved.
Show resolved Hide resolved
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;
ValeriaVG marked this conversation as resolved.
Show resolved Hide resolved
/** 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