mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 07:02:13 +00:00
sizeof, load and store builtins
This commit is contained in:
parent
017efc71b6
commit
63a67e7c67
38
assembly.d.ts
vendored
38
assembly.d.ts
vendored
@ -30,36 +30,36 @@ declare type f64 = number;
|
||||
// builtins
|
||||
|
||||
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */
|
||||
declare function clz<T extends number>(value: T): T;
|
||||
declare function clz<T = i32 | i64>(value: T): T;
|
||||
/** Performs the sign-agnostic count tailing zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered trailing if the value is zero. */
|
||||
declare function ctz<T>(value: T): T;
|
||||
declare function ctz<T = i32 | i64>(value: T): T;
|
||||
/** Performs the sign-agnostic count number of one bits operation on a 32-bit or 64-bit integer. */
|
||||
declare function popcnt<T>(value: T): T;
|
||||
declare function popcnt<T = i32 | i64>(value: T): T;
|
||||
/** Performs the sign-agnostic rotate left operation on a 32-bit or 64-bit integer. */
|
||||
declare function rotl<T>(value: T, shift: T): T;
|
||||
declare function rotl<T = i32 | i64>(value: T, shift: T): T;
|
||||
/** Performs the sign-agnostic rotate right operation on a 32-bit or 64-bit integer. */
|
||||
declare function rotr<T>(value: T, shift: T): T;
|
||||
declare function rotr<T = i32 | i64>(value: T, shift: T): T;
|
||||
|
||||
/** Computes the absolute value of a 32-bit or 64-bit float. */
|
||||
declare function abs<T>(value: T): T;
|
||||
declare function abs<T = f32 | f64>(value: T): T;
|
||||
/** Performs the ceiling operation on a 32-bit or 64-bit float. */
|
||||
declare function ceil<T>(value: T): T;
|
||||
declare function ceil<T = f32 | f64>(value: T): T;
|
||||
/** Composes a 32-bit or 64-bit float from the magnitude of `x` and the sign of `y`. */
|
||||
declare function copysign<T>(x: T, y: T): T;
|
||||
declare function copysign<T = f32 | f64>(x: T, y: T): T;
|
||||
/** Performs the floor operation on a 32-bit or 64-bit float. */
|
||||
declare function floor<T>(value: T): T;
|
||||
declare function floor<T = f32 | f64>(value: T): T;
|
||||
/** Determines the maximum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
|
||||
declare function max<T>(left: T, right: T): T;
|
||||
declare function max<T = f32 | f64>(left: T, right: T): T;
|
||||
/** Determines the minimum of two 32-bit or 64-bit floats. If either operand is `NaN`, returns `NaN`. */
|
||||
declare function min<T>(left: T, right: T): T;
|
||||
declare function min<T = f32 | f64>(left: T, right: T): T;
|
||||
/** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */
|
||||
declare function nearest<T>(value: T): T;
|
||||
declare function nearest<T = f32 | f64>(value: T): T;
|
||||
/** Reinterprets the bits of a value of type `T1` as type `T2`. Valid reinterpretations are i32 to/from f32 and i64 to/from f64. */
|
||||
declare function reinterpret<T1,T2>(value: T1): T2;
|
||||
declare function reinterpret<T1 = i32 | i64 | f32 | f64, T2 = i32 | i64 | f32 | f64>(value: T1): T2;
|
||||
/** Calculates the square root of a 32-bit or 64-bit float. */
|
||||
declare function sqrt<T>(value: T): 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>(value: T): T;
|
||||
declare function trunc<T = f32 | f64>(value: T): T;
|
||||
|
||||
/** Returns the current memory size in units of pages. One page is 64kb. */
|
||||
declare function current_memory(): i32;
|
||||
@ -76,14 +76,14 @@ declare function store<T>(offset: usize, value: T): void;
|
||||
declare function sizeof<T>(): usize;
|
||||
|
||||
/** NaN (not a number) as a 32-bit or 64-bit float depending on context. */
|
||||
declare const NaN: number;
|
||||
declare const NaN: f32 | f64;
|
||||
/** Positive infinity as a 32-bit or 64-bit float depending on context. */
|
||||
declare const Infinity: number;
|
||||
declare const Infinity: f32 | f64;
|
||||
|
||||
/** Tests if a 32-bit or 64-bit float is NaN. */
|
||||
declare function isNaN<T>(value: T): bool;
|
||||
declare function isNaN<T = f32 | f64>(value: T): bool;
|
||||
/** Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity. */
|
||||
declare function isFinite<T>(value: T): bool;
|
||||
declare function isFinite<T = f32 | f64>(value: T): bool;
|
||||
/** Traps if the specified value is `false`. */
|
||||
declare function assert(isTrue: bool): void;
|
||||
|
||||
|
@ -88,6 +88,8 @@ export class Options {
|
||||
noEmit: bool = false;
|
||||
/** If true, compiles everything instead of just reachable code. */
|
||||
noTreeShaking: bool = false;
|
||||
/** If true, replaces assertions with nops. */
|
||||
noDebug: bool = false;
|
||||
}
|
||||
|
||||
const enum ConversionKind {
|
||||
@ -1398,16 +1400,73 @@ export class Compiler extends DiagnosticEmitter {
|
||||
const functionPrototype: FunctionPrototype = <FunctionPrototype>element;
|
||||
let functionInstance: Function | null = null;
|
||||
if (functionPrototype.isBuiltin) {
|
||||
const k: i32 = expression.typeArguments.length;
|
||||
const resolvedTypeArguments: Type[] = new Array(k);
|
||||
sb.length = 0;
|
||||
for (let i: i32 = 0, k: i32 = expression.typeArguments.length; i < k; ++i) {
|
||||
let type: Type | null = this.program.resolveType(expression.typeArguments[i], this.currentFunction.contextualTypeArguments, true); // reports
|
||||
if (!type)
|
||||
for (let i: i32 = 0; i < k; ++i) {
|
||||
let resolvedType: Type | null = this.program.resolveType(expression.typeArguments[i], this.currentFunction.contextualTypeArguments, true); // reports
|
||||
if (!resolvedType)
|
||||
return this.module.createUnreachable();
|
||||
sb.push(type.toString());
|
||||
resolvedTypeArguments[i] = resolvedType;
|
||||
sb.push(resolvedType.toString());
|
||||
}
|
||||
|
||||
functionInstance = <Function | null>functionPrototype.instances.get(sb.join(","));
|
||||
if (!functionInstance) {
|
||||
// TODO: sizeof, load, store, see program.ts/initializeBuiltins
|
||||
let arg0: ExpressionRef, arg1: ExpressionRef;
|
||||
|
||||
if (functionPrototype.internalName == "sizeof") { // no parameters
|
||||
this.currentType = this.options.target == Target.WASM64 ? Type.usize64 : Type.usize32;
|
||||
if (k != 1) {
|
||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, expression.range, "1", k.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
if (expression.arguments.length != 0) {
|
||||
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, expression.range, "0", expression.arguments.length.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
return this.options.target == Target.WASM64
|
||||
? this.module.createI64(resolvedTypeArguments[0].byteSize, 0)
|
||||
: this.module.createI32(resolvedTypeArguments[0].byteSize);
|
||||
|
||||
} else if (functionPrototype.internalName == "load") {
|
||||
this.currentType = resolvedTypeArguments[0];
|
||||
if (k != 1) {
|
||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, expression.range, "1", k.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
if (expression.arguments.length != 1) {
|
||||
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, expression.range, "1", expression.arguments.length.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
arg0 = this.compileExpression(expression.arguments[0], Type.usize32, ConversionKind.IMPLICIT); // reports
|
||||
this.currentType = resolvedTypeArguments[0];
|
||||
if (!arg0)
|
||||
return this.module.createUnreachable();
|
||||
return this.module.createLoad(resolvedTypeArguments[0].byteSize, resolvedTypeArguments[0].isSignedInteger, arg0, typeToNativeType(resolvedTypeArguments[0]));
|
||||
|
||||
} else if (functionPrototype.internalName == "store") {
|
||||
this.currentType = Type.void;
|
||||
if (k != 1) {
|
||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, expression.range, "1", k.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
if (expression.arguments.length != 2) {
|
||||
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, expression.range, "2", expression.arguments.length.toString());
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
arg0 = this.compileExpression(expression.arguments[0], Type.usize32, ConversionKind.IMPLICIT); // reports
|
||||
this.currentType = Type.void;
|
||||
if (!arg0)
|
||||
return this.module.createUnreachable();
|
||||
arg1 = this.compileExpression(expression.arguments[1], resolvedTypeArguments[0], ConversionKind.IMPLICIT);
|
||||
this.currentType = Type.void;
|
||||
if (!arg1)
|
||||
return this.module.createUnreachable();
|
||||
return this.module.createStore(resolvedTypeArguments[0].byteSize, arg0, arg1, typeToNativeType(resolvedTypeArguments[0]));
|
||||
}
|
||||
this.error(DiagnosticCode.Operation_not_supported, expression.range);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
} else {
|
||||
// TODO: infer type arguments from parameter types if omitted
|
||||
@ -1458,8 +1517,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
this.currentType = functionInstance.returnType;
|
||||
|
||||
let tempLocal: Local;
|
||||
if (functionInstance.isBuiltin) {
|
||||
let tempLocal: Local;
|
||||
switch (functionInstance.template.internalName) {
|
||||
|
||||
case "clz": // i32/i64.clz
|
||||
@ -1570,11 +1629,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
case "unreachable":
|
||||
return this.module.createUnreachable();
|
||||
|
||||
case "sizeof": // T.size
|
||||
if (this.options.target == Target.WASM64)
|
||||
return this.module.createI64(Math.ceil(functionInstance.typeArguments[0].size / 8), 0);
|
||||
return this.module.createI32(Math.ceil(functionInstance.typeArguments[0].size / 8));
|
||||
|
||||
case "isNaN": // value != value
|
||||
if (functionInstance.typeArguments[0] == Type.f64) {
|
||||
tempLocal = this.currentFunction.addLocal(Type.f64);
|
||||
@ -1626,10 +1680,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
|
||||
case "assert":
|
||||
return this.module.createIf(
|
||||
this.module.createUnary(UnaryOp.EqzI32, operands[0]),
|
||||
this.module.createUnreachable()
|
||||
);
|
||||
return this.options.noDebug
|
||||
? this.module.createNop()
|
||||
: this.module.createIf(
|
||||
this.module.createUnary(UnaryOp.EqzI32, operands[0]),
|
||||
this.module.createUnreachable()
|
||||
);
|
||||
}
|
||||
this.error(DiagnosticCode.Operation_not_supported, reportNode.range);
|
||||
return this.module.createUnreachable();
|
||||
|
6
src/glue/js.d.ts
vendored
6
src/glue/js.d.ts
vendored
@ -11,6 +11,6 @@ declare type f32 = number;
|
||||
declare type f64 = number;
|
||||
declare type bool = boolean;
|
||||
|
||||
// Raw memory access (here: Binaryen memory, T=u8)
|
||||
declare function store<T>(ptr: usize, val: u8): void;
|
||||
declare function load<T>(ptr: usize): u8;
|
||||
// Raw memory access (here: Binaryen memory)
|
||||
declare function store<T = u8>(ptr: usize, val: T): void;
|
||||
declare function load<T = u8>(ptr: usize): T;
|
||||
|
@ -1149,19 +1149,21 @@ function initializeBuiltins(program: Program): void {
|
||||
addGenericUnaryBuiltin(program, "sqrt", genericFloat);
|
||||
addGenericUnaryBuiltin(program, "trunc", genericFloat);
|
||||
|
||||
addBuiltin(program, "current_memory", [], usize);
|
||||
addBuiltin(program, "grow_memory", [ usize ], usize);
|
||||
addBuiltin(program, "unreachable", [], Type.void);
|
||||
addSimpleBuiltin(program, "current_memory", [], usize);
|
||||
addSimpleBuiltin(program, "grow_memory", [ usize ], usize);
|
||||
addSimpleBuiltin(program, "unreachable", [], Type.void);
|
||||
|
||||
addGenericUnaryTestBuiltin(program, "isNaN", genericFloat);
|
||||
addGenericUnaryTestBuiltin(program, "isFinite", genericFloat);
|
||||
addBuiltin(program, "assert", [ Type.bool ], Type.void);
|
||||
addSimpleBuiltin(program, "assert", [ Type.bool ], Type.void);
|
||||
|
||||
// TODO: load, store, sizeof
|
||||
// sizeof, for example, has varying Ts but really shouldn't provide an instance for each class
|
||||
addGenericAnyBuiltin(program, "sizeof");
|
||||
addGenericAnyBuiltin(program, "load");
|
||||
addGenericAnyBuiltin(program, "store");
|
||||
}
|
||||
|
||||
function addBuiltin(program: Program, name: string, parameterTypes: Type[], returnType: Type) {
|
||||
/** Adds a simple (non-generic) builtin. */
|
||||
function addSimpleBuiltin(program: Program, name: string, parameterTypes: Type[], returnType: Type) {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isGeneric = false;
|
||||
prototype.isBuiltin = true;
|
||||
@ -1173,6 +1175,7 @@ function addBuiltin(program: Program, name: string, parameterTypes: Type[], retu
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
/** Adds a generic unary builtin that takes and returns a value of its generic type. */
|
||||
function addGenericUnaryBuiltin(program: Program, name: string, types: Type[]): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isGeneric = true;
|
||||
@ -1184,6 +1187,7 @@ function addGenericUnaryBuiltin(program: Program, name: string, types: Type[]):
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
/** Adds a generic binary builtin that takes two and returns a value of its generic type. */
|
||||
function addGenericBinaryBuiltin(program: Program, name: string, types: Type[]): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isGeneric = true;
|
||||
@ -1195,6 +1199,7 @@ function addGenericBinaryBuiltin(program: Program, name: string, types: Type[]):
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
/** Adds a generic unary builtin that alwways returns `bool`. */
|
||||
function addGenericUnaryTestBuiltin(program: Program, name: string, types: Type[]): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isGeneric = true;
|
||||
@ -1205,3 +1210,12 @@ function addGenericUnaryTestBuiltin(program: Program, name: string, types: Type[
|
||||
}
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
/** Adds a special generic builtin that takes any type argument. */
|
||||
function addGenericAnyBuiltin(program: Program, name: string): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isGeneric = true;
|
||||
prototype.isBuiltin = true;
|
||||
program.elements.set(name, prototype);
|
||||
// instances are hard coded in compiler.ts
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ export class Type {
|
||||
|
||||
kind: TypeKind;
|
||||
size: i32;
|
||||
byteSize: i32;
|
||||
classType: Class | null;
|
||||
nullable: bool = false;
|
||||
nullableType: Type | null = null; // cached, of this type
|
||||
@ -36,6 +37,7 @@ export class Type {
|
||||
constructor(kind: TypeKind, size: i32) {
|
||||
this.kind = kind;
|
||||
this.size = size;
|
||||
this.byteSize = Math.ceil(<f64>size / 8);
|
||||
this.classType = null;
|
||||
}
|
||||
|
||||
|
@ -838,6 +838,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
binary/b
|
||||
binary/i
|
||||
binary/I
|
||||
|
@ -104,3 +104,20 @@ s = grow_memory(1);
|
||||
if (0) unreachable();
|
||||
|
||||
assert(true);
|
||||
|
||||
sizeof<u8>();
|
||||
sizeof<u16>();
|
||||
sizeof<u32>();
|
||||
sizeof<u64>();
|
||||
sizeof<usize>();
|
||||
sizeof<bool>();
|
||||
sizeof<i8>();
|
||||
sizeof<i16>();
|
||||
sizeof<i32>();
|
||||
sizeof<i64>();
|
||||
sizeof<isize>();
|
||||
sizeof<f32>();
|
||||
sizeof<f64>();
|
||||
|
||||
i = load<i32>(4);
|
||||
store<i32>(4, i);
|
||||
|
@ -475,6 +475,54 @@
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
(drop
|
||||
(i32.const 1)
|
||||
)
|
||||
(drop
|
||||
(i32.const 2)
|
||||
)
|
||||
(drop
|
||||
(i32.const 4)
|
||||
)
|
||||
(drop
|
||||
(i32.const 8)
|
||||
)
|
||||
(drop
|
||||
(i32.const 4)
|
||||
)
|
||||
(drop
|
||||
(i32.const 1)
|
||||
)
|
||||
(drop
|
||||
(i32.const 1)
|
||||
)
|
||||
(drop
|
||||
(i32.const 2)
|
||||
)
|
||||
(drop
|
||||
(i32.const 4)
|
||||
)
|
||||
(drop
|
||||
(i32.const 8)
|
||||
)
|
||||
(drop
|
||||
(i32.const 4)
|
||||
)
|
||||
(drop
|
||||
(i32.const 4)
|
||||
)
|
||||
(drop
|
||||
(i32.const 8)
|
||||
)
|
||||
(set_global $builtins/i
|
||||
(i32.load
|
||||
(i32.const 4)
|
||||
)
|
||||
)
|
||||
(i32.store
|
||||
(i32.const 4)
|
||||
(get_global $builtins/i)
|
||||
)
|
||||
)
|
||||
)
|
||||
(;
|
||||
@ -499,6 +547,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
builtins/b
|
||||
builtins/i
|
||||
builtins/I
|
||||
|
@ -77,6 +77,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
do/loopDo
|
||||
do/loopDoInDo
|
||||
[program.exports]
|
||||
|
@ -46,6 +46,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -68,6 +68,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
if/ifThenElse
|
||||
if/ifThen
|
||||
if/ifThenElseBlock
|
||||
|
@ -60,6 +60,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -161,6 +161,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
[program.exports]
|
||||
|
||||
;)
|
||||
|
@ -62,6 +62,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -167,6 +167,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
switch/doSwitch
|
||||
switch/doSwitchDefaultFirst
|
||||
switch/doSwitchDefaultOmitted
|
||||
|
@ -655,6 +655,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
unary/i
|
||||
unary/I
|
||||
unary/f
|
||||
|
@ -86,6 +86,9 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
sizeof
|
||||
load
|
||||
store
|
||||
while/loopWhile
|
||||
while/loopWhileInWhile
|
||||
[program.exports]
|
||||
|
Loading…
x
Reference in New Issue
Block a user