diff --git a/cli/asc.json b/cli/asc.json index b373f1bb..004cfb41 100644 --- a/cli/asc.json +++ b/cli/asc.json @@ -163,6 +163,7 @@ " mutable-global Enables mutable global imports and exports", " bulk-memory Enables bulk memory operations", " simd Enables SIMD types and operations.", + " threads Enables threading and atomic operations.", "" ], "type": "s" diff --git a/src/builtins.ts b/src/builtins.ts index f7a534fd..d63064c4 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -20,7 +20,8 @@ import { Expression, LiteralKind, LiteralExpression, - StringLiteralExpression + StringLiteralExpression, + CallExpression } from "./ast"; import { @@ -71,7 +72,7 @@ export function compileCall( typeArguments: Type[] | null, operands: Expression[], contextualType: Type, - reportNode: Node + reportNode: CallExpression ): ExpressionRef { var module = compiler.module; @@ -1678,7 +1679,8 @@ export function compileCall( compiler.currentType = Type.void; return module.createStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset); } - case "Atomic.load": { // Atomic.load(offset: usize, constantOffset?: usize) -> * + case "atomic.load": { // load(offset: usize, constantOffset?: usize) -> * + if (!compiler.options.hasFeature(Feature.THREADS)) break; if (operands.length < 1 || operands.length > 2) { if (!(typeArguments && typeArguments.length == 1)) { compiler.error( @@ -1729,7 +1731,8 @@ export function compileCall( offset ); } - case "Atomic.store": { // Atomic.store(offset: usize, value: *, constantOffset?: usize) -> void + case "atomic.store": { // store(offset: usize, value: *, constantOffset?: usize) -> void + if (!compiler.options.hasFeature(Feature.THREADS)) break; compiler.currentType = Type.void; if (operands.length < 2 || operands.length > 3) { if (!(typeArguments && typeArguments.length == 1)) { @@ -1798,13 +1801,14 @@ export function compileCall( compiler.currentType = Type.void; return module.createAtomicStore(typeArguments[0].byteSize, arg0, arg1, type.toNativeType(), offset); } - case "Atomic.add": // add(ptr: usize, value: T, constantOffset?: usize): T; - case "Atomic.sub": // sub(ptr: usize, value: T, constantOffset?: usize): T; - case "Atomic.and": // and(ptr: usize, value: T, constantOffset?: usize): T; - case "Atomic.or": // or(ptr: usize, value: T, constantOffset?: usize): T; - case "Atomic.xor": // xor(ptr: usize, value: T, constantOffset?: usize): T; - case "Atomic.xchg": // xchg(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.add": // add(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.sub": // sub(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.and": // and(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.or": // or(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.xor": // xor(ptr: usize, value: T, constantOffset?: usize): T; + case "atomic.xchg": // xchg(ptr: usize, value: T, constantOffset?: usize): T; { + if (!compiler.options.hasFeature(Feature.THREADS)) break; if (operands.length < 2 || operands.length > 3) { if (!(typeArguments && typeArguments.length == 1)) { compiler.error( @@ -1872,13 +1876,13 @@ export function compileCall( return module.createUnreachable(); } let RMWOp: AtomicRMWOp | null = null; - switch (prototype.internalName) { - case "Atomic.add": { RMWOp = AtomicRMWOp.Add; break; } - case "Atomic.sub": { RMWOp = AtomicRMWOp.Sub; break; } - case "Atomic.and": { RMWOp = AtomicRMWOp.And; break; } - case "Atomic.or": { RMWOp = AtomicRMWOp.Or; break; } - case "Atomic.xor": { RMWOp = AtomicRMWOp.Xor; break; } - case "Atomic.xchg": { RMWOp = AtomicRMWOp.Xchg; break; } + switch (prototype.simpleName) { + case "add": { RMWOp = AtomicRMWOp.Add; break; } + case "sub": { RMWOp = AtomicRMWOp.Sub; break; } + case "and": { RMWOp = AtomicRMWOp.And; break; } + case "or": { RMWOp = AtomicRMWOp.Or; break; } + case "xor": { RMWOp = AtomicRMWOp.Xor; break; } + case "xchg": { RMWOp = AtomicRMWOp.Xchg; break; } } compiler.currentType = typeArguments[0]; if (RMWOp !== null) { @@ -1893,7 +1897,8 @@ export function compileCall( return module.createUnreachable(); } } - case "Atomic.cmpxchg": { // cmpxchg(ptr: usize, expected:T, replacement: T, constantOffset?: usize): T; + case "atomic.cmpxchg": { // cmpxchg(ptr: usize, expected:T, replacement: T, constantOffset?: usize): T; + if (!compiler.options.hasFeature(Feature.THREADS)) break; if (operands.length < 3 || operands.length > 4) { if (!(typeArguments && typeArguments.length == 1)) { compiler.error( @@ -1980,7 +1985,8 @@ export function compileCall( typeArguments[0].byteSize, offset, arg0, arg1, arg2, type.toNativeType() ); } - case "Atomic.wait": { // wait(ptr: usize, expected:T, timeout: i64): i32; + case "atomic.wait": { // wait(ptr: usize, expected:T, timeout: i64): i32; + if (!compiler.options.hasFeature(Feature.THREADS)) break; let hasError = typeArguments == null; if (operands.length != 3) { compiler.error( @@ -2050,7 +2056,8 @@ export function compileCall( arg0, arg1, arg2, type.toNativeType() ); } - case "Atomic.notify": { // notify(ptr: usize, count: u32): u32; + case "atomic.notify": { // notify(ptr: usize, count: u32): u32; + if (!compiler.options.hasFeature(Feature.THREADS)) break; let hasError = typeArguments == null; if (operands.length != 2) { compiler.error( @@ -3171,8 +3178,8 @@ export function compileCall( return expr; } compiler.error( - DiagnosticCode.Operation_not_supported, - reportNode.range + DiagnosticCode.Cannot_find_name_0, + reportNode.expression.range, prototype.internalName ); return module.createUnreachable(); } @@ -3183,8 +3190,9 @@ function deferASMCall( prototype: FunctionPrototype, operands: Expression[], contextualType: Type, - reportNode: Node + reportNode: CallExpression ): ExpressionRef { + /* tslint:disable:max-line-length */ switch (prototype.internalName) { // TODO: Operators can't be just deferred (don't have a corresponding generic built-in) @@ -3263,84 +3271,88 @@ function deferASMCall( case "i64.store": return deferASM("store", compiler, Type.i64, operands, Type.i64, reportNode); case "f32.store": return deferASM("store", compiler, Type.f32, operands, Type.f32, reportNode); case "f64.store": return deferASM("store", compiler, Type.f64, operands, Type.f64, reportNode); - - case "i32.atomic.load8_u": return deferASM("Atomic.load", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.load16_u": return deferASM("Atomic.load", compiler, Type.u16, operands, Type.u32, reportNode); - case "i32.atomic.load": return deferASM("Atomic.load", compiler, Type.i32, operands, Type.i32, reportNode); - case "i64.atomic.load8_u": return deferASM("Atomic.load", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.load16_u": return deferASM("Atomic.load", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.load32_u": return deferASM("Atomic.load", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.load": return deferASM("Atomic.load", compiler, Type.i64, operands, Type.i64, reportNode); - - case "i32.atomic.store8": return deferASM("Atomic.store", compiler, Type.i8, operands, Type.i32, reportNode); - case "i32.atomic.store16": return deferASM("Atomic.store", compiler, Type.i16, operands, Type.i32, reportNode); - case "i32.atomic.store": return deferASM("Atomic.store", compiler, Type.i32, operands, Type.i32, reportNode); - case "i64.atomic.store8": return deferASM("Atomic.store", compiler, Type.i8, operands, Type.i64, reportNode); - case "i64.atomic.store16": return deferASM("Atomic.store", compiler, Type.i16, operands, Type.i64, reportNode); - case "i64.atomic.store32": return deferASM("Atomic.store", compiler, Type.i32, operands, Type.i64, reportNode); - case "i64.atomic.store": return deferASM("Atomic.store", compiler, Type.i64, operands, Type.i64, reportNode); - - case "i32.atomic.rmw8_u.add": return deferASM("Atomic.add", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.add": return deferASM("Atomic.add", compiler, Type.u16, operands, Type.u32, reportNode); - case "i32.atomic.rmw.add": return deferASM("Atomic.add", compiler, Type.u32, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.add": return deferASM("Atomic.add", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.add": return deferASM("Atomic.add", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.add": return deferASM("Atomic.add", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.add": return deferASM("Atomic.add", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.sub": return deferASM("Atomic.sub", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.sub": return deferASM("Atomic.sub", compiler, Type.u16, operands, Type.u32, reportNode); - case "i32.atomic.rmw.sub": return deferASM("Atomic.sub", compiler, Type.u32, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.sub": return deferASM("Atomic.sub", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.sub": return deferASM("Atomic.sub", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.sub": return deferASM("Atomic.sub", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.sub": return deferASM("Atomic.sub", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.and": return deferASM("Atomic.and", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.and": return deferASM("Atomic.and", compiler, Type.u16, operands, Type.u32, reportNode); - case "i32.atomic.rmw.and": return deferASM("Atomic.and", compiler, Type.u32, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.and": return deferASM("Atomic.and", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.and": return deferASM("Atomic.and", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.and": return deferASM("Atomic.and", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.and": return deferASM("Atomic.and", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.or": return deferASM("Atomic.or", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.or": return deferASM("Atomic.or", compiler, Type.u16, operands, Type.u32, reportNode); - case "i32.atomic.rmw.or": return deferASM("Atomic.or", compiler, Type.u32, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.or": return deferASM("Atomic.or", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.or": return deferASM("Atomic.or", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.or": return deferASM("Atomic.or", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.or": return deferASM("Atomic.or", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.xor": return deferASM("Atomic.xor", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.xor": return deferASM("Atomic.xor", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.xor": return deferASM("Atomic.xor", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.xor": return deferASM("Atomic.xor", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.xchg": return deferASM("Atomic.xchg", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.xchg": return deferASM("Atomic.xchg", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.atomic.rmw8_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw16_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i32.atomic.rmw.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); - case "i64.atomic.rmw8_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u8, operands, Type.u64, reportNode); - case "i64.atomic.rmw16_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u16, operands, Type.u64, reportNode); - case "i64.atomic.rmw32_u.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u32, operands, Type.u64, reportNode); - case "i64.atomic.rmw.cmpxchg": return deferASM("Atomic.cmpxchg", compiler, Type.u64, operands, Type.u64, reportNode); - - case "i32.wait": return deferASM("Atomic.wait", compiler, Type.i32, operands, Type.u32, reportNode); - case "i64.wait": return deferASM("Atomic.wait", compiler, Type.i64, operands, Type.i64, reportNode); - case "i32.notify": return deferASM("Atomic.notify", compiler, Type.i32, operands, Type.u32, reportNode); - case "i64.notify": return deferASM("Atomic.notify", compiler, Type.i64, operands, Type.i64, reportNode); } + if (compiler.options.hasFeature(Feature.THREADS)) { + switch (prototype.internalName) { + case "i32.atomic.load8_u": return deferASM("atomic.load", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.load16_u": return deferASM("atomic.load", compiler, Type.u16, operands, Type.u32, reportNode); + case "i32.atomic.load": return deferASM("atomic.load", compiler, Type.i32, operands, Type.i32, reportNode); + case "i64.atomic.load8_u": return deferASM("atomic.load", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.load16_u": return deferASM("atomic.load", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.load32_u": return deferASM("atomic.load", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.load": return deferASM("atomic.load", compiler, Type.i64, operands, Type.i64, reportNode); + + case "i32.atomic.store8": return deferASM("atomic.store", compiler, Type.i8, operands, Type.i32, reportNode); + case "i32.atomic.store16": return deferASM("atomic.store", compiler, Type.i16, operands, Type.i32, reportNode); + case "i32.atomic.store": return deferASM("atomic.store", compiler, Type.i32, operands, Type.i32, reportNode); + case "i64.atomic.store8": return deferASM("atomic.store", compiler, Type.i8, operands, Type.i64, reportNode); + case "i64.atomic.store16": return deferASM("atomic.store", compiler, Type.i16, operands, Type.i64, reportNode); + case "i64.atomic.store32": return deferASM("atomic.store", compiler, Type.i32, operands, Type.i64, reportNode); + case "i64.atomic.store": return deferASM("atomic.store", compiler, Type.i64, operands, Type.i64, reportNode); + + case "i32.atomic.rmw8_u.add": return deferASM("atomic.add", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.add": return deferASM("atomic.add", compiler, Type.u16, operands, Type.u32, reportNode); + case "i32.atomic.rmw.add": return deferASM("atomic.add", compiler, Type.u32, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.add": return deferASM("atomic.add", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.add": return deferASM("atomic.add", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.add": return deferASM("atomic.add", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.add": return deferASM("atomic.add", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.sub": return deferASM("atomic.sub", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.sub": return deferASM("atomic.sub", compiler, Type.u16, operands, Type.u32, reportNode); + case "i32.atomic.rmw.sub": return deferASM("atomic.sub", compiler, Type.u32, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.sub": return deferASM("atomic.sub", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.sub": return deferASM("atomic.sub", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.sub": return deferASM("atomic.sub", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.sub": return deferASM("atomic.sub", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.and": return deferASM("atomic.and", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.and": return deferASM("atomic.and", compiler, Type.u16, operands, Type.u32, reportNode); + case "i32.atomic.rmw.and": return deferASM("atomic.and", compiler, Type.u32, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.and": return deferASM("atomic.and", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.and": return deferASM("atomic.and", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.and": return deferASM("atomic.and", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.and": return deferASM("atomic.and", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.or": return deferASM("atomic.or", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.or": return deferASM("atomic.or", compiler, Type.u16, operands, Type.u32, reportNode); + case "i32.atomic.rmw.or": return deferASM("atomic.or", compiler, Type.u32, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.or": return deferASM("atomic.or", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.or": return deferASM("atomic.or", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.or": return deferASM("atomic.or", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.or": return deferASM("atomic.or", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.xor": return deferASM("atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.xor": return deferASM("atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw.xor": return deferASM("atomic.xor", compiler, Type.u8, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.xor": return deferASM("atomic.xor", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.xor": return deferASM("atomic.xor", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.xor": return deferASM("atomic.xor", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.xor": return deferASM("atomic.xor", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.xchg": return deferASM("atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.xchg": return deferASM("atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw.xchg": return deferASM("atomic.xchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.xchg": return deferASM("atomic.xchg", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.xchg": return deferASM("atomic.xchg", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.xchg": return deferASM("atomic.xchg", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.xchg": return deferASM("atomic.xchg", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.atomic.rmw8_u.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw16_u.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i32.atomic.rmw.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u8, operands, Type.u32, reportNode); + case "i64.atomic.rmw8_u.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u8, operands, Type.u64, reportNode); + case "i64.atomic.rmw16_u.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u16, operands, Type.u64, reportNode); + case "i64.atomic.rmw32_u.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u32, operands, Type.u64, reportNode); + case "i64.atomic.rmw.cmpxchg": return deferASM("atomic.cmpxchg", compiler, Type.u64, operands, Type.u64, reportNode); + + case "i32.wait": return deferASM("atomic.wait", compiler, Type.i32, operands, Type.u32, reportNode); + case "i64.wait": return deferASM("atomic.wait", compiler, Type.i64, operands, Type.i64, reportNode); + case "i32.notify": return deferASM("atomic.notify", compiler, Type.i32, operands, Type.u32, reportNode); + case "i64.notify": return deferASM("atomic.notify", compiler, Type.i64, operands, Type.i64, reportNode); + } + } + /* tslint:enable:max-line-length */ return 0; } @@ -3351,10 +3363,11 @@ function deferASM( typeArgument: Type, operands: Expression[], valueType: Type, - reportNode: Node + reportNode: CallExpression ): ExpressionRef { - // Built-in wasm functions can be namespaced like Atomic.{OPERATION} + // Built-in wasm functions can be namespaced like atomic.{OPERATION} // Split name by '.' to find member function prototype + // FIXME: This is slower than it needs to be due to the way resolving works atm var names = name.split("."); var prototype: Element = assert(compiler.program.elementsLookup.get(names[0])); if (names.length > 1) { diff --git a/src/compiler.ts b/src/compiler.ts index 5c47e3ba..e1f38fb4 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -237,7 +237,9 @@ export const enum Feature { /** Bulk memory operations. */ BULK_MEMORY = 1 << 2, // see: https://github.com/WebAssembly/bulk-memory-operations /** SIMD types and operations. */ - SIMD = 1 << 3 // see: https://github.com/WebAssembly/simd + SIMD = 1 << 3, // see: https://github.com/WebAssembly/simd + /** Threading and atomic operations. */ + THREADS = 1 << 4 // see: https://github.com/WebAssembly/threads } /** Indicates the desired kind of a conversion. */ diff --git a/src/index.ts b/src/index.ts index 26698891..f7dcd38c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -132,6 +132,8 @@ export const FEATURE_MUTABLE_GLOBAL = Feature.MUTABLE_GLOBAL; export const FEATURE_BULK_MEMORY = Feature.BULK_MEMORY; /** SIMD types and operations. */ export const FEATURE_SIMD = Feature.SIMD; +/** Threading and atomic operations. */ +export const FEATURE_THREADS = Feature.THREADS; /** Enables a specific feature. */ export function enableFeature(options: Options, feature: Feature): void { diff --git a/std/assembly/builtins.ts b/std/assembly/builtins.ts index a40b5be9..c8dd2ec3 100644 --- a/std/assembly/builtins.ts +++ b/std/assembly/builtins.ts @@ -43,7 +43,7 @@ @builtin export declare function call_indirect(target: void, ...args: void[]): T; @builtin export declare function instantiate(...args: void[]): T; -export namespace Atomic { +export namespace atomic { @builtin export declare function load(offset: usize, constantOffset?: usize): T; @builtin export declare function store(offset: usize, value: void, constantOffset?: usize): void; @builtin export declare function add(ptr: usize, value: T, constantOffset?: usize): T; @@ -88,7 +88,7 @@ export namespace i32 { @builtin export declare function store16(offset: usize, value: i32, constantOffset?: usize): void; @builtin export declare function store(offset: usize, value: i32, constantOffset?: usize): void; - namespace atomic { + export namespace atomic { @builtin export declare function load8_s(offset: usize, constantOffset?: usize): i32; @builtin export declare function load8_u(offset: usize, constantOffset?: usize): i32; @builtin export declare function load16_s(offset: usize, constantOffset?: usize): i32; @@ -100,33 +100,33 @@ export namespace i32 { @builtin export declare function wait(ptr: usize, expected:i32, timeout:i64): i32; @builtin export declare function notify(ptr: usize, count:u32): u32; - namespace rmw8_u { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32 + export namespace rmw8_u { + @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; } - namespace rmw16_u { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32 + export namespace rmw16_u { + @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; } - namespace rmw { - @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32 - @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32 + export namespace rmw { + @builtin export declare function add(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function sub(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function and(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function or(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xor(offset: usize, value: i32, constantOffset?: usize): i32; + @builtin export declare function xchg(offset: usize, value: i32, constantOffset?: usize): i32; @builtin export declare function cmpxchg(offset: usize, expected:i32, replacement: i32, constantOffset?: usize): i32; } } @@ -166,43 +166,43 @@ export namespace i64 { @builtin export declare function wait(ptr: usize, expected:i64, timeout:i64): i32; @builtin export declare function notify(ptr: usize, count:u32): u32; - namespace rmw8_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64 + export namespace rmw8_u { + @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; } - namespace rmw16_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64 + export namespace rmw16_u { + @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; } - namespace rmw32_u { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64 + export namespace rmw32_u { + @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; } - namespace rmw { - @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64 - @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64 + export namespace rmw { + @builtin export declare function add(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function sub(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function and(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function or(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xor(offset: usize, value: i64, constantOffset?: usize): i64; + @builtin export declare function xchg(offset: usize, value: i64, constantOffset?: usize): i64; @builtin export declare function cmpxchg(offset: usize, expected:i64, replacement: i64, constantOffset?: usize): i64; } } diff --git a/std/portable/index.js b/std/portable/index.js index a16c032e..c772b7c4 100644 --- a/std/portable/index.js +++ b/std/portable/index.js @@ -12,6 +12,7 @@ globalScope.ASC_FEATURE_MUTABLE_GLOBAL = false; globalScope.ASC_FEATURE_SIGN_EXTENSION = false; globalScope.ASC_FEATURE_BULK_MEMORY = false; globalScope.ASC_FEATURE_SIMD = false; +globalScope.ASC_FEATURE_THREADS = false; var F64 = new Float64Array(1); var U64 = new Uint32Array(F64.buffer);