2018-03-17 23:41:48 +01:00
|
|
|
/**
|
2018-03-19 01:12:18 +01:00
|
|
|
* Built-in elements providing WebAssembly core functionality.
|
|
|
|
* @module builtins
|
|
|
|
*//***/
|
2018-03-17 23:41:48 +01:00
|
|
|
|
2018-04-22 23:13:02 +02:00
|
|
|
import {
|
2017-12-24 03:19:47 +01:00
|
|
|
Compiler,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind,
|
2019-02-07 11:40:23 +01:00
|
|
|
WrapMode,
|
|
|
|
Feature
|
2017-12-24 03:19:47 +01:00
|
|
|
} from "./compiler";
|
|
|
|
|
|
|
|
import {
|
|
|
|
DiagnosticCode
|
|
|
|
} from "./diagnostics";
|
|
|
|
|
|
|
|
import {
|
|
|
|
Node,
|
2018-03-24 00:38:49 +01:00
|
|
|
NodeKind,
|
|
|
|
Expression,
|
|
|
|
LiteralKind,
|
|
|
|
LiteralExpression,
|
2019-02-07 18:21:09 +01:00
|
|
|
StringLiteralExpression,
|
|
|
|
CallExpression
|
2017-12-24 03:19:47 +01:00
|
|
|
} from "./ast";
|
|
|
|
|
|
|
|
import {
|
2018-01-10 23:19:14 +01:00
|
|
|
Type,
|
|
|
|
TypeKind,
|
|
|
|
TypeFlags
|
2017-12-24 03:19:47 +01:00
|
|
|
} from "./types";
|
|
|
|
|
|
|
|
import {
|
|
|
|
BinaryOp,
|
2018-03-21 16:29:08 +01:00
|
|
|
UnaryOp,
|
2017-12-24 03:19:47 +01:00
|
|
|
HostOp,
|
|
|
|
NativeType,
|
|
|
|
ExpressionRef,
|
2018-05-06 00:00:54 +02:00
|
|
|
ExpressionId,
|
|
|
|
getExpressionId,
|
|
|
|
getExpressionType,
|
|
|
|
getConstValueI64High,
|
|
|
|
getConstValueI64Low,
|
2019-02-07 15:25:49 +01:00
|
|
|
getConstValueI32,
|
|
|
|
AtomicRMWOp
|
2017-12-24 03:19:47 +01:00
|
|
|
} from "./module";
|
|
|
|
|
|
|
|
import {
|
2018-03-21 16:29:08 +01:00
|
|
|
ElementKind,
|
|
|
|
FunctionPrototype,
|
2018-01-20 05:27:54 +01:00
|
|
|
Class,
|
2018-04-11 23:35:19 +02:00
|
|
|
Field,
|
2018-07-18 23:49:32 +02:00
|
|
|
Global,
|
2019-02-07 15:25:49 +01:00
|
|
|
DecoratorFlags,
|
2019-02-21 00:11:22 +01:00
|
|
|
ClassPrototype
|
2017-12-24 03:19:47 +01:00
|
|
|
} from "./program";
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
import {
|
|
|
|
FlowFlags
|
|
|
|
} from "./flow";
|
|
|
|
|
2018-07-14 16:42:00 +02:00
|
|
|
import {
|
|
|
|
ReportMode
|
|
|
|
} from "./resolver";
|
|
|
|
|
2018-07-18 23:49:32 +02:00
|
|
|
import {
|
2019-02-21 00:11:22 +01:00
|
|
|
CommonFlags, CommonSymbols
|
2018-07-18 23:49:32 +02:00
|
|
|
} from "./common";
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
/** Symbols of various compiler built-ins. */
|
|
|
|
export namespace BuiltinSymbols {
|
|
|
|
// std/builtins.ts
|
|
|
|
export const isInteger = "~lib/builtins/isInteger";
|
|
|
|
export const isFloat = "~lib/builtins/isFloat";
|
|
|
|
export const isSigned = "~lib/builtins/isSigned";
|
|
|
|
export const isReference = "~lib/builtins/isReference";
|
|
|
|
export const isString = "~lib/builtins/isString";
|
|
|
|
export const isArray = "~lib/builtins/isArray";
|
2019-02-22 01:11:05 +01:00
|
|
|
export const isFunction = "~lib/builtins/isFunction";
|
|
|
|
export const isNullable = "~lib/builtins/isNullable";
|
2019-02-21 00:11:22 +01:00
|
|
|
export const isDefined = "~lib/builtins/isDefined";
|
|
|
|
export const isConstant = "~lib/builtins/isConstant";
|
|
|
|
export const isManaged = "~lib/builtins/isManaged";
|
|
|
|
export const clz = "~lib/builtins/clz";
|
|
|
|
export const ctz = "~lib/builtins/ctz";
|
|
|
|
export const popcnt = "~lib/builtins/popcnt";
|
|
|
|
export const rotl = "~lib/builtins/rotl";
|
|
|
|
export const rotr = "~lib/builtins/rotr";
|
|
|
|
export const abs = "~lib/builtins/abs";
|
|
|
|
export const max = "~lib/builtins/max";
|
|
|
|
export const min = "~lib/builtins/min";
|
|
|
|
export const ceil = "~lib/builtins/ceil";
|
|
|
|
export const floor = "~lib/builtins/floor";
|
|
|
|
export const copysign = "~lib/builtins/copysign";
|
|
|
|
export const nearest = "~lib/builtins/nearest";
|
|
|
|
export const reinterpret = "~lib/builtins/reinterpret";
|
|
|
|
export const sqrt = "~lib/builtins/sqrt";
|
|
|
|
export const trunc = "~lib/builtins/trunc";
|
|
|
|
export const load = "~lib/builtins/load";
|
|
|
|
export const store = "~lib/builtins/store";
|
|
|
|
export const atomic_load = "~lib/builtins/atomic.load";
|
|
|
|
export const atomic_store = "~lib/builtins/atomic.store";
|
|
|
|
export const atomic_add = "~lib/builtins/atomic.add";
|
|
|
|
export const atomic_sub = "~lib/builtins/atomic.sub";
|
|
|
|
export const atomic_and = "~lib/builtins/atomic.and";
|
|
|
|
export const atomic_or = "~lib/builtins/atomic.or";
|
|
|
|
export const atomic_xor = "~lib/builtins/atomic.xor";
|
|
|
|
export const atomic_xchg = "~lib/builtins/atomic.xchg";
|
|
|
|
export const atomic_cmpxchg = "~lib/builtins/atomic.cmpxchg";
|
|
|
|
export const atomic_wait = "~lib/builtins/atomic.wait";
|
|
|
|
export const atomic_notify = "~lib/builtins/atomic.notify";
|
|
|
|
export const sizeof = "~lib/builtins/sizeof";
|
|
|
|
export const alignof = "~lib/builtins/alignof";
|
|
|
|
export const offsetof = "~lib/builtins/offsetof";
|
|
|
|
export const select = "~lib/builtins/select";
|
|
|
|
export const unreachable = "~lib/builtins/unreachable";
|
|
|
|
export const changetype = "~lib/builtins/changetype";
|
|
|
|
export const assert = "~lib/builtins/assert";
|
|
|
|
export const unchecked = "~lib/builtins/unchecked";
|
|
|
|
export const call_indirect = "~lib/builtins/call_indirect";
|
|
|
|
export const instantiate = "~lib/builtins/instantiate";
|
|
|
|
export const i8 = "~lib/builtins/i8";
|
|
|
|
export const i16 = "~lib/builtins/i16";
|
|
|
|
export const i32 = "~lib/builtins/i32";
|
|
|
|
export const i64 = "~lib/builtins/i64";
|
|
|
|
export const isize = "~lib/builtins/isize";
|
|
|
|
export const u8 = "~lib/builtins/u8";
|
|
|
|
export const u16 = "~lib/builtins/u16";
|
|
|
|
export const u32 = "~lib/builtins/u32";
|
|
|
|
export const u64 = "~lib/builtins/u64";
|
|
|
|
export const usize = "~lib/builtins/usize";
|
|
|
|
export const bool = "~lib/builtins/bool";
|
|
|
|
export const f32 = "~lib/builtins/f32";
|
|
|
|
export const f64 = "~lib/builtins/f64";
|
|
|
|
export const v128 = "~lib/builtins/v128";
|
|
|
|
export const void_ = "~lib/builtins/void";
|
|
|
|
export const i32_clz = "~lib/builtins/i32.clz";
|
|
|
|
export const i64_clz = "~lib/builtins/i64.clz";
|
|
|
|
export const i32_ctz = "~lib/builtins/i32.ctz";
|
|
|
|
export const i64_ctz = "~lib/builtins/i64.ctz";
|
|
|
|
export const i32_popcnt = "~lib/builtins/i32.popcnt";
|
|
|
|
export const i64_popcnt = "~lib/builtins/i64.popcnt";
|
|
|
|
export const i32_rotl = "~lib/builtins/i32.rotl";
|
|
|
|
export const i64_rotl = "~lib/builtins/i64.rotl";
|
|
|
|
export const i32_rotr = "~lib/builtins/i32.rotr";
|
|
|
|
export const i64_rotr = "~lib/builtins/i64.rotr";
|
|
|
|
export const f32_abs = "~lib/builtins/f32.abs";
|
|
|
|
export const f64_abs = "~lib/builtins/f64.abs";
|
|
|
|
export const f32_max = "~lib/builtins/f32.max";
|
|
|
|
export const f64_max = "~lib/builtins/f64.max";
|
|
|
|
export const f32_min = "~lib/builtins/f32.min";
|
|
|
|
export const f64_min = "~lib/builtins/f64.min";
|
|
|
|
export const f32_ceil = "~lib/builtins/f32.ceil";
|
|
|
|
export const f64_ceil = "~lib/builtins/f64.ceil";
|
|
|
|
export const f32_floor = "~lib/builtins/f32.floor";
|
|
|
|
export const f64_floor = "~lib/builtins/f64.floor";
|
|
|
|
export const f32_copysign = "~lib/builtins/f32.copysign";
|
|
|
|
export const f64_copysign = "~lib/builtins/f64.copysign";
|
|
|
|
export const f32_nearest = "~lib/builtins/f32.nearest";
|
|
|
|
export const f64_nearest = "~lib/builtins/f64.nearest";
|
|
|
|
export const i32_reinterpret_f32 = "~lib/builtins/i32.reinterpret_f32";
|
|
|
|
export const i64_reinterpret_f64 = "~lib/builtins/i64.reinterpret_f64";
|
|
|
|
export const f32_reinterpret_i32 = "~lib/builtins/f32.reinterpret_i32";
|
|
|
|
export const f64_reinterpret_i64 = "~lib/builtins/f64.reinterpret_i64";
|
|
|
|
export const f32_sqrt = "~lib/builtins/f32.sqrt";
|
|
|
|
export const f64_sqrt = "~lib/builtins/f64.sqrt";
|
|
|
|
export const f32_trunc = "~lib/builtins/f32.trunc";
|
|
|
|
export const f64_trunc = "~lib/builtins/f64.trunc";
|
|
|
|
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";
|
|
|
|
export const i32_load16_u = "~lib/builtins/i32.load16_u";
|
|
|
|
export const i32_load = "~lib/builtins/i32.load";
|
|
|
|
export const i64_load8_s = "~lib/builtins/i64.load8_s";
|
|
|
|
export const i64_load8_u = "~lib/builtins/i64.load8_u";
|
|
|
|
export const i64_load16_s = "~lib/builtins/i64.load16_s";
|
|
|
|
export const i64_load16_u = "~lib/builtins/i64.load16_u";
|
|
|
|
export const i64_load32_s = "~lib/builtins/i64.load32_s";
|
|
|
|
export const i64_load32_u = "~lib/builtins/i64.load32_u";
|
|
|
|
export const i64_load = "~lib/builtins/i64.load";
|
|
|
|
export const f32_load = "~lib/builtins/f32.load";
|
|
|
|
export const f64_load = "~lib/builtins/f64.load";
|
|
|
|
export const i32_store8 = "~lib/builtins/i32.store8";
|
|
|
|
export const i32_store16 = "~lib/builtins/i32.store16";
|
|
|
|
export const i32_store = "~lib/builtins/i32.store";
|
|
|
|
export const i64_store8 = "~lib/builtins/i64.store8";
|
|
|
|
export const i64_store16 = "~lib/builtins/i64.store16";
|
|
|
|
export const i64_store32 = "~lib/builtins/i64.store32";
|
|
|
|
export const i64_store = "~lib/builtins/i64.store";
|
|
|
|
export const f32_store = "~lib/builtins/f32.store";
|
|
|
|
export const f64_store = "~lib/builtins/f64.store";
|
|
|
|
export const i32_atomic_load8_u = "~lib/builtins/i32.atomic.load8_u";
|
|
|
|
export const i32_atomic_load16_u = "~lib/builtins/i32.atomic.load16_u";
|
|
|
|
export const i32_atomic_load = "~lib/builtins/i32.atomic.load";
|
|
|
|
export const i64_atomic_load8_u = "~lib/builtins/i64.atomic.load8_u";
|
|
|
|
export const i64_atomic_load16_u = "~lib/builtins/i64.atomic.load16_u";
|
|
|
|
export const i64_atomic_load32_u = "~lib/builtins/i64.atomic.load32_u";
|
|
|
|
export const i64_atomic_load = "~lib/builtins/i64.atomic.load";
|
|
|
|
export const i32_atomic_store8 = "~lib/builtins/i32.atomic.store8";
|
|
|
|
export const i32_atomic_store16 = "~lib/builtins/i32.atomic.store16";
|
|
|
|
export const i32_atomic_store = "~lib/builtins/i32.atomic.store";
|
|
|
|
export const i64_atomic_store8 = "~lib/builtins/i64.atomic.store8";
|
|
|
|
export const i64_atomic_store16 = "~lib/builtins/i64.atomic.store16";
|
|
|
|
export const i64_atomic_store32 = "~lib/builtins/i64.atomic.store32";
|
|
|
|
export const i64_atomic_store = "~lib/builtins/i64.atomic.store";
|
|
|
|
export const i32_atomic_rmw8_u_add = "~lib/builtins/i32.atomic.rmw8_u.add";
|
|
|
|
export const i32_atomic_rmw16_u_add = "~lib/builtins/i32.atomic.rmw16_u.add";
|
|
|
|
export const i32_atomic_rmw_add = "~lib/builtins/i32.atomic.rmw.add";
|
|
|
|
export const i64_atomic_rmw8_u_add = "~lib/builtins/i64.atomic.rmw8_u.add";
|
|
|
|
export const i64_atomic_rmw16_u_add = "~lib/builtins/i64.atomic.rmw16_u.add";
|
|
|
|
export const i64_atomic_rmw32_u_add = "~lib/builtins/i64.atomic.rmw32_u.add";
|
|
|
|
export const i64_atomic_rmw_add = "~lib/builtins/i64.atomic.rmw.add";
|
|
|
|
export const i32_atomic_rmw8_u_sub = "~lib/builtins/i32.atomic.rmw8_u.sub";
|
|
|
|
export const i32_atomic_rmw16_u_sub = "~lib/builtins/i32.atomic.rmw16_u.sub";
|
|
|
|
export const i32_atomic_rmw_sub = "~lib/builtins/i32.atomic.rmw.sub";
|
|
|
|
export const i64_atomic_rmw8_u_sub = "~lib/builtins/i64.atomic.rmw8_u.sub";
|
|
|
|
export const i64_atomic_rmw16_u_sub = "~lib/builtins/i64.atomic.rmw16_u.sub";
|
|
|
|
export const i64_atomic_rmw32_u_sub = "~lib/builtins/i64.atomic.rmw32_u.sub";
|
|
|
|
export const i64_atomic_rmw_sub = "~lib/builtins/i64.atomic.rmw.sub";
|
|
|
|
export const i32_atomic_rmw8_u_and = "~lib/builtins/i32.atomic.rmw8_u.and";
|
|
|
|
export const i32_atomic_rmw16_u_and = "~lib/builtins/i32.atomic.rmw16_u.and";
|
|
|
|
export const i32_atomic_rmw_and = "~lib/builtins/i32.atomic.rmw.and";
|
|
|
|
export const i64_atomic_rmw8_u_and = "~lib/builtins/i64.atomic.rmw8_u.and";
|
|
|
|
export const i64_atomic_rmw16_u_and = "~lib/builtins/i64.atomic.rmw16_u.and";
|
|
|
|
export const i64_atomic_rmw32_u_and = "~lib/builtins/i64.atomic.rmw32_u.and";
|
|
|
|
export const i64_atomic_rmw_and = "~lib/builtins/i64.atomic.rmw.and";
|
|
|
|
export const i32_atomic_rmw8_u_or = "~lib/builtins/i32.atomic.rmw8_u.or";
|
|
|
|
export const i32_atomic_rmw16_u_or = "~lib/builtins/i32.atomic.rmw16_u.or";
|
|
|
|
export const i32_atomic_rmw_or = "~lib/builtins/i32.atomic.rmw.or";
|
|
|
|
export const i64_atomic_rmw8_u_or = "~lib/builtins/i64.atomic.rmw8_u.or";
|
|
|
|
export const i64_atomic_rmw16_u_or = "~lib/builtins/i64.atomic.rmw16_u.or";
|
|
|
|
export const i64_atomic_rmw32_u_or = "~lib/builtins/i64.atomic.rmw32_u.or";
|
|
|
|
export const i64_atomic_rmw_or = "~lib/builtins/i64.atomic.rmw.or";
|
|
|
|
export const i32_atomic_rmw8_u_xor = "~lib/builtins/i32.atomic.rmw8_u.xor";
|
|
|
|
export const i32_atomic_rmw16_u_xor = "~lib/builtins/i32.atomic.rmw16_u.xor";
|
|
|
|
export const i32_atomic_rmw_xor = "~lib/builtins/i32.atomic.rmw.xor";
|
|
|
|
export const i64_atomic_rmw8_u_xor = "~lib/builtins/i64.atomic.rmw8_u.xor";
|
|
|
|
export const i64_atomic_rmw16_u_xor = "~lib/builtins/i64.atomic.rmw16_u.xor";
|
|
|
|
export const i64_atomic_rmw32_u_xor = "~lib/builtins/i64.atomic.rmw32_u.xor";
|
|
|
|
export const i64_atomic_rmw_xor = "~lib/builtins/i64.atomic.rmw.xor";
|
|
|
|
export const i32_atomic_rmw8_u_xchg = "~lib/builtins/i32.atomic.rmw8_u.xchg";
|
|
|
|
export const i32_atomic_rmw16_u_xchg = "~lib/builtins/i32.atomic.rmw16_u.xchg";
|
|
|
|
export const i32_atomic_rmw_xchg = "~lib/builtins/i32.atomic.rmw.xchg";
|
|
|
|
export const i64_atomic_rmw8_u_xchg = "~lib/builtins/i64.atomic.rmw8_u.xchg";
|
|
|
|
export const i64_atomic_rmw16_u_xchg = "~lib/builtins/i64.atomic.rmw16_u.xchg";
|
|
|
|
export const i64_atomic_rmw32_u_xchg = "~lib/builtins/i64.atomic.rmw32_u.xchg";
|
|
|
|
export const i64_atomic_rmw_xchg = "~lib/builtins/i64.atomic.rmw.xchg";
|
|
|
|
export const i32_atomic_rmw8_u_cmpxchg = "~lib/builtins/i32.atomic.rmw8_u.cmpxchg";
|
|
|
|
export const i32_atomic_rmw16_u_cmpxchg = "~lib/builtins/i32.atomic.rmw16_u.cmpxchg";
|
|
|
|
export const i32_atomic_rmw_cmpxchg = "~lib/builtins/i32.atomic.rmw.cmpxchg";
|
|
|
|
export const i64_atomic_rmw8_u_cmpxchg = "~lib/builtins/i64.atomic.rmw8_u.cmpxchg";
|
|
|
|
export const i64_atomic_rmw16_u_cmpxchg = "~lib/builtins/i64.atomic.rmw16_u.cmpxchg";
|
|
|
|
export const i64_atomic_rmw32_u_cmpxchg = "~lib/builtins/i64.atomic.rmw32_u.cmpxchg";
|
|
|
|
export const i64_atomic_rmw_cmpxchg = "~lib/builtins/i64.atomic.rmw.cmpxchg";
|
|
|
|
export const i32_wait = "~lib/builtins/i32.wait";
|
|
|
|
export const i64_wait = "~lib/builtins/i64.wait";
|
|
|
|
export const i32_notify = "~lib/builtins/i32.notify";
|
|
|
|
export const i64_notify = "~lib/builtins/i64.notify";
|
|
|
|
// std/diagnostics.ts
|
|
|
|
export const ERROR = "~lib/diagnostics/ERROR";
|
|
|
|
export const WARNING = "~lib/diagnostics/WARNING";
|
|
|
|
export const INFO = "~lib/diagnostics/INFO";
|
|
|
|
// std/memory.ts
|
|
|
|
export const HEAP_BASE = "~lib/memory/HEAP_BASE";
|
|
|
|
export const memory_size = "~lib/memory/memory.size";
|
|
|
|
export const memory_grow = "~lib/memory/memory.grow";
|
|
|
|
export const memory_copy = "~lib/memory/memory.copy";
|
|
|
|
export const memory_fill = "~lib/memory/memory.fill";
|
|
|
|
// std/gc.ts
|
|
|
|
export const iterateRoots = "~lib/gc/iterateRoots";
|
|
|
|
}
|
|
|
|
|
2017-12-05 13:35:14 +01:00
|
|
|
/** Compiles a call to a built-in function. */
|
2018-02-16 18:57:51 +01:00
|
|
|
export function compileCall(
|
|
|
|
compiler: Compiler,
|
|
|
|
prototype: FunctionPrototype,
|
|
|
|
typeArguments: Type[] | null,
|
|
|
|
operands: Expression[],
|
|
|
|
contextualType: Type,
|
2019-02-07 18:21:09 +01:00
|
|
|
reportNode: CallExpression
|
2018-02-16 18:57:51 +01:00
|
|
|
): ExpressionRef {
|
2017-12-28 04:09:40 +01:00
|
|
|
var module = compiler.module;
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2017-12-28 04:09:40 +01:00
|
|
|
var arg0: ExpressionRef,
|
2017-12-05 01:45:15 +01:00
|
|
|
arg1: ExpressionRef,
|
2018-01-10 13:09:05 +01:00
|
|
|
arg2: ExpressionRef,
|
|
|
|
ret: ExpressionRef;
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2018-01-10 13:09:05 +01:00
|
|
|
// NOTE that some implementations below make use of the select expression where straight-forward.
|
2018-07-14 18:01:19 +02:00
|
|
|
// whether worth or not should probably be tested once it's known if/how embedders handle it.
|
2018-01-10 13:09:05 +01:00
|
|
|
// search: createSelect
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2017-12-12 01:35:48 +01:00
|
|
|
switch (prototype.internalName) {
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2018-03-17 12:54:37 +01:00
|
|
|
// types
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isInteger: { // isInteger<T!>() / isInteger<T?>(value: T) -> bool
|
2018-04-07 23:31:36 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
2018-03-17 12:54:37 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (!type) return module.createUnreachable();
|
2018-03-17 12:54:37 +01:00
|
|
|
return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE)
|
|
|
|
? module.createI32(1)
|
|
|
|
: module.createI32(0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isFloat: { // isFloat<T!>() / isFloat<T?>(value: T) -> bool
|
2018-04-07 23:31:36 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
2018-03-17 12:54:37 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (!type) return module.createUnreachable();
|
2018-03-17 12:54:37 +01:00
|
|
|
return type.is(TypeFlags.FLOAT)
|
|
|
|
? module.createI32(1)
|
|
|
|
: module.createI32(0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isSigned: { // isSigned<T!>() / isSigned<T?>(value: T) -> bool
|
2018-04-27 00:08:41 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
if (!type) return module.createUnreachable();
|
|
|
|
return type.is(TypeFlags.SIGNED)
|
|
|
|
? module.createI32(1)
|
|
|
|
: module.createI32(0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isReference: { // isReference<T!>() / isReference<T?>(value: T) -> bool
|
2018-04-07 23:31:36 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
2018-03-17 12:54:37 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (!type) return module.createUnreachable();
|
2018-03-17 12:54:37 +01:00
|
|
|
return type.is(TypeFlags.REFERENCE)
|
|
|
|
? module.createI32(1)
|
|
|
|
: module.createI32(0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isString: { // isString<T!>() / isString<T?>(value: T) -> bool
|
2018-04-07 23:31:36 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
2018-03-17 12:54:37 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (!type) return module.createUnreachable();
|
2018-03-21 23:27:53 +01:00
|
|
|
let classType = type.classReference;
|
2018-03-17 12:54:37 +01:00
|
|
|
if (classType) {
|
2018-03-31 18:18:55 +02:00
|
|
|
let stringInstance = compiler.program.stringInstance;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (stringInstance && classType.isAssignableTo(stringInstance)) return module.createI32(1);
|
2018-03-17 12:54:37 +01:00
|
|
|
}
|
|
|
|
return module.createI32(0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isArray: { // isArray<T!>() / isArray<T?>(value: T) -> bool
|
2018-04-07 23:31:36 +02:00
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
2018-03-17 12:54:37 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2018-04-07 23:31:36 +02:00
|
|
|
if (!type) return module.createUnreachable();
|
2019-02-21 00:11:22 +01:00
|
|
|
let classReference = type.classReference;
|
|
|
|
if (!classReference) return module.createI32(0);
|
|
|
|
let classPrototype = classReference.prototype;
|
|
|
|
return module.createI32(
|
|
|
|
(<ClassPrototype>classPrototype).extends(compiler.program.arrayPrototype)
|
|
|
|
? 1
|
|
|
|
: 0
|
|
|
|
);
|
2018-03-17 12:54:37 +01:00
|
|
|
}
|
2019-02-22 01:11:05 +01:00
|
|
|
case BuiltinSymbols.isFunction: { // isFunction<T!> / isFunction<T?>(value: T) -> bool
|
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
if (!type) return module.createUnreachable();
|
|
|
|
return module.createI32(type.signatureReference ? 1 : 0);
|
|
|
|
}
|
|
|
|
case BuiltinSymbols.isNullable: { // isNullable<T!> / isNullable<T?>(value: T) -> bool
|
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
if (!type) return module.createUnreachable();
|
|
|
|
return module.createI32(type.is(TypeFlags.NULLABLE) ? 1 : 0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isDefined: { // isDefined(expression) -> bool
|
2018-07-14 16:42:00 +02:00
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2019-01-09 12:45:29 +01:00
|
|
|
let element = compiler.resolver.resolveExpression(
|
|
|
|
operands[0],
|
2019-02-06 23:42:43 +01:00
|
|
|
compiler.currentFlow,
|
2019-01-09 12:45:29 +01:00
|
|
|
Type.void,
|
|
|
|
ReportMode.SWALLOW
|
|
|
|
);
|
2018-07-18 23:49:32 +02:00
|
|
|
return module.createI32(element ? 1 : 0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isConstant: { // isConstant(expression) -> bool
|
2018-07-18 23:49:32 +02:00
|
|
|
compiler.currentType = Type.bool;
|
2018-07-14 16:42:00 +02:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
2018-07-18 23:49:32 +02:00
|
|
|
}
|
|
|
|
if (operands.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-07-14 16:42:00 +02:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let expr = compiler.compileExpressionRetainType(operands[0], Type.i32, WrapMode.NONE);
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
return module.createI32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isManaged: { // isManaged<T>() -> bool
|
2018-08-02 18:23:02 +02:00
|
|
|
if (!compiler.program.hasGC) {
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
return module.createI32(0);
|
|
|
|
}
|
|
|
|
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
|
|
|
|
compiler.currentType = Type.bool;
|
|
|
|
if (!type) return module.createUnreachable();
|
|
|
|
let classType = type.classReference;
|
|
|
|
return classType !== null && !classType.hasDecorator(DecoratorFlags.UNMANAGED)
|
|
|
|
? module.createI32(1)
|
|
|
|
: module.createI32(0);
|
|
|
|
}
|
2018-03-17 12:54:37 +01:00
|
|
|
|
2017-12-15 17:23:04 +01:00
|
|
|
// math
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.clz: { // clz<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-05-06 00:00:54 +02:00
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16: {
|
|
|
|
ret = module.createUnary(UnaryOp.ClzI32, arg0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TypeKind.BOOL: // usually overflows
|
|
|
|
case TypeKind.I32:
|
|
|
|
case TypeKind.U32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ClzI32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.ClzI64
|
|
|
|
: UnaryOp.ClzI32,
|
|
|
|
arg0
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ClzI64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.ctz: { // ctz<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-05-06 00:00:54 +02:00
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16: {
|
|
|
|
ret = module.createUnary(UnaryOp.CtzI32, arg0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TypeKind.BOOL: // usually overflows
|
|
|
|
case TypeKind.I32:
|
|
|
|
case TypeKind.U32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.CtzI32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.CtzI64
|
|
|
|
: UnaryOp.CtzI32,
|
|
|
|
arg0
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.CtzI64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.popcnt: { // popcnt<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-05-06 00:00:54 +02:00
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16: {
|
|
|
|
ret = module.createUnary(UnaryOp.PopcntI32, arg0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TypeKind.BOOL: // usually overflows
|
|
|
|
case TypeKind.I32:
|
|
|
|
case TypeKind.U32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.PopcntI32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.PopcntI64
|
|
|
|
: UnaryOp.PopcntI32,
|
|
|
|
arg0
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.PopcntI64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.rotl: { // rotl<T?>(value: T, shift: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], compiler.currentType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.BOOL: {
|
2018-05-06 00:00:54 +02:00
|
|
|
ret = compiler.ensureSmallIntegerWrap(
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(BinaryOp.RotlI32, arg0, arg1),
|
2018-04-28 18:07:20 +02:00
|
|
|
compiler.currentType
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I32:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.RotlI32, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.RotlI64
|
|
|
|
: BinaryOp.RotlI32,
|
|
|
|
arg0,
|
|
|
|
arg1
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.RotlI64, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return ret; // possibly overflows
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.rotr: { // rotr<T?>(value: T, shift: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], compiler.currentType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.BOOL: {
|
2018-05-06 00:00:54 +02:00
|
|
|
ret = compiler.ensureSmallIntegerWrap(
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(BinaryOp.RotrI32, arg0, arg1),
|
2018-04-28 18:07:20 +02:00
|
|
|
compiler.currentType
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I32:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.RotrI32, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.RotrI64
|
|
|
|
: BinaryOp.RotrI32,
|
|
|
|
arg0,
|
|
|
|
arg1
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.RotrI64, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return ret; // possibly overflowws
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.abs: { // abs<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.I32: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
2019-01-15 19:22:24 +02:00
|
|
|
|
2018-05-06 00:00:54 +02:00
|
|
|
// possibly overflows, e.g. abs<i8>(-128) == 128
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getTempLocal(Type.i32, false);
|
|
|
|
let tempLocalIndex2 = flow.getAndFreeTempLocal(Type.i32, false).index;
|
2019-01-15 19:22:24 +02:00
|
|
|
let tempLocalIndex1 = tempLocal1.index;
|
|
|
|
|
|
|
|
// (x + (x >> 31)) ^ (x >> 31)
|
|
|
|
ret = module.createBinary(BinaryOp.XorI32,
|
|
|
|
module.createBinary(BinaryOp.AddI32,
|
|
|
|
module.createTeeLocal(
|
|
|
|
tempLocalIndex2,
|
|
|
|
module.createBinary(BinaryOp.ShrI32,
|
|
|
|
module.createTeeLocal(tempLocalIndex1, arg0),
|
|
|
|
module.createI32(31)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
module.createGetLocal(tempLocalIndex1, NativeType.I32)
|
2018-01-10 13:09:05 +01:00
|
|
|
),
|
2019-01-15 19:22:24 +02:00
|
|
|
module.createGetLocal(tempLocalIndex2, NativeType.I32)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
2019-01-15 19:22:24 +02:00
|
|
|
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal1);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2019-01-15 19:22:24 +02:00
|
|
|
let options = compiler.options;
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
2019-01-15 19:22:24 +02:00
|
|
|
let wasm64 = options.isWasm64;
|
|
|
|
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getTempLocal(options.usizeType, false);
|
|
|
|
let tempLocalIndex2 = flow.getAndFreeTempLocal(options.usizeType, false).index;
|
2019-01-15 19:22:24 +02:00
|
|
|
let tempLocalIndex1 = tempLocal1.index;
|
|
|
|
|
|
|
|
ret = module.createBinary(wasm64 ? BinaryOp.XorI64 : BinaryOp.XorI32,
|
|
|
|
module.createBinary(wasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32,
|
|
|
|
module.createTeeLocal(
|
|
|
|
tempLocalIndex2,
|
|
|
|
module.createBinary(wasm64 ? BinaryOp.ShrI64 : BinaryOp.ShrI32,
|
|
|
|
module.createTeeLocal(tempLocalIndex1, arg0),
|
|
|
|
wasm64 ? module.createI64(63) : module.createI32(31)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
module.createGetLocal(tempLocalIndex1, options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
),
|
2019-01-15 19:22:24 +02:00
|
|
|
module.createGetLocal(tempLocalIndex2, options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
2019-01-15 19:22:24 +02:00
|
|
|
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal1);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.I64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
2019-01-15 19:22:24 +02:00
|
|
|
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getTempLocal(Type.i64, false);
|
|
|
|
let tempLocalIndex2 = flow.getAndFreeTempLocal(Type.i64, false).index;
|
2019-01-15 19:22:24 +02:00
|
|
|
let tempLocalIndex1 = tempLocal1.index;
|
|
|
|
|
|
|
|
// (x + (x >> 63)) ^ (x >> 63)
|
|
|
|
ret = module.createBinary(BinaryOp.XorI64,
|
|
|
|
module.createBinary(BinaryOp.AddI64,
|
|
|
|
module.createTeeLocal(
|
|
|
|
tempLocalIndex2,
|
|
|
|
module.createBinary(BinaryOp.ShrI64,
|
|
|
|
module.createTeeLocal(tempLocalIndex1, arg0),
|
|
|
|
module.createI64(63)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
module.createGetLocal(tempLocalIndex1, NativeType.I64)
|
2018-01-10 13:09:05 +01:00
|
|
|
),
|
2019-01-15 19:22:24 +02:00
|
|
|
module.createGetLocal(tempLocalIndex2, NativeType.I64)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
2019-01-15 19:22:24 +02:00
|
|
|
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal1);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
|
|
|
case TypeKind.U32:
|
|
|
|
case TypeKind.U64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.BOOL: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = arg0;
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.AbsF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.AbsF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // void
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.max: { // max<T?>(left: T, right: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], compiler.currentType, ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.I32: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg0, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg1, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.GtI32,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I32),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I32)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
|
|
|
case TypeKind.U32:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.BOOL: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg0, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg1, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.GtU32,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I32),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I32)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.I64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(Type.i64, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(Type.i64, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.GtI64,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I64),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I64)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.U64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(Type.i64, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(Type.i64, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.GtU64,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I64),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I64)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(compiler.options.usizeType, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(compiler.options.usizeType, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.GtI64
|
|
|
|
: BinaryOp.GtI32,
|
2018-01-21 17:52:44 +01:00
|
|
|
module.createGetLocal(tempLocal0.index, compiler.options.nativeSizeType),
|
|
|
|
module.createGetLocal(tempLocal1.index, compiler.options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(compiler.options.usizeType, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(compiler.options.usizeType, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.GtU64
|
|
|
|
: BinaryOp.GtU32,
|
2018-01-21 17:52:44 +01:00
|
|
|
module.createGetLocal(tempLocal0.index, compiler.options.nativeSizeType),
|
|
|
|
module.createGetLocal(tempLocal1.index, compiler.options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.MaxF32, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.MaxF64, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // void
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.min: { // min<T?>(left: T, right: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], compiler.currentType, ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.I32: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg0, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg1, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.LtI32,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I32),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I32)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
|
|
|
case TypeKind.U32:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.BOOL: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg0, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg1, compiler.currentType)
|
|
|
|
);
|
2019-02-06 23:42:43 +01:00
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.LtU32,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I32),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I32)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.I64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(Type.i64, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(Type.i64, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.LtI64,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I64),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I64)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.U64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(Type.i64, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(Type.i64, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
|
|
|
module.createBinary(BinaryOp.LtU64,
|
|
|
|
module.createGetLocal(tempLocal0.index, NativeType.I64),
|
|
|
|
module.createGetLocal(tempLocal1.index, NativeType.I64)
|
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(compiler.options.usizeType, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(compiler.options.usizeType, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.LtI64
|
|
|
|
: BinaryOp.LtI32,
|
2018-01-21 17:52:44 +01:00
|
|
|
module.createGetLocal(tempLocal0.index, compiler.options.nativeSizeType),
|
|
|
|
module.createGetLocal(tempLocal1.index, compiler.options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal0 = flow.getTempLocal(compiler.options.usizeType, false);
|
|
|
|
let tempLocal1 = flow.getAndFreeTempLocal(compiler.options.usizeType, false);
|
|
|
|
flow.freeTempLocal(tempLocal0);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(
|
|
|
|
module.createTeeLocal(tempLocal0.index, arg0),
|
|
|
|
module.createTeeLocal(tempLocal1.index, arg1),
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createBinary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? BinaryOp.LtU64
|
|
|
|
: BinaryOp.LtU32,
|
2018-01-21 17:52:44 +01:00
|
|
|
module.createGetLocal(tempLocal0.index, compiler.options.nativeSizeType),
|
|
|
|
module.createGetLocal(tempLocal1.index, compiler.options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
)
|
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.MinF32, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.MinF64, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // void
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.ceil: { // ceil<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // any integer
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = arg0;
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.CeilF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.CeilF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.floor: { // floor<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // any integer
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = arg0;
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.FloorF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.FloorF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.copysign: { // copysign<T?>(left: T, right: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], compiler.currentType, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-03-12 14:06:39 +01:00
|
|
|
switch (compiler.currentType.kind) { // TODO: does an integer version make sense?
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.CopysignF32, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createBinary(BinaryOp.CopysignF64, arg0, arg1);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.nearest: { // nearest<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // any integer
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = arg0;
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.NearestF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.NearestF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.reinterpret: { // reinterpret<T!>(value: *) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-01-13 01:15:09 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-01-13 01:15:09 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2018-01-13 01:15:09 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
switch (typeArguments[0].kind) {
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I32:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U32: {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f32, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-13 01:15:09 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ReinterpretF32, arg0);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-13 01:15:09 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ReinterpretF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (typeArguments[0].is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-13 01:15:09 +01:00
|
|
|
compiler.currentType = typeArguments[0];
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.ISIZE: {
|
2018-02-25 00:13:39 +01:00
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? Type.f64
|
2018-05-06 00:00:54 +02:00
|
|
|
: Type.f32,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-02-25 00:13:39 +01:00
|
|
|
ret = module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.ReinterpretF64
|
|
|
|
: UnaryOp.ReinterpretF32,
|
|
|
|
arg0
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-13 01:15:09 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ReinterpretI32, arg0);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i64, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-13 01:15:09 +01:00
|
|
|
ret = module.createUnary(UnaryOp.ReinterpretI64, arg0);
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // small integers and void
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-01-13 01:15:09 +01:00
|
|
|
compiler.currentType = typeArguments[0];
|
2018-01-10 13:09:05 +01:00
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.sqrt: { // sqrt<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-03-12 14:06:39 +01:00
|
|
|
switch (compiler.currentType.kind) { // TODO: integer versions (that return f64 or convert)?
|
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.SqrtF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.SqrtF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
// case TypeKind.VOID:
|
2018-03-12 14:06:39 +01:00
|
|
|
default: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.trunc: { // trunc<T?>(value: T) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments && typeArguments.length) {
|
|
|
|
compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
switch (compiler.currentType.kind) {
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2018-03-21 23:27:53 +01:00
|
|
|
if (compiler.currentType.is(TypeFlags.REFERENCE)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall-through
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
default: { // any integer
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = arg0;
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
// TODO: truncate to contextual type directly (if not void etc.)?
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.TruncF32, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnary(UnaryOp.TruncF64, arg0);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2017-12-15 17:23:04 +01:00
|
|
|
// memory access
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.load: { // load<T!>(offset: usize, constantOffset?: usize) -> *
|
2018-01-21 16:34:50 +01:00
|
|
|
if (operands.length < 1 || operands.length > 2) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-24 00:38:49 +01:00
|
|
|
let offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports
|
2018-02-25 00:13:39 +01:00
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
2018-01-21 16:34:50 +01:00
|
|
|
return module.createUnreachable();
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-03-01 19:42:07 +01:00
|
|
|
compiler.currentType = typeArguments[0];
|
2018-02-25 00:13:39 +01:00
|
|
|
return module.createLoad(
|
|
|
|
typeArguments[0].byteSize,
|
|
|
|
typeArguments[0].is(TypeFlags.SIGNED | TypeFlags.INTEGER),
|
|
|
|
arg0,
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
contextualType.is(TypeFlags.INTEGER) &&
|
2018-03-01 19:42:07 +01:00
|
|
|
contextualType.size > typeArguments[0].size
|
2018-01-23 15:44:25 +01:00
|
|
|
? (compiler.currentType = contextualType).toNativeType()
|
2018-02-25 00:13:39 +01:00
|
|
|
: (compiler.currentType = typeArguments[0]).toNativeType(),
|
|
|
|
offset
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.store: { // store<T!>(offset: usize, value: *, constantOffset?: usize) -> void
|
2017-12-05 01:45:15 +01:00
|
|
|
compiler.currentType = Type.void;
|
2018-01-21 16:34:50 +01:00
|
|
|
if (operands.length < 2 || operands.length > 3) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 2) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-01-23 15:44:25 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2018-01-23 15:44:25 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-02-25 00:13:39 +01:00
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
typeArguments[0],
|
2018-01-23 15:44:25 +01:00
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
2018-05-06 00:00:54 +02:00
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
2018-01-23 15:44:25 +01:00
|
|
|
);
|
2018-03-24 00:38:49 +01:00
|
|
|
let type: Type;
|
2018-02-25 00:13:39 +01:00
|
|
|
if (
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
2018-05-06 00:00:54 +02:00
|
|
|
(
|
|
|
|
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
|
|
|
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
|
|
|
)
|
2018-02-25 00:13:39 +01:00
|
|
|
) {
|
|
|
|
arg1 = compiler.convertExpression(
|
|
|
|
arg1,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
2018-05-06 00:00:54 +02:00
|
|
|
WrapMode.NONE, // still clears garbage bits
|
2018-02-25 00:13:39 +01:00
|
|
|
operands[1]
|
|
|
|
);
|
2018-01-23 15:44:25 +01:00
|
|
|
type = typeArguments[0];
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-01-23 15:44:25 +01:00
|
|
|
type = compiler.currentType;
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-03-24 00:38:49 +01:00
|
|
|
let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports
|
2018-02-25 00:13:39 +01:00
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
2018-01-21 16:34:50 +01:00
|
|
|
return module.createUnreachable();
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
compiler.currentType = Type.void;
|
2018-01-23 15:44:25 +01:00
|
|
|
return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_load: { // load<T!>(offset: usize, constantOffset?: usize) -> *
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
if (operands.length < 1 || operands.length > 2) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
let offset = operands.length == 2 ? evaluateConstantOffset(compiler, operands[1]) : 0; // reports
|
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
compiler.currentType = typeArguments[0];
|
|
|
|
return module.createAtomicLoad(
|
|
|
|
typeArguments[0].byteSize,
|
|
|
|
arg0,
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
contextualType.is(TypeFlags.INTEGER) &&
|
|
|
|
contextualType.size > typeArguments[0].size
|
|
|
|
? (compiler.currentType = contextualType).toNativeType()
|
|
|
|
: (compiler.currentType = typeArguments[0]).toNativeType(),
|
|
|
|
offset
|
|
|
|
);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_store: { // store<T!>(offset: usize, value: *, constantOffset?: usize) -> void
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
compiler.currentType = Type.void;
|
|
|
|
if (operands.length < 2 || operands.length > 3) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 2) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
typeArguments[0],
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
let type: Type;
|
|
|
|
if (
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
(
|
|
|
|
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
|
|
|
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
arg1 = compiler.convertExpression(
|
|
|
|
arg1,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[1]
|
|
|
|
);
|
|
|
|
type = typeArguments[0];
|
|
|
|
} else {
|
|
|
|
type = compiler.currentType;
|
|
|
|
}
|
|
|
|
let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports
|
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
return module.createAtomicStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_add: // add<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
|
|
|
case BuiltinSymbols.atomic_sub: // sub<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
|
|
|
case BuiltinSymbols.atomic_and: // and<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
|
|
|
case BuiltinSymbols.atomic_or: // or<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
|
|
|
case BuiltinSymbols.atomic_xor: // xor<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
|
|
|
case BuiltinSymbols.atomic_xchg: // xchg<T!>(ptr: usize, value: T, constantOffset?: usize): T;
|
2019-02-07 15:25:49 +01:00
|
|
|
{
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
if (operands.length < 2 || operands.length > 3) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 2) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
typeArguments[0],
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
|
|
|
|
let type: Type;
|
|
|
|
if (
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
(
|
|
|
|
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
|
|
|
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
arg1 = compiler.convertExpression(
|
|
|
|
arg1,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[1]
|
|
|
|
);
|
|
|
|
type = typeArguments[0];
|
|
|
|
} else {
|
|
|
|
type = compiler.currentType;
|
|
|
|
}
|
|
|
|
|
|
|
|
let offset = operands.length == 3 ? evaluateConstantOffset(compiler, operands[2]) : 0; // reports
|
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let RMWOp: AtomicRMWOp | null = null;
|
2019-02-21 00:11:22 +01:00
|
|
|
switch (prototype.internalName) {
|
|
|
|
case BuiltinSymbols.atomic_add: { RMWOp = AtomicRMWOp.Add; break; }
|
|
|
|
case BuiltinSymbols.atomic_sub: { RMWOp = AtomicRMWOp.Sub; break; }
|
|
|
|
case BuiltinSymbols.atomic_and: { RMWOp = AtomicRMWOp.And; break; }
|
|
|
|
case BuiltinSymbols.atomic_or: { RMWOp = AtomicRMWOp.Or; break; }
|
|
|
|
case BuiltinSymbols.atomic_xor: { RMWOp = AtomicRMWOp.Xor; break; }
|
|
|
|
case BuiltinSymbols.atomic_xchg: { RMWOp = AtomicRMWOp.Xchg; break; }
|
2019-02-07 15:25:49 +01:00
|
|
|
}
|
|
|
|
compiler.currentType = typeArguments[0];
|
|
|
|
if (RMWOp !== null) {
|
|
|
|
return module.createAtomicRMW(
|
|
|
|
RMWOp, typeArguments[0].byteSize, offset, arg0, arg1, type.toNativeType()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_cmpxchg: { // cmpxchg<T!>(ptr: usize, expected: T, replacement: T, cOff?: usize): T
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
if (operands.length < 3 || operands.length > 4) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length < 3) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
typeArguments[0],
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg2 = compiler.compileExpression(
|
|
|
|
operands[2],
|
|
|
|
typeArguments[0],
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
|
|
|
|
let type: Type;
|
|
|
|
if (
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
(
|
|
|
|
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
|
|
|
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
arg1 = compiler.convertExpression(
|
|
|
|
arg1,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[1]
|
|
|
|
);
|
|
|
|
arg2 = compiler.convertExpression(
|
|
|
|
arg2,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[2]
|
|
|
|
);
|
|
|
|
type = typeArguments[0];
|
|
|
|
} else {
|
|
|
|
type = compiler.currentType;
|
|
|
|
}
|
|
|
|
|
|
|
|
let offset = operands.length == 4 ? evaluateConstantOffset(compiler, operands[3]) : 0; // reports
|
|
|
|
if (offset < 0) { // reported in evaluateConstantOffset
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
compiler.currentType = typeArguments[0];
|
|
|
|
return module.createAtomicCmpxchg(
|
|
|
|
typeArguments[0].byteSize, offset, arg0, arg1, arg2, type.toNativeType()
|
|
|
|
);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_wait: { // wait<T!>(ptr: usize, expected:T, timeout: i64): i32;
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
let hasError = typeArguments == null;
|
|
|
|
if (operands.length != 3) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
hasError = true;
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
hasError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!typeArguments || hasError) {
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
typeArguments[0],
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER)
|
|
|
|
? ConversionKind.NONE // no need to convert to small int (but now might result in a float)
|
|
|
|
: ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg2 = compiler.compileExpression(
|
|
|
|
operands[2],
|
|
|
|
Type.i64,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
|
|
|
|
let type: Type = typeArguments[0];
|
|
|
|
if (
|
|
|
|
typeArguments[0].is(TypeFlags.INTEGER) &&
|
|
|
|
(
|
|
|
|
!compiler.currentType.is(TypeFlags.INTEGER) || // float to int
|
|
|
|
compiler.currentType.size < typeArguments[0].size // int to larger int (clear garbage bits)
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
arg1 = compiler.convertExpression(
|
|
|
|
arg1,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[1]
|
|
|
|
);
|
|
|
|
arg2 = compiler.convertExpression(
|
|
|
|
arg2,
|
|
|
|
compiler.currentType, typeArguments[0],
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE, // still clears garbage bits
|
|
|
|
operands[2]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return module.createAtomicWait(
|
|
|
|
arg0, arg1, arg2, type.toNativeType()
|
|
|
|
);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.atomic_notify: { // notify<T!>(ptr: usize, count: u32): u32;
|
2019-02-07 18:21:09 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.THREADS)) break;
|
2019-02-07 15:25:49 +01:00
|
|
|
let hasError = typeArguments == null;
|
|
|
|
if (operands.length != 2) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
hasError = true;
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
hasError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!typeArguments || hasError) {
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
Type.i32,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
|
|
|
|
return module.createAtomicWake(
|
|
|
|
arg0, arg1
|
|
|
|
);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.sizeof: { // sizeof<T!>() -> usize
|
2018-01-21 17:52:44 +01:00
|
|
|
compiler.currentType = compiler.options.usizeType;
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 0) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "0", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-03-24 00:38:49 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let byteSize = (<Type[]>typeArguments)[0].byteSize;
|
|
|
|
if (compiler.options.isWasm64) {
|
|
|
|
// implicitly wrap if contextual type is a 32-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) {
|
|
|
|
compiler.currentType = Type.u32;
|
|
|
|
ret = module.createI32(byteSize);
|
|
|
|
} else {
|
|
|
|
ret = module.createI64(byteSize, 0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// implicitly extend if contextual type is a 64-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) {
|
|
|
|
compiler.currentType = Type.u64;
|
|
|
|
ret = module.createI64(byteSize, 0);
|
|
|
|
} else {
|
|
|
|
ret = module.createI32(byteSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.alignof: { // alignof<T!>() -> usize
|
2018-04-02 19:05:26 +02:00
|
|
|
compiler.currentType = compiler.options.usizeType;
|
|
|
|
if (operands.length != 0) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "0", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2018-04-11 23:35:19 +02:00
|
|
|
return module.createUnreachable();
|
2018-04-02 19:05:26 +02:00
|
|
|
}
|
|
|
|
let byteSize = (<Type[]>typeArguments)[0].byteSize;
|
|
|
|
let alignLog2: i32;
|
|
|
|
switch (byteSize) {
|
|
|
|
case 1: { alignLog2 = 0; break; }
|
|
|
|
case 2: { alignLog2 = 1; break; }
|
|
|
|
case 4: { alignLog2 = 2; break; }
|
|
|
|
case 8: { alignLog2 = 3; break; }
|
2019-02-21 00:11:22 +01:00
|
|
|
default: { assert(false, "unexected byte size"); return module.createUnreachable(); }
|
2018-04-02 19:05:26 +02:00
|
|
|
}
|
|
|
|
if (compiler.options.isWasm64) {
|
|
|
|
// implicitly wrap if contextual type is a 32-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) {
|
|
|
|
compiler.currentType = Type.u32;
|
|
|
|
ret = module.createI32(alignLog2);
|
|
|
|
} else {
|
|
|
|
ret = module.createI64(alignLog2, 0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// implicitly extend if contextual type is a 64-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) {
|
|
|
|
compiler.currentType = Type.u64;
|
|
|
|
ret = module.createI64(alignLog2, 0);
|
|
|
|
} else {
|
|
|
|
ret = module.createI32(alignLog2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.offsetof: { // offsetof<T!>(fieldName?: string) -> usize
|
2018-03-24 00:38:49 +01:00
|
|
|
compiler.currentType = compiler.options.usizeType;
|
|
|
|
if (operands.length > 1) {
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
2018-03-24 00:38:49 +01:00
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-03-24 00:38:49 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
2018-03-24 00:38:49 +01:00
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-03-24 00:38:49 +01:00
|
|
|
let classType = typeArguments[0].classReference;
|
|
|
|
if (!classType) {
|
|
|
|
compiler.error( // TODO: better error
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let offset: i32;
|
|
|
|
if (operands.length) {
|
|
|
|
if (
|
|
|
|
operands[0].kind != NodeKind.LITERAL ||
|
|
|
|
(<LiteralExpression>operands[0]).literalKind != LiteralKind.STRING
|
|
|
|
) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.String_literal_expected,
|
|
|
|
operands[0].range
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let fieldName = (<StringLiteralExpression>operands[0]).value;
|
|
|
|
let field = classType.members ? classType.members.get(fieldName) : null;
|
|
|
|
if (!(field && field.kind == ElementKind.FIELD)) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_has_no_property_1,
|
|
|
|
operands[0].range, classType.internalName, fieldName
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
offset = (<Field>field).memoryOffset;
|
|
|
|
} else {
|
|
|
|
offset = classType.currentMemoryOffset;
|
|
|
|
}
|
|
|
|
if (compiler.options.isWasm64) {
|
|
|
|
// implicitly wrap if contextual type is a 32-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) {
|
|
|
|
compiler.currentType = Type.u32;
|
|
|
|
return module.createI32(offset);
|
|
|
|
} else {
|
|
|
|
return module.createI64(offset);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// implicitly extend if contextual type is a 64-bit integer
|
|
|
|
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) {
|
|
|
|
compiler.currentType = Type.u64;
|
|
|
|
return module.createI64(offset);
|
|
|
|
} else {
|
|
|
|
return module.createI32(offset);
|
|
|
|
}
|
|
|
|
}
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
|
|
|
|
// control flow
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.select: { // select<T?>(ifTrue: T, ifFalse: T, condition: bool) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 3) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpressionRetainType(operands[0], Type.i32, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-03-24 00:38:49 +01:00
|
|
|
let type = compiler.currentType;
|
2018-05-06 00:00:54 +02:00
|
|
|
arg1 = compiler.compileExpression(operands[1], type, ConversionKind.IMPLICIT, WrapMode.NONE);
|
|
|
|
arg2 = compiler.makeIsTrueish(
|
|
|
|
compiler.compileExpressionRetainType(operands[2], Type.bool, WrapMode.NONE),
|
|
|
|
compiler.currentType
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = type;
|
|
|
|
switch (compiler.currentType.kind) {
|
2018-05-06 00:00:54 +02:00
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
|
|
|
case TypeKind.BOOL: {
|
|
|
|
ret = module.createSelect(arg0, arg1, arg2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: { // any other value type
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createSelect(arg0, arg1, arg2);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createUnreachable();
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.unreachable: { // unreachable() -> *
|
2018-02-25 00:13:39 +01:00
|
|
|
if (operands.length != 0) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "0", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-15 17:23:04 +01:00
|
|
|
|
|
|
|
// host operations
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.memory_size: { // memory.size() -> i32
|
2017-12-05 01:45:15 +01:00
|
|
|
compiler.currentType = Type.i32;
|
2018-02-25 00:13:39 +01:00
|
|
|
if (operands.length != 0) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "0", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createHost(HostOp.CurrentMemory);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.memory_grow: { // memory.grow(pages: i32) -> i32
|
2017-12-05 01:45:15 +01:00
|
|
|
compiler.currentType = Type.i32;
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "0", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
arg0 = module.createUnreachable();
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], Type.i32, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createHost(HostOp.GrowMemory, null, [ arg0 ]);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
// see: https://github.com/WebAssembly/bulk-memory-operations
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.memory_copy: { // memory.copy(dest: usize, src: usize: n: usize) -> void
|
2019-02-07 11:40:23 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) {
|
|
|
|
let instance = compiler.resolver.resolveFunction(prototype, null); // reports
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
if (!instance) return module.createUnreachable();
|
|
|
|
return compiler.compileCallDirect(instance, operands, reportNode);
|
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 3) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.void;
|
2017-12-19 17:49:15 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2019-02-07 11:40:23 +01:00
|
|
|
let usizeType = compiler.options.usizeType;
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
2019-02-07 11:40:23 +01:00
|
|
|
usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
2019-02-07 11:40:23 +01:00
|
|
|
usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg2 = compiler.compileExpression(
|
|
|
|
operands[2],
|
2019-02-07 11:40:23 +01:00
|
|
|
usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2017-12-19 17:49:15 +01:00
|
|
|
compiler.currentType = Type.void;
|
2019-02-07 11:40:23 +01:00
|
|
|
return module.createMemoryCopy(arg0, arg1, arg2);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.memory_fill: { // memory.fill(dest: usize, value: u8, n: usize) -> void
|
2019-02-07 11:40:23 +01:00
|
|
|
if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) {
|
|
|
|
let instance = compiler.resolver.resolveFunction(prototype, null); // reports
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
if (!instance) return module.createUnreachable();
|
|
|
|
return compiler.compileCallDirect(instance, operands, reportNode);
|
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 3) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "3", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.void;
|
2017-12-19 17:49:15 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2019-02-07 11:40:23 +01:00
|
|
|
let usizeType = compiler.options.usizeType;
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(
|
|
|
|
operands[0],
|
2019-02-07 11:40:23 +01:00
|
|
|
usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg1 = compiler.compileExpression(
|
|
|
|
operands[1],
|
|
|
|
Type.u32,
|
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
|
|
|
arg2 = compiler.compileExpression(
|
|
|
|
operands[2],
|
2019-02-07 11:40:23 +01:00
|
|
|
usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.IMPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2017-12-19 17:49:15 +01:00
|
|
|
compiler.currentType = Type.void;
|
2019-02-07 11:40:23 +01:00
|
|
|
return module.createMemoryFill(arg0, arg1, arg2);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2017-12-19 17:49:15 +01:00
|
|
|
|
2018-01-10 13:09:05 +01:00
|
|
|
// other
|
2017-12-08 04:03:44 +01:00
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.changetype: { // changetype<T!>(value: *) -> T
|
2018-01-10 13:09:05 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-15 17:23:04 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = typeArguments[0];
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpressionRetainType(
|
2018-02-25 00:13:39 +01:00
|
|
|
operands[0],
|
2018-05-11 16:31:56 +02:00
|
|
|
typeArguments[0],
|
2018-05-06 00:00:54 +02:00
|
|
|
WrapMode.NONE
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = typeArguments[0];
|
2018-05-11 16:31:56 +02:00
|
|
|
if (compiler.currentType.size != typeArguments[0].size) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-02-02 03:07:54 +01:00
|
|
|
// if (reportNode.range.source.sourceKind != SourceKind.STDLIB)
|
|
|
|
// compiler.warning(DiagnosticCode.Operation_is_unsafe, reportNode.range);
|
2018-01-10 13:09:05 +01:00
|
|
|
return arg0; // any usize to any usize
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.assert: { // assert<T?>(isTrueish: T, message?: string) -> T with T != null
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length < 1 || operands.length > 2) {
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0].nonNullableType;
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (operands.length < 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
} else if (operands.length > 2) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "2", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
if (typeArguments) {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0].nonNullableType;
|
2018-01-10 13:09:05 +01:00
|
|
|
if (typeArguments.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
arg0 = compiler.compileExpressionRetainType(operands[0], Type.bool, WrapMode.WRAP);
|
2018-02-25 00:13:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
|
2018-03-24 00:38:49 +01:00
|
|
|
let type = compiler.currentType;
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = type.nonNullableType;
|
|
|
|
|
|
|
|
// just return ifTrueish if assertions are disabled, or simplify if dropped anyway
|
|
|
|
if (compiler.options.noAssert) {
|
|
|
|
if (contextualType == Type.void) {
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
return module.createNop();
|
|
|
|
}
|
2017-12-08 04:03:44 +01:00
|
|
|
return arg0;
|
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
|
2018-03-13 02:32:10 +01:00
|
|
|
let abort = compileAbort(compiler, operands.length == 2 ? operands[1] : null, reportNode);
|
2018-01-27 17:02:52 +01:00
|
|
|
|
2018-01-27 16:23:00 +01:00
|
|
|
compiler.currentType = type.nonNullableType;
|
|
|
|
|
2018-01-10 13:09:05 +01:00
|
|
|
if (contextualType == Type.void) { // simplify if dropped anyway
|
|
|
|
switch (compiler.currentType.kind) {
|
2018-03-12 14:06:39 +01:00
|
|
|
default: { // any integer up to 32-bits incl. bool
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createUnary(UnaryOp.EqzI32,
|
|
|
|
arg0
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createUnary(UnaryOp.EqzI64,
|
|
|
|
arg0
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.ISIZE:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.EqzI64
|
|
|
|
: UnaryOp.EqzI32,
|
2018-01-10 13:09:05 +01:00
|
|
|
arg0
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
// TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`?
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.F32: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createBinary(BinaryOp.EqF32,
|
|
|
|
arg0,
|
|
|
|
module.createF32(0)
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createBinary(BinaryOp.EqF64,
|
|
|
|
arg0,
|
|
|
|
module.createF64(0)
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-27 16:23:00 +01:00
|
|
|
ret = abort;
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
} else {
|
|
|
|
switch (compiler.currentType.kind) {
|
2018-05-06 00:00:54 +02:00
|
|
|
case TypeKind.I8:
|
|
|
|
case TypeKind.I16:
|
|
|
|
case TypeKind.U8:
|
|
|
|
case TypeKind.U16:
|
|
|
|
case TypeKind.BOOL: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
|
|
|
let tempLocal = flow.getAndFreeTempLocal(
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.currentType,
|
|
|
|
!flow.canOverflow(arg0, compiler.currentType)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
2018-05-06 00:00:54 +02:00
|
|
|
module.createTeeLocal(tempLocal.index, arg0),
|
|
|
|
module.createGetLocal(tempLocal.index, NativeType.I32),
|
|
|
|
abort
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TypeKind.I32:
|
|
|
|
case TypeKind.U32:
|
|
|
|
default: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal = compiler.currentFlow.getAndFreeTempLocal(Type.i32, false);
|
2018-05-06 00:00:54 +02:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createTeeLocal(tempLocal.index, arg0),
|
|
|
|
module.createGetLocal(tempLocal.index, NativeType.I32),
|
|
|
|
abort
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.I64:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.U64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal = compiler.currentFlow.getAndFreeTempLocal(Type.i64, false);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createUnary(UnaryOp.EqzI64,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createTeeLocal(tempLocal.index, arg0)
|
2018-01-10 13:09:05 +01:00
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createGetLocal(tempLocal.index, NativeType.I64)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
case TypeKind.ISIZE:
|
2018-03-12 14:06:39 +01:00
|
|
|
case TypeKind.USIZE: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal = compiler.currentFlow.getAndFreeTempLocal(compiler.options.usizeType, false);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
2018-02-25 00:13:39 +01:00
|
|
|
module.createUnary(
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? UnaryOp.EqzI64
|
|
|
|
: UnaryOp.EqzI32,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createTeeLocal(tempLocal.index, arg0)
|
2018-01-10 13:09:05 +01:00
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createGetLocal(tempLocal.index, compiler.options.nativeSizeType)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F32: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal = compiler.currentFlow.getAndFreeTempLocal(Type.f32, false);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createBinary(BinaryOp.EqF32,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createTeeLocal(tempLocal.index, arg0),
|
2018-01-10 13:09:05 +01:00
|
|
|
module.createF32(0)
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createGetLocal(tempLocal.index, NativeType.F32)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.F64: {
|
2019-02-06 23:42:43 +01:00
|
|
|
let tempLocal = compiler.currentFlow.getAndFreeTempLocal(Type.f64, false);
|
2018-01-10 13:09:05 +01:00
|
|
|
ret = module.createIf(
|
|
|
|
module.createBinary(BinaryOp.EqF64,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createTeeLocal(tempLocal.index, arg0),
|
2018-01-10 13:09:05 +01:00
|
|
|
module.createF64(0)
|
|
|
|
),
|
2018-01-27 16:23:00 +01:00
|
|
|
abort,
|
2018-03-24 00:38:49 +01:00
|
|
|
module.createGetLocal(tempLocal.index, NativeType.F64)
|
2018-01-10 13:09:05 +01:00
|
|
|
);
|
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
|
|
|
case TypeKind.VOID: {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
2018-01-27 16:23:00 +01:00
|
|
|
ret = abort;
|
2018-01-10 13:09:05 +01:00
|
|
|
break;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2017-12-14 11:55:35 +01:00
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
return ret;
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.unchecked: {
|
2018-04-25 05:04:35 +02:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2019-02-06 23:42:43 +01:00
|
|
|
let flow = compiler.currentFlow;
|
2018-04-25 05:04:35 +02:00
|
|
|
flow.set(FlowFlags.UNCHECKED_CONTEXT);
|
2018-05-06 00:00:54 +02:00
|
|
|
ret = compiler.compileExpressionRetainType(operands[0], contextualType, WrapMode.NONE);
|
2018-04-25 05:04:35 +02:00
|
|
|
flow.unset(FlowFlags.UNCHECKED_CONTEXT);
|
|
|
|
return ret;
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.call_indirect: { // call_indirect<T?>(target: Function | u32, ...args: *[]) -> T
|
2018-05-25 15:59:17 +02:00
|
|
|
if (operands.length < 1) {
|
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_at_least_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let returnType: Type;
|
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length != 1) {
|
|
|
|
if (typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
returnType = typeArguments[0];
|
|
|
|
} else {
|
|
|
|
returnType = contextualType;
|
|
|
|
}
|
|
|
|
arg0 = compiler.compileExpressionRetainType(operands[0], Type.u32, WrapMode.NONE);
|
|
|
|
if (compiler.currentType.kind != TypeKind.U32) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
operands[0].range
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let numOperands = operands.length - 1;
|
|
|
|
let operandExprs = new Array<ExpressionRef>(numOperands);
|
|
|
|
let signatureParts = new Array<string>(numOperands + 1);
|
|
|
|
let nativeReturnType = returnType.toNativeType();
|
|
|
|
let nativeParamTypes = new Array<NativeType>(numOperands);
|
|
|
|
for (let i = 0; i < numOperands; ++i) {
|
|
|
|
operandExprs[i] = compiler.compileExpressionRetainType(operands[1 + i], Type.i32, WrapMode.NONE);
|
|
|
|
let operandType = compiler.currentType;
|
|
|
|
signatureParts[i] = operandType.toSignatureString();
|
|
|
|
nativeParamTypes[i] = operandType.toNativeType();
|
|
|
|
}
|
|
|
|
signatureParts[numOperands] = returnType.toSignatureString();
|
|
|
|
let typeName = signatureParts.join("");
|
|
|
|
let typeRef = module.getFunctionTypeBySignature(nativeReturnType, nativeParamTypes);
|
|
|
|
if (!typeRef) typeRef = module.addFunctionType(typeName, nativeReturnType, nativeParamTypes);
|
|
|
|
compiler.currentType = returnType;
|
|
|
|
// of course this can easily result in a 'RuntimeError: function signature mismatch' trap and
|
|
|
|
// thus must be used with care. it exists because it *might* be useful in specific scenarios.
|
|
|
|
return module.createCallIndirect(arg0, operandExprs, typeName);
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.instantiate: {
|
2018-11-29 15:28:08 +01:00
|
|
|
if (!(typeArguments && typeArguments.length == 1)) {
|
|
|
|
if (typeArguments && typeArguments.length) compiler.currentType = typeArguments[0];
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let classInstance = typeArguments[0].classReference;
|
|
|
|
if (!classInstance) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Operation_not_supported,
|
|
|
|
reportNode.range
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
return compiler.compileInstantiate(classInstance, operands, reportNode);
|
|
|
|
}
|
2017-12-05 15:06:44 +01:00
|
|
|
|
2018-07-18 23:49:32 +02:00
|
|
|
// user-defined diagnostic macros
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.ERROR: {
|
2018-07-18 23:49:32 +02:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.User_defined_0,
|
|
|
|
reportNode.range, (operands.length ? operands[0] : reportNode).range.toString()
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.WARNING: {
|
2018-07-18 23:49:32 +02:00
|
|
|
compiler.warning(
|
|
|
|
DiagnosticCode.User_defined_0,
|
|
|
|
reportNode.range, (operands.length ? operands[0] : reportNode).range.toString()
|
|
|
|
);
|
|
|
|
return module.createNop();
|
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.INFO: {
|
2018-07-18 23:49:32 +02:00
|
|
|
compiler.info(
|
|
|
|
DiagnosticCode.User_defined_0,
|
|
|
|
reportNode.range, (operands.length ? operands[0] : reportNode).range.toString()
|
|
|
|
);
|
|
|
|
return module.createNop();
|
|
|
|
}
|
|
|
|
|
2017-12-15 17:23:04 +01:00
|
|
|
// conversions
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i8: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.i8;
|
2017-12-12 01:35:48 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.i8,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i16: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.i16;
|
2017-12-12 01:35:48 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.i16,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i32: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.i32;
|
2017-12-12 01:35:48 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.i32,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i64: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.i64;
|
2017-12-12 01:35:48 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.i64,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.isize: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
compiler.currentType = compiler.options.isWasm64
|
|
|
|
? Type.isize64
|
|
|
|
: Type.isize32;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? Type.isize64
|
|
|
|
: Type.isize32,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.u8: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.u8;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.u8,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.u16: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.u16;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.u16,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.u32: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.u32;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.u32,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.u64: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.u64;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.u64,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.usize: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-21 17:52:44 +01:00
|
|
|
compiler.currentType = compiler.options.usizeType;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
compiler.options.usizeType,
|
2018-05-06 00:00:54 +02:00
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.bool: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.bool;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.bool,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.f32: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.f32;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.f32,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.f64: {
|
2018-02-25 00:13:39 +01:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
2018-01-10 13:09:05 +01:00
|
|
|
if (operands.length != 1) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
2018-01-10 13:09:05 +01:00
|
|
|
compiler.currentType = Type.f64;
|
2017-12-15 17:23:04 +01:00
|
|
|
return module.createUnreachable();
|
2018-01-10 13:09:05 +01:00
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
return compiler.compileExpression(
|
|
|
|
operands[0],
|
|
|
|
Type.f64,
|
|
|
|
ConversionKind.EXPLICIT,
|
|
|
|
WrapMode.NONE
|
|
|
|
);
|
2018-03-12 14:06:39 +01:00
|
|
|
}
|
2019-02-21 00:11:22 +01:00
|
|
|
// TODO: v128
|
2018-07-18 23:49:32 +02:00
|
|
|
|
|
|
|
// gc
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.iterateRoots: {
|
2018-07-18 23:49:32 +02:00
|
|
|
if (typeArguments) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (operands.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
|
|
|
let expr = compiler.compileExpressionRetainType(operands[0], Type.u32, WrapMode.NONE);
|
|
|
|
let type = compiler.currentType;
|
|
|
|
let signatureReference = type.signatureReference;
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
if (
|
|
|
|
!type.is(TypeFlags.REFERENCE) ||
|
|
|
|
!signatureReference ||
|
|
|
|
signatureReference.parameterTypes.length != 1 ||
|
|
|
|
signatureReference.parameterTypes[0] != compiler.options.usizeType
|
|
|
|
) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
|
|
|
|
reportNode.range, type.toString(), "(ref: usize) => void"
|
|
|
|
);
|
|
|
|
return module.createUnreachable();
|
|
|
|
}
|
2018-07-20 16:49:27 +02:00
|
|
|
compiler.currentType = Type.void;
|
2018-07-20 20:32:25 +02:00
|
|
|
// just emit a call even if the function doesn't yet exist
|
|
|
|
compiler.needsIterateRoots = true;
|
|
|
|
return module.createCall("~iterateRoots", [ expr ], NativeType.None);
|
2018-07-18 23:49:32 +02:00
|
|
|
}
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-04-27 19:12:25 +02:00
|
|
|
var expr = deferASMCall(compiler, prototype, operands, contextualType, reportNode);
|
|
|
|
if (expr) {
|
|
|
|
if (typeArguments && typeArguments.length) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Type_0_is_not_generic,
|
|
|
|
reportNode.range, prototype.internalName
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return expr;
|
|
|
|
}
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
2019-02-07 18:21:09 +01:00
|
|
|
DiagnosticCode.Cannot_find_name_0,
|
|
|
|
reportNode.expression.range, prototype.internalName
|
2018-02-25 00:13:39 +01:00
|
|
|
);
|
2018-01-05 01:55:59 +01:00
|
|
|
return module.createUnreachable();
|
2017-12-05 01:45:15 +01:00
|
|
|
}
|
2018-01-19 16:13:14 +01:00
|
|
|
|
2018-04-27 19:12:25 +02:00
|
|
|
/** Defers an inline-assembler-like call to a built-in function. */
|
|
|
|
function deferASMCall(
|
|
|
|
compiler: Compiler,
|
|
|
|
prototype: FunctionPrototype,
|
|
|
|
operands: Expression[],
|
|
|
|
contextualType: Type,
|
2019-02-07 18:21:09 +01:00
|
|
|
reportNode: CallExpression
|
2018-04-27 19:12:25 +02:00
|
|
|
): ExpressionRef {
|
2019-02-07 18:21:09 +01:00
|
|
|
/* tslint:disable:max-line-length */
|
2018-04-27 19:12:25 +02:00
|
|
|
switch (prototype.internalName) {
|
|
|
|
|
|
|
|
// TODO: Operators can't be just deferred (don't have a corresponding generic built-in)
|
|
|
|
// add, sub, mul, div_s, div_u, rem_s, rem_u
|
|
|
|
// and, or, xor, shl, shr_u, shr_s
|
|
|
|
// eq, eqz, ne, lt_s, lt_u, le_s, le_u, gt_s, gt_u, ge_s, ge_u
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i32_clz: return deferASM(BuiltinSymbols.clz, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_clz: return deferASM(BuiltinSymbols.clz, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_ctz: return deferASM(BuiltinSymbols.ctz, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_ctz: return deferASM(BuiltinSymbols.ctz, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_popcnt: return deferASM(BuiltinSymbols.popcnt, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_popcnt: return deferASM(BuiltinSymbols.popcnt, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_rotl: return deferASM(BuiltinSymbols.rotl, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_rotl: return deferASM(BuiltinSymbols.rotl, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_rotr: return deferASM(BuiltinSymbols.rotr, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_rotr: return deferASM(BuiltinSymbols.rotr, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_abs: return deferASM(BuiltinSymbols.abs, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_abs: return deferASM(BuiltinSymbols.abs, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_max: return deferASM(BuiltinSymbols.max, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_max: return deferASM(BuiltinSymbols.max, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_min: return deferASM(BuiltinSymbols.min, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_min: return deferASM(BuiltinSymbols.min, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_ceil: return deferASM(BuiltinSymbols.ceil, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_ceil: return deferASM(BuiltinSymbols.ceil, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_floor: return deferASM(BuiltinSymbols.floor, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_floor: return deferASM(BuiltinSymbols.floor, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_copysign: return deferASM(BuiltinSymbols.copysign, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_copysign: return deferASM(BuiltinSymbols.copysign, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_nearest: return deferASM(BuiltinSymbols.nearest, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_nearest: return deferASM(BuiltinSymbols.nearest, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_reinterpret_f32: return deferASM(BuiltinSymbols.reinterpret, compiler, Type.i32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_reinterpret_f64: return deferASM(BuiltinSymbols.reinterpret, compiler, Type.i64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_reinterpret_i32: return deferASM(BuiltinSymbols.reinterpret, compiler, Type.f32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_reinterpret_i64: return deferASM(BuiltinSymbols.reinterpret, compiler, Type.f64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_sqrt: return deferASM(BuiltinSymbols.sqrt, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_sqrt: return deferASM(BuiltinSymbols.sqrt, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_trunc: return deferASM(BuiltinSymbols.trunc, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_trunc: return deferASM(BuiltinSymbols.trunc, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_load8_s: return deferASM(BuiltinSymbols.load, compiler, Type.i8, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_load8_u: return deferASM(BuiltinSymbols.load, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_load16_s: return deferASM(BuiltinSymbols.load, compiler, Type.i16, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_load16_u: return deferASM(BuiltinSymbols.load, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_load: return deferASM(BuiltinSymbols.load, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load8_s: return deferASM(BuiltinSymbols.load, compiler, Type.i8, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load8_u: return deferASM(BuiltinSymbols.load, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load16_s: return deferASM(BuiltinSymbols.load, compiler, Type.i16, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load16_u: return deferASM(BuiltinSymbols.load, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load32_s: return deferASM(BuiltinSymbols.load, compiler, Type.i32, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load32_u: return deferASM(BuiltinSymbols.load, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_load: return deferASM(BuiltinSymbols.load, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_load: return deferASM(BuiltinSymbols.load, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_load: return deferASM(BuiltinSymbols.load, compiler, Type.f64, operands, Type.f64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_store8: return deferASM(BuiltinSymbols.store, compiler, Type.i8, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_store16: return deferASM(BuiltinSymbols.store, compiler, Type.i16, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_store: return deferASM(BuiltinSymbols.store, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_store8: return deferASM(BuiltinSymbols.store, compiler, Type.i8, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_store16: return deferASM(BuiltinSymbols.store, compiler, Type.i16, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_store32: return deferASM(BuiltinSymbols.store, compiler, Type.i32, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_store: return deferASM(BuiltinSymbols.store, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.f32_store: return deferASM(BuiltinSymbols.store, compiler, Type.f32, operands, Type.f32, reportNode);
|
|
|
|
case BuiltinSymbols.f64_store: return deferASM(BuiltinSymbols.store, compiler, Type.f64, operands, Type.f64, reportNode);
|
2018-04-27 19:12:25 +02:00
|
|
|
}
|
2019-02-07 18:21:09 +01:00
|
|
|
if (compiler.options.hasFeature(Feature.THREADS)) {
|
|
|
|
switch (prototype.internalName) {
|
2019-02-21 00:11:22 +01:00
|
|
|
case BuiltinSymbols.i32_atomic_load8_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_load16_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_load: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_load8_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_load16_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_load32_u: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_load: return deferASM(BuiltinSymbols.atomic_load, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_store8: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i8, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_store16: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i16, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_store: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i32, operands, Type.i32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_store8: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i8, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_store16: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i16, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_store32: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i32, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_store: return deferASM(BuiltinSymbols.atomic_store, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_add: return deferASM(BuiltinSymbols.atomic_add, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_sub: return deferASM(BuiltinSymbols.atomic_sub, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_and: return deferASM(BuiltinSymbols.atomic_and, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u16, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_or: return deferASM(BuiltinSymbols.atomic_or, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_xor: return deferASM(BuiltinSymbols.atomic_xor, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_xchg: return deferASM(BuiltinSymbols.atomic_xchg, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw8_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw16_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i32_atomic_rmw_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw8_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u8, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw16_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u16, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw32_u_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u32, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i64_atomic_rmw_cmpxchg: return deferASM(BuiltinSymbols.atomic_cmpxchg, compiler, Type.u64, operands, Type.u64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_wait: return deferASM(BuiltinSymbols.atomic_wait, compiler, Type.i32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_wait: return deferASM(BuiltinSymbols.atomic_wait, compiler, Type.i64, operands, Type.i64, reportNode);
|
|
|
|
case BuiltinSymbols.i32_notify: return deferASM(BuiltinSymbols.atomic_notify, compiler, Type.i32, operands, Type.u32, reportNode);
|
|
|
|
case BuiltinSymbols.i64_notify: return deferASM(BuiltinSymbols.atomic_notify, compiler, Type.i64, operands, Type.i64, reportNode);
|
2019-02-07 18:21:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* tslint:enable:max-line-length */
|
2018-04-27 19:12:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** A helper for deferring inline-assembler-like calls to built-in functions. */
|
|
|
|
function deferASM(
|
|
|
|
name: string,
|
|
|
|
compiler: Compiler,
|
|
|
|
typeArgument: Type,
|
|
|
|
operands: Expression[],
|
|
|
|
valueType: Type,
|
2019-02-07 18:21:09 +01:00
|
|
|
reportNode: CallExpression
|
2018-04-27 19:12:25 +02:00
|
|
|
): ExpressionRef {
|
2019-02-21 00:11:22 +01:00
|
|
|
assert(compiler.program.elementsByName.has(name));
|
|
|
|
var prototype = compiler.program.elementsByName.get(name)!;
|
2018-04-27 19:12:25 +02:00
|
|
|
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
|
|
|
return compileCall(compiler, <FunctionPrototype>prototype, [ typeArgument ], operands, valueType, reportNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Evaluates the constant type of a type argument *or* expression. */
|
2018-04-07 23:31:36 +02:00
|
|
|
function evaluateConstantType(
|
|
|
|
compiler: Compiler,
|
|
|
|
typeArguments: Type[] | null,
|
|
|
|
operands: Expression[],
|
|
|
|
reportNode: Node
|
|
|
|
): Type | null {
|
|
|
|
if (operands.length == 0) { // requires type argument
|
|
|
|
if (!typeArguments || typeArguments.length != 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return typeArguments[0];
|
|
|
|
}
|
|
|
|
if (operands.length == 1) { // optional type argument
|
|
|
|
if (typeArguments) {
|
|
|
|
if (typeArguments.length == 1) {
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-04-07 23:31:36 +02:00
|
|
|
} else {
|
|
|
|
if (typeArguments.length) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.compileExpressionRetainType(operands[0], Type.i32, WrapMode.NONE);
|
2018-04-07 23:31:36 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
compiler.compileExpressionRetainType(operands[0], Type.i32, WrapMode.NONE);
|
2018-04-07 23:31:36 +02:00
|
|
|
}
|
|
|
|
return compiler.currentType;
|
|
|
|
}
|
|
|
|
if (typeArguments && typeArguments.length > 1) {
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_type_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", typeArguments.length.toString(10)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
compiler.error(
|
|
|
|
DiagnosticCode.Expected_0_arguments_but_got_1,
|
|
|
|
reportNode.range, "1", operands.length.toString(10)
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2018-04-27 19:12:25 +02:00
|
|
|
/** Evaluates a `constantOffset` argument.*/
|
2018-01-21 16:34:50 +01:00
|
|
|
function evaluateConstantOffset(compiler: Compiler, expression: Expression): i32 {
|
|
|
|
var expr: ExpressionRef;
|
|
|
|
var value: i32;
|
2018-02-25 00:13:39 +01:00
|
|
|
if (compiler.options.isWasm64) {
|
2018-05-06 00:00:54 +02:00
|
|
|
expr = compiler.precomputeExpression(expression, Type.usize64, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-21 16:34:50 +01:00
|
|
|
if (
|
2018-05-06 00:00:54 +02:00
|
|
|
getExpressionId(expr) != ExpressionId.Const ||
|
|
|
|
getExpressionType(expr) != NativeType.I64 ||
|
|
|
|
getConstValueI64High(expr) != 0 ||
|
|
|
|
(value = getConstValueI64Low(expr)) < 0
|
2018-01-21 16:34:50 +01:00
|
|
|
) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
2019-02-07 23:04:57 +01:00
|
|
|
DiagnosticCode.Expression_must_be_a_compile_time_constant,
|
2018-02-25 00:13:39 +01:00
|
|
|
expression.range
|
|
|
|
);
|
2018-01-21 16:34:50 +01:00
|
|
|
value = -1;
|
|
|
|
}
|
|
|
|
} else {
|
2018-05-06 00:00:54 +02:00
|
|
|
expr = compiler.precomputeExpression(expression, Type.usize32, ConversionKind.IMPLICIT, WrapMode.NONE);
|
2018-01-21 16:34:50 +01:00
|
|
|
if (
|
2018-05-06 00:00:54 +02:00
|
|
|
getExpressionId(expr) != ExpressionId.Const ||
|
|
|
|
getExpressionType(expr) != NativeType.I32 ||
|
|
|
|
(value = getConstValueI32(expr)) < 0
|
2018-01-21 16:34:50 +01:00
|
|
|
) {
|
2018-02-25 00:13:39 +01:00
|
|
|
compiler.error(
|
2019-02-07 23:04:57 +01:00
|
|
|
DiagnosticCode.Expression_must_be_a_compile_time_constant,
|
2018-02-25 00:13:39 +01:00
|
|
|
expression.range
|
|
|
|
);
|
2018-01-21 16:34:50 +01:00
|
|
|
value = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2018-02-02 03:07:54 +01:00
|
|
|
/** Compiles an abort wired to the conditionally imported 'abort' function. */
|
2018-02-25 00:13:39 +01:00
|
|
|
export function compileAbort(
|
|
|
|
compiler: Compiler,
|
|
|
|
message: Expression | null,
|
|
|
|
reportNode: Node
|
|
|
|
): ExpressionRef {
|
2018-03-12 14:06:39 +01:00
|
|
|
var program = compiler.program;
|
2018-01-27 17:02:52 +01:00
|
|
|
var module = compiler.module;
|
2018-03-12 14:06:39 +01:00
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
var stringInstance = compiler.program.stringInstance;
|
|
|
|
if (!stringInstance) return module.createUnreachable();
|
2018-03-12 14:06:39 +01:00
|
|
|
|
2018-07-18 23:49:32 +02:00
|
|
|
var abortInstance = program.abortInstance;
|
2018-03-12 14:06:39 +01:00
|
|
|
if (!(abortInstance && compiler.compileFunction(abortInstance))) return module.createUnreachable();
|
|
|
|
|
|
|
|
var messageArg = message != null
|
2019-02-21 00:11:22 +01:00
|
|
|
? compiler.compileExpression(message, stringInstance.type, ConversionKind.IMPLICIT, WrapMode.NONE)
|
|
|
|
: stringInstance.type.toNativeZero(module);
|
2018-03-12 14:06:39 +01:00
|
|
|
|
2018-08-02 18:23:02 +02:00
|
|
|
var filenameArg = compiler.ensureStaticString(reportNode.range.source.normalizedPath);
|
2018-03-12 14:06:39 +01:00
|
|
|
|
|
|
|
compiler.currentType = Type.void;
|
|
|
|
return module.createBlock(null, [
|
2018-10-11 08:49:08 +02:00
|
|
|
module.createCall(
|
2018-03-12 14:06:39 +01:00
|
|
|
abortInstance.internalName, [
|
|
|
|
messageArg,
|
|
|
|
filenameArg,
|
|
|
|
module.createI32(reportNode.range.line),
|
|
|
|
module.createI32(reportNode.range.column)
|
|
|
|
],
|
|
|
|
NativeType.None
|
|
|
|
),
|
|
|
|
module.createUnreachable()
|
|
|
|
]);
|
2018-01-27 17:02:52 +01:00
|
|
|
}
|
2018-07-20 20:32:25 +02:00
|
|
|
|
|
|
|
/** Compiles the iterateRoots function if requires. */
|
|
|
|
export function compileIterateRoots(compiler: Compiler): void {
|
|
|
|
var module = compiler.module;
|
|
|
|
var exprs = new Array<ExpressionRef>();
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
for (let element of compiler.program.elementsByName.values()) {
|
2018-07-20 20:32:25 +02:00
|
|
|
if (element.kind != ElementKind.GLOBAL) continue;
|
|
|
|
let global = <Global>element;
|
|
|
|
let classReference = global.type.classReference;
|
|
|
|
if (
|
|
|
|
global.is(CommonFlags.COMPILED) &&
|
|
|
|
classReference !== null &&
|
|
|
|
!classReference.hasDecorator(DecoratorFlags.UNMANAGED)
|
|
|
|
) {
|
|
|
|
if (global.is(CommonFlags.INLINED)) {
|
|
|
|
let value = global.constantIntegerValue;
|
|
|
|
exprs.push(
|
|
|
|
module.createCallIndirect(
|
|
|
|
module.createGetLocal(0, NativeType.I32),
|
|
|
|
[
|
|
|
|
compiler.options.isWasm64
|
|
|
|
? module.createI64(i64_low(value), i64_high(value))
|
|
|
|
: module.createI32(i64_low(value))
|
|
|
|
],
|
2019-02-07 15:26:26 +01:00
|
|
|
"i_"
|
2018-07-20 20:32:25 +02:00
|
|
|
)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
exprs.push(
|
|
|
|
module.createCallIndirect(
|
|
|
|
module.createGetLocal(0, NativeType.I32),
|
|
|
|
[
|
|
|
|
module.createGetGlobal(
|
|
|
|
global.internalName,
|
|
|
|
compiler.options.nativeSizeType
|
|
|
|
)
|
|
|
|
],
|
2019-02-07 15:26:26 +01:00
|
|
|
"i_"
|
2018-07-20 20:32:25 +02:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var typeRef = compiler.ensureFunctionType([ Type.i32 ], Type.void);
|
|
|
|
module.addFunction("~iterateRoots", typeRef, [],
|
|
|
|
exprs.length
|
|
|
|
? module.createBlock(null, exprs)
|
|
|
|
: module.createNop()
|
|
|
|
);
|
|
|
|
}
|
2018-08-02 18:23:02 +02:00
|
|
|
|
|
|
|
/** Ensures that the specified class's GC hook exists and returns its function table index. */
|
|
|
|
export function ensureGCHook(
|
|
|
|
compiler: Compiler,
|
|
|
|
classInstance: Class
|
|
|
|
): u32 {
|
|
|
|
var program = compiler.program;
|
|
|
|
assert(classInstance.type.isManaged(program));
|
|
|
|
|
|
|
|
// check if the GC hook has already been created
|
|
|
|
{
|
|
|
|
let existingIndex = classInstance.gcHookIndex;
|
|
|
|
if (existingIndex != <u32>-1) return existingIndex;
|
|
|
|
}
|
|
|
|
|
2019-02-21 00:11:22 +01:00
|
|
|
// check if the class implements a custom GC function (only valid for library elements)
|
2018-08-02 18:23:02 +02:00
|
|
|
var members = classInstance.members;
|
2019-02-21 00:11:22 +01:00
|
|
|
if (classInstance.isDeclaredInLibrary) {
|
2018-08-02 18:23:02 +02:00
|
|
|
if (members !== null && members.has("__gc")) {
|
|
|
|
let gcPrototype = assert(members.get("__gc"));
|
|
|
|
assert(gcPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
|
|
|
|
let gcInstance = assert(program.resolver.resolveFunction(<FunctionPrototype>gcPrototype, null));
|
|
|
|
assert(gcInstance.is(CommonFlags.PRIVATE | CommonFlags.INSTANCE));
|
|
|
|
assert(!gcInstance.isAny(CommonFlags.AMBIENT | CommonFlags.VIRTUAL));
|
|
|
|
assert(gcInstance.signature.parameterTypes.length == 0);
|
|
|
|
assert(gcInstance.signature.returnType == Type.void);
|
|
|
|
gcInstance.internalName = classInstance.internalName + "~gc";
|
|
|
|
assert(compiler.compileFunction(gcInstance));
|
|
|
|
let index = compiler.ensureFunctionTableEntry(gcInstance);
|
|
|
|
classInstance.gcHookIndex = index;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var module = compiler.module;
|
|
|
|
var options = compiler.options;
|
|
|
|
var nativeSizeType = options.nativeSizeType;
|
|
|
|
var nativeSizeSize = options.usizeType.byteSize;
|
|
|
|
var body = new Array<ExpressionRef>();
|
|
|
|
|
|
|
|
// nothing to mark if 'this' is null
|
|
|
|
body.push(
|
|
|
|
module.createIf(
|
|
|
|
module.createUnary(
|
|
|
|
options.isWasm64
|
|
|
|
? UnaryOp.EqzI64
|
|
|
|
: UnaryOp.EqzI32,
|
|
|
|
module.createGetLocal(0, nativeSizeType)
|
|
|
|
),
|
|
|
|
module.createReturn()
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// remember the function index so we don't recurse infinitely
|
|
|
|
var functionTable = compiler.functionTable;
|
|
|
|
var gcHookIndex = functionTable.length;
|
2018-09-13 23:10:49 +02:00
|
|
|
functionTable.push("<placeholder>");
|
2018-08-02 18:23:02 +02:00
|
|
|
classInstance.gcHookIndex = gcHookIndex;
|
|
|
|
|
|
|
|
// if the class extends a base class, call its hook first (calls mark)
|
|
|
|
var baseInstance = classInstance.base;
|
|
|
|
if (baseInstance) {
|
|
|
|
assert(baseInstance.type.isManaged(program));
|
|
|
|
body.push(
|
|
|
|
module.createCallIndirect(
|
|
|
|
module.createI32(
|
|
|
|
ensureGCHook(compiler, <Class>baseInstance.type.classReference)
|
|
|
|
),
|
|
|
|
[
|
|
|
|
module.createGetLocal(0, nativeSizeType)
|
|
|
|
],
|
2019-02-07 15:26:26 +01:00
|
|
|
nativeSizeType == NativeType.I64 ? "I_" : "i_"
|
2018-08-02 18:23:02 +02:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// if this class is the top-most base class, mark the instance
|
|
|
|
} else {
|
|
|
|
body.push(
|
|
|
|
module.createCall(assert(program.gcMarkInstance).internalName, [
|
|
|
|
module.createGetLocal(0, nativeSizeType)
|
|
|
|
], NativeType.None)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// mark instances assigned to own fields that are again references
|
|
|
|
if (members) {
|
|
|
|
for (let member of members.values()) {
|
|
|
|
if (member.kind == ElementKind.FIELD) {
|
|
|
|
if ((<Field>member).parent === classInstance) {
|
|
|
|
let type = (<Field>member).type;
|
|
|
|
if (type.isManaged(program)) {
|
|
|
|
let offset = (<Field>member).memoryOffset;
|
|
|
|
assert(offset >= 0);
|
|
|
|
body.push(
|
|
|
|
module.createCall(assert(program.gcMarkInstance).internalName, [
|
|
|
|
module.createLoad(
|
|
|
|
nativeSizeSize,
|
|
|
|
false,
|
|
|
|
module.createGetLocal(0, nativeSizeType),
|
|
|
|
nativeSizeType,
|
|
|
|
offset
|
|
|
|
)
|
|
|
|
], NativeType.None)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the function to the module and return its table index
|
2018-09-13 23:10:49 +02:00
|
|
|
var funcName = classInstance.internalName + "~gc";
|
|
|
|
module.addFunction(
|
|
|
|
funcName,
|
2018-08-02 18:23:02 +02:00
|
|
|
compiler.ensureFunctionType(null, Type.void, options.usizeType),
|
|
|
|
null,
|
|
|
|
module.createBlock(null, body)
|
|
|
|
);
|
2018-09-13 23:10:49 +02:00
|
|
|
functionTable[gcHookIndex] = funcName;
|
2018-08-02 18:23:02 +02:00
|
|
|
return gcHookIndex;
|
|
|
|
}
|