From 625f87a6defca8499ffb723b5073400e530f6187 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 13 Nov 2019 22:54:57 +0100 Subject: [PATCH] Add concrete SIMD types --- src/builtins.ts | 130 ++++++++++++++++++++++---------- src/common.ts | 11 +++ src/program.ts | 34 ++++++++- src/resolver.ts | 64 +++++++++++++++- src/types.ts | 85 ++++++++++++++++++++- std/assembly/index.d.ts | 36 +++++++-- std/assembly/vector.ts | 41 +++++++++- tests/compiler/features/simd.ts | 92 +++++++++++----------- 8 files changed, 395 insertions(+), 98 deletions(-) diff --git a/src/builtins.ts b/src/builtins.ts index 0578325ec5..819bfc1188 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -341,9 +341,13 @@ export namespace BuiltinSymbols { export const v128_qfms = "~lib/builtins/v128.qfms"; export const i8x16 = "~lib/builtins/i8x16"; + export const u8x16 = "~lib/builtins/u8x16"; export const i16x8 = "~lib/builtins/i16x8"; + export const u16x8 = "~lib/builtins/u16x8"; export const i32x4 = "~lib/builtins/i32x4"; + export const u32x4 = "~lib/builtins/u32x4"; export const i64x2 = "~lib/builtins/i64x2"; + export const u64x2 = "~lib/builtins/u64x2"; export const f32x4 = "~lib/builtins/f32x4"; export const f64x2 = "~lib/builtins/f64x2"; @@ -597,6 +601,7 @@ export function compileCall( isAsm: bool = false ): ExpressionRef { var module = compiler.module; + var alt: bool = false; switch (prototype.internalName) { @@ -2544,13 +2549,15 @@ export function compileCall( // === SIMD =================================================================================== case BuiltinSymbols.v128: // alias for now - case BuiltinSymbols.i8x16: { + case BuiltinSymbols.i8x16: alt = true; + case BuiltinSymbols.u8x16: { + let outType = alt ? Type.i8x16 : Type.u8x16; if ( checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 16, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2563,23 +2570,25 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.I32); writeI8(getConstValueI32(expr), bytes, i); } } - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.v128(bytes); } - case BuiltinSymbols.i16x8: { + case BuiltinSymbols.i16x8: alt = true; + case BuiltinSymbols.u16x8: { + let outType = alt ? Type.i16x8 : Type.u16x8; if ( checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 8, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2592,23 +2601,25 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.I32); writeI16(getConstValueI32(expr), bytes, i << 1); } } - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.v128(bytes); } - case BuiltinSymbols.i32x4: { + case BuiltinSymbols.i32x4: alt = true; + case BuiltinSymbols.u32x4: { + let outType = alt ? Type.i32x4 : Type.u32x4; if ( checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 4, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2621,23 +2632,25 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.I32); writeI32(getConstValueI32(expr), bytes, i << 2); } } - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.v128(bytes); } - case BuiltinSymbols.i64x2: { + case BuiltinSymbols.i64x2: alt = true; + case BuiltinSymbols.u64x2: { + let outType = alt ? Type.i64x2 : Type.u64x2; if ( checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 2, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2650,7 +2663,7 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.I64); @@ -2659,7 +2672,7 @@ export function compileCall( writeI32(getConstValueI64High(expr), bytes, off + 4); } } - compiler.currentType = Type.v128; + compiler.currentType = outType; return module.v128(bytes); } case BuiltinSymbols.f32x4: { @@ -2668,7 +2681,7 @@ export function compileCall( checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 4, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = Type.f32x4; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2681,14 +2694,14 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = Type.f32x4; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.F32); writeF32(getConstValueF32(expr), bytes, i << 2); } } - compiler.currentType = Type.v128; + compiler.currentType = Type.f32x4; return module.v128(bytes); } case BuiltinSymbols.f64x2: { @@ -2697,7 +2710,7 @@ export function compileCall( checkTypeAbsent(typeArguments, reportNode, prototype) | checkArgsRequired(operands, 2, reportNode, compiler) ) { - compiler.currentType = Type.v128; + compiler.currentType = Type.f64x2; return module.unreachable(); } let bytes = new Uint8Array(16); @@ -2710,14 +2723,14 @@ export function compileCall( DiagnosticCode.Expression_must_be_a_compile_time_constant, value.range ); - compiler.currentType = Type.v128; + compiler.currentType = Type.f64x2; return module.unreachable(); } assert(getExpressionType(expr) == NativeType.F64); writeF64(getConstValueF64(expr), bytes, i << 3); } } - compiler.currentType = Type.v128; + compiler.currentType = Type.f64x2; return module.v128(bytes); } case BuiltinSymbols.v128_splat: { // splat(x: T) -> v128 @@ -2731,30 +2744,67 @@ export function compileCall( } let type = typeArguments![0]; let arg0 = compiler.compileExpression(operands[0], type, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; if (!type.is(TypeFlags.REFERENCE)) { switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.SplatI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.SplatI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.SplatI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.SplatI64x2, arg0); - case TypeKind.ISIZE: + case TypeKind.I8: { + compiler.currentType = Type.i8x16; + return module.unary(UnaryOp.SplatI8x16, arg0); + } + case TypeKind.U8: { + compiler.currentType = Type.u8x16; + return module.unary(UnaryOp.SplatI8x16, arg0); + } + case TypeKind.I16: { + compiler.currentType = Type.i16x8; + return module.unary(UnaryOp.SplatI16x8, arg0); + } + case TypeKind.U16: { + compiler.currentType = Type.u16x8; + return module.unary(UnaryOp.SplatI16x8, arg0); + } + case TypeKind.I32: { + compiler.currentType = Type.i32x4; + return module.unary(UnaryOp.SplatI32x4, arg0); + } + case TypeKind.U32: { + compiler.currentType = Type.u32x4; + return module.unary(UnaryOp.SplatI32x4, arg0); + } + case TypeKind.I64: { + compiler.currentType = Type.i64x2; + return module.unary(UnaryOp.SplatI64x2, arg0); + } + case TypeKind.U64: { + compiler.currentType = Type.u64x2; + return module.unary(UnaryOp.SplatI64x2, arg0); + } + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) { + compiler.currentType = Type.i64x2; + return module.unary(UnaryOp.SplatI64x2, arg0); + } + compiler.currentType = Type.i32x4; + return module.unary(UnaryOp.SplatI32x4, arg0); + } case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.SplatI64x2 - : UnaryOp.SplatI32x4, - arg0 - ); + if (compiler.options.isWasm64) { + compiler.currentType = Type.u64x2; + return module.unary(UnaryOp.SplatI64x2, arg0); + } + compiler.currentType = Type.u32x4; + return module.unary(UnaryOp.SplatI32x4, arg0); + } + case TypeKind.F32: { + compiler.currentType = Type.f32x4; + return module.unary(UnaryOp.SplatF32x4, arg0); + } + case TypeKind.F64: { + compiler.currentType = Type.f64x2; + return module.unary(UnaryOp.SplatF64x2, arg0); } - case TypeKind.F32: return module.unary(UnaryOp.SplatF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SplatF64x2, arg0); } } + compiler.currentType = Type.v128; compiler.error( DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, reportNode.typeArgumentsRange, "v128.splat", type.toString() diff --git a/src/common.ts b/src/common.ts index 4c8106a25a..ac06e1fd31 100644 --- a/src/common.ts +++ b/src/common.ts @@ -138,6 +138,7 @@ export namespace CommonSymbols { export const indexof = "indexof"; export const valueof = "valueof"; export const returnof = "returnof"; + export const vectorof = "vectorof"; // aliases export const null_ = "null"; export const true_ = "true"; @@ -177,6 +178,16 @@ export namespace CommonSymbols { export const F32 = "F32"; export const F64 = "F64"; export const V128 = "V128"; + export const I8x16 = "I8x16"; + export const U8x16 = "U8x16"; + export const I16x8 = "I16x8"; + export const U16x8 = "U16x8"; + export const I32x4 = "I32x4"; + export const U32x4 = "U32x4"; + export const I64x2 = "I64x2"; + export const U64x2 = "U64x2"; + export const F32x4 = "F32x4"; + export const F64x2 = "F64x2"; export const Anyref = "Anyref"; export const String = "String"; export const Array = "Array"; diff --git a/src/program.ts b/src/program.ts index a7b9f4dce5..7614d7499b 100644 --- a/src/program.ts +++ b/src/program.ts @@ -661,7 +661,25 @@ export class Program extends DiagnosticEmitter { this.makeNativeTypeDeclaration(CommonSymbols.returnof, CommonFlags.EXPORT | CommonFlags.GENERIC), DecoratorFlags.BUILTIN )); - if (options.hasFeature(Feature.SIMD)) this.registerNativeType(CommonSymbols.v128, Type.v128); + if (options.hasFeature(Feature.SIMD)) { + this.nativeFile.add(CommonSymbols.vectorof, new TypeDefinition( + CommonSymbols.vectorof, + this.nativeFile, + this.makeNativeTypeDeclaration(CommonSymbols.vectorof, CommonFlags.EXPORT | CommonFlags.GENERIC), + DecoratorFlags.BUILTIN + )); + this.registerNativeType(CommonSymbols.v128, Type.v128); + this.registerNativeType(CommonSymbols.i8x16, Type.i8x16); + this.registerNativeType(CommonSymbols.u8x16, Type.u8x16); + this.registerNativeType(CommonSymbols.i16x8, Type.i16x8); + this.registerNativeType(CommonSymbols.u16x8, Type.u16x8); + this.registerNativeType(CommonSymbols.i32x4, Type.i32x4); + this.registerNativeType(CommonSymbols.u32x4, Type.u32x4); + this.registerNativeType(CommonSymbols.i64x2, Type.i64x2); + this.registerNativeType(CommonSymbols.u64x2, Type.u64x2); + this.registerNativeType(CommonSymbols.f32x4, Type.f32x4); + this.registerNativeType(CommonSymbols.f64x2, Type.f64x2); + } if (options.hasFeature(Feature.REFERENCE_TYPES)) this.registerNativeType(CommonSymbols.anyref, Type.anyref); // register compiler hints @@ -879,7 +897,19 @@ export class Program extends DiagnosticEmitter { this.registerWrapperClass(Type.bool, CommonSymbols.Bool); this.registerWrapperClass(Type.f32, CommonSymbols.F32); this.registerWrapperClass(Type.f64, CommonSymbols.F64); - if (options.hasFeature(Feature.SIMD)) this.registerWrapperClass(Type.v128, CommonSymbols.V128); + if (options.hasFeature(Feature.SIMD)) { + this.registerWrapperClass(Type.v128, CommonSymbols.V128); + this.registerWrapperClass(Type.i8x16, CommonSymbols.I8x16); + this.registerWrapperClass(Type.u8x16, CommonSymbols.U8x16); + this.registerWrapperClass(Type.i16x8, CommonSymbols.I16x8); + this.registerWrapperClass(Type.u16x8, CommonSymbols.U16x8); + this.registerWrapperClass(Type.i32x4, CommonSymbols.I32x4); + this.registerWrapperClass(Type.u32x4, CommonSymbols.U32x4); + this.registerWrapperClass(Type.i64x2, CommonSymbols.I64x2); + this.registerWrapperClass(Type.u64x2, CommonSymbols.U64x2); + this.registerWrapperClass(Type.f32x4, CommonSymbols.F32x4); + this.registerWrapperClass(Type.f64x2, CommonSymbols.F64x2); + } if (options.hasFeature(Feature.REFERENCE_TYPES)) this.registerWrapperClass(Type.anyref, CommonSymbols.Anyref); // register views but don't instantiate them yet diff --git a/src/resolver.ts b/src/resolver.ts index 3ef1d2228a..3ebbedf562 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -95,6 +95,7 @@ import { import { BuiltinSymbols } from "./builtins"; +import { Feature } from "../std/assembly/shared/feature"; /** Indicates whether errors are reported or not. */ export enum ReportMode { @@ -282,6 +283,10 @@ export class Resolver extends DiagnosticEmitter { case CommonSymbols.indexof: return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode); case CommonSymbols.valueof: return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode); case CommonSymbols.returnof: return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode); + case CommonSymbols.vectorof: { + if (!this.program.options.hasFeature(Feature.SIMD)) break; + return this.resolveBuiltinVectorofType(node, ctxElement, ctxTypes, reportMode); + } } } @@ -537,6 +542,9 @@ export class Resolver extends DiagnosticEmitter { } var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode); if (!typeArgument) return null; + if (typeArgument.is(TypeFlags.VECTOR)) { + return typeArgument.subType; + } var classReference = typeArgument.classReference; if (!classReference) { if (reportMode == ReportMode.REPORT) { @@ -547,7 +555,6 @@ export class Resolver extends DiagnosticEmitter { } return null; } - var overload = classReference.lookupOverload(OperatorKind.INDEXED_GET); if (overload) return overload.signature.returnType; if (reportMode == ReportMode.REPORT) { @@ -594,6 +601,61 @@ export class Resolver extends DiagnosticEmitter { return signatureReference.returnType; } + private resolveBuiltinVectorofType( + /** The type to resolve. */ + node: NamedTypeNode, + /** Contextual element. */ + ctxElement: Element, + /** Contextual types, i.e. `T`. */ + ctxTypes: Map | null = null, + /** How to proceed with eventual diagnostics. */ + reportMode: ReportMode = ReportMode.REPORT + ): Type | null { + var typeArgumentNodes = node.typeArguments; + if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + ); + } + return null; + } + var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode); + if (!typeArgument) return null; + if (!typeArgument.isAny(TypeFlags.REFERENCE | TypeFlags.VECTOR)) { + switch (typeArgument.kind) { + case TypeKind.I8: return Type.i8x16; + case TypeKind.I16: return Type.i16x8; + case TypeKind.I32: return Type.i32x4; + case TypeKind.I64: return Type.i64x2; + case TypeKind.ISIZE: { + return this.program.options.isWasm64 + ? Type.i64x2 + : Type.i32x4; + } + case TypeKind.U8: return Type.u8x16; + case TypeKind.U16: return Type.u16x8; + case TypeKind.U32: return Type.u32x4; + case TypeKind.U64: return Type.u64x2; + case TypeKind.USIZE: { + return this.program.options.isWasm64 + ? Type.u64x2 + : Type.u32x4; + } + case TypeKind.F32: return Type.f32x4; + case TypeKind.F64: return Type.f64x2; + } + } + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + typeArgumentNodes[0].range, "vectorof", typeArgument.toString() + ); + } + return null; + } + /** Resolves a type name to the program element it refers to. */ resolveTypeName( /** The type name to resolve. */ diff --git a/src/types.ts b/src/types.ts index abf42c8458..5e4fc888db 100644 --- a/src/types.ts +++ b/src/types.ts @@ -118,9 +118,11 @@ export class Type { nonNullableType: Type; /** Cached nullable type, if non-nullable. */ private cachedNullableType: Type | null = null; + /** Subtype, if a specialized vector type. */ + subType: Type | null; /** Constructs a new resolved type. */ - constructor(kind: TypeKind, flags: TypeFlags, size: u32) { + constructor(kind: TypeKind, flags: TypeFlags, size: u32, subType: Type | null = null) { this.kind = kind; this.flags = flags; this.size = size; @@ -128,6 +130,7 @@ export class Type { this.classReference = null; this.signatureReference = null; this.nonNullableType = this; + this.subType = subType; } /** Returns the closest int type representing this type. */ @@ -554,6 +557,86 @@ export class Type { TypeFlags.VALUE, 128 ); + /** A 128-bit vector of sixteen 8-bit signed integer lanes. */ + static readonly i8x16: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.i8 + ); + + /** A 128-bit vector of sixteen 8-bit unsigned integer lanes. */ + static readonly u8x16: Type = new Type(TypeKind.V128, + TypeFlags.UNSIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.u8 + ); + + /** A 128-bit vector of eight 16-bit signed integer lanes. */ + static readonly i16x8: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.i16 + ); + + /** A 128-bit vector of eight 16-bit unsigned integer lanes. */ + static readonly u16x8: Type = new Type(TypeKind.V128, + TypeFlags.UNSIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.u16 + ); + + /** A 128-bit vector of four 32-bit signed integer lanes. */ + static readonly i32x4: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.i32 + ); + + /** A 128-bit vector of four 32-bit unsigned integer lanes. */ + static readonly u32x4: Type = new Type(TypeKind.V128, + TypeFlags.UNSIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.u32 + ); + + /** A 128-bit vector of two 32-bit signed integer lanes. */ + static readonly i64x2: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.i64 + ); + + /** A 128-bit vector of two 32-bit unsigned integer lanes. */ + static readonly u64x2: Type = new Type(TypeKind.V128, + TypeFlags.UNSIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.u64 + ); + + /** A 128-bit vector of four 32-bit float lanes. */ + static readonly f32x4: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.f32 + ); + + /** A 128-bit vector of two 64-bit float lanes. */ + static readonly f64x2: Type = new Type(TypeKind.V128, + TypeFlags.SIGNED | + TypeFlags.VECTOR | + TypeFlags.VALUE, 128, + Type.f64 + ); + /** A host reference. */ static readonly anyref: Type = new Type(TypeKind.ANYREF, TypeFlags.REFERENCE, 0 diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 1d4fdddd6e..7d9e919ee3 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -34,7 +34,27 @@ declare type f32 = number; /** A 64-bit float. */ declare type f64 = number; /** A 128-bit vector. */ -declare type v128 = object; +declare type v128 = object & { __v128__: true }; +/** A vector of sixteen 8-bit signed integer lanes. */ +declare type i8x16 = v128 | {0: i8, 1: i8, 2: i8, 3: i8, 4: i8, 5: i8, 6: i8, 7: i8, 8: i8, 9: i8, 10: i8, 11: i8, 12: i8, 13: i8, 14: i8, 15: i8}; +/** A vector of sixteen 8-bit unsigned integer lanes. */ +declare type u8x16 = v128 | {0: u8, 1: u8, 2: u8, 3: u8, 4: u8, 5: u8, 6: u8, 7: u8, 8: u8, 9: u8, 10: u8, 11: u8, 12: u8, 13: u8, 14: u8, 15: u8}; +/** A vector of eight 16-bit signed integer lanes. */ +declare type i16x8 = v128 | {0: i16, 1: i16, 2: i16, 3: i16, 4: i16, 5: i16, 6: i16, 7: i16}; +/** A vector of eight 16-bit unsigned integer lanes. */ +declare type u16x8 = v128 | {0: u16, 1: u16, 2: u16, 3: u16, 4: u16, 5: u16, 6: u16, 7: u16}; +/** A vector of four 32-bit signed integer lanes. */ +declare type i32x4 = v128 | {0: i32, 1: i32, 2: i32, 3: i32}; +/** A vector of four 32-bit unsigned integer lanes. */ +declare type u32x4 = v128 | {0: u32, 1: u32, 2: u32, 3: u32}; +/** A vector of two 64-bit signed integer lanes. */ +declare type i64x2 = v128 | {0: i64, 1: i64}; +/** A vector of two 64-bit unsigned integer lanes. */ +declare type u64x2 = v128 | {0: u64, 1: u64}; +/** A vector of four 32-bit float lanes. */ +declare type f32x4 = v128 | {0: f32, 1: f32, 2: f32, 3: f32}; +/** A vector of two 64-bit float lanes. */ +declare type f64x2 = v128 | {0: f64, 1: f64}; /** A host reference. */ declare type anyref = object; @@ -627,7 +647,7 @@ declare namespace v128 { export function qfms(a: v128, b: v128, c: v128): v128; } /** Initializes a 128-bit vector from sixteen 8-bit integer values. Arguments must be compile-time constants. */ -declare function i8x16(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): v128; +declare function i8x16(a: i8, b: i8, c: i8, d: i8, e: i8, f: i8, g: i8, h: i8, i: i8, j: i8, k: i8, l: i8, m: i8, n: i8, o: i8, p: i8): i8x16; declare namespace i8x16 { /** Creates a vector with sixteen identical 8-bit integer lanes. */ export function splat(x: i8): v128; @@ -697,7 +717,7 @@ declare namespace i8x16 { export function narrow_i16x8_u(a: v128, b: v128): v128; } /** Initializes a 128-bit vector from eight 16-bit integer values. Arguments must be compile-time constants. */ -declare function i16x8(a: i16, b: i16, c: i16, d: i16, e: i16, f: i16, g: i16, h: i16): v128; +declare function i16x8(a: i16, b: i16, c: i16, d: i16, e: i16, f: i16, g: i16, h: i16): i16x8; declare namespace i16x8 { /** Creates a vector with eight identical 16-bit integer lanes. */ export function splat(x: i16): v128; @@ -779,7 +799,7 @@ declare namespace i16x8 { export function load8x8_u(ptr: usize, immOffset?: u32, immAlign?: u32): v128; } /** Initializes a 128-bit vector from four 32-bit integer values. Arguments must be compile-time constants. */ -declare function i32x4(a: i32, b: i32, c: i32, d: i32): v128; +declare function i32x4(a: i32, b: i32, c: i32, d: i32): i32x4; declare namespace i32x4 { /** Creates a vector with four identical 32-bit integer lanes. */ export function splat(x: i32): v128; @@ -853,7 +873,7 @@ declare namespace i32x4 { export function load16x4_u(ptr: usize, immOffset?: u32, immAlign?: u32): v128; } /** Initializes a 128-bit vector from two 64-bit integer values. Arguments must be compile-time constants. */ -declare function i64x2(a: i64, b: i64): v128; +declare function i64x2(a: i64, b: i64): i64x2; declare namespace i64x2 { /** Creates a vector with two identical 64-bit integer lanes. */ export function splat(x: i64): v128; @@ -889,7 +909,7 @@ declare namespace i64x2 { export function load32x2_u(ptr: usize, immOffset?: u32, immAlign?: u32): v128; } /** Initializes a 128-bit vector from four 32-bit float values. Arguments must be compile-time constants. */ -declare function f32x4(a: f32, b: f32, c: f32, d: f32): v128; +declare function f32x4(a: f32, b: f32, c: f32, d: f32): f32x4; declare namespace f32x4 { /** Creates a vector with four identical 32-bit float lanes. */ export function splat(x: f32): v128; @@ -937,7 +957,7 @@ declare namespace f32x4 { export function qfms(a: v128, b: v128, c: v128): v128; } /** Initializes a 128-bit vector from two 64-bit float values. Arguments must be compile-time constants. */ -declare function f64x2(a: f64, b: f64): v128; +declare function f64x2(a: f64, b: f64): f64x2; declare namespace f64x2 { /** Creates a vector with two identical 64-bit float lanes. */ export function splat(x: f64): v128; @@ -1014,6 +1034,8 @@ declare type valueof = T[0]; declare type ReturnType any> = T extends (...args: any) => infer R ? R : any; /** A special type evaluated to the return type of T if T is a callable function. */ declare type returnof any> = ReturnType; +/** Special type evaluating the corresponding vector type of the specified element type. */ +declare type vectorof = v128; /** Pseudo-class representing the backing class of integer types. */ declare class _Integer { diff --git a/std/assembly/vector.ts b/std/assembly/vector.ts index c7f1afa358..983b837131 100644 --- a/std/assembly/vector.ts +++ b/std/assembly/vector.ts @@ -1,4 +1,43 @@ -/** Vector abstraction. */ @sealed @unmanaged export abstract class V128 { } + +@sealed @unmanaged +export abstract class I8x16 { +} + +@sealed @unmanaged +export abstract class U8x16 { +} + +@sealed @unmanaged +export abstract class I16x8 { +} + +@sealed @unmanaged +export abstract class U16x8 { +} + +@sealed @unmanaged +export abstract class I32x4 { +} + +@sealed @unmanaged +export abstract class U32x4 { +} + +@sealed @unmanaged +export abstract class I64x2 { +} + +@sealed @unmanaged +export abstract class U64x2 { +} + +@sealed @unmanaged +export abstract class F32x4 { +} + +@sealed @unmanaged +export abstract class F64x2 { +} diff --git a/tests/compiler/features/simd.ts b/tests/compiler/features/simd.ts index b17d8ed011..a030eb5050 100644 --- a/tests/compiler/features/simd.ts +++ b/tests/compiler/features/simd.ts @@ -3,50 +3,50 @@ function test_v128(): void { // equality and inequality assert( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) == // i8x16.all_true(i8x16.eq(lhs, rhs)) - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ); assert( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) != // i8x16.any_true(i8x16.ne(lhs, rhs)) - v128(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + i8x16(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ); // bitwise assert( v128.and( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), - v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + i8x16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) ) == - v128(1, 0, 1, 0, 1, 0, 1, 0, 1, 0 , 1 , 0 , 1 , 0 , 1 , 0) + i8x16(1, 0, 1, 0, 1, 0, 1, 0, 1, 0 , 1 , 0 , 1 , 0 , 1 , 0) ); assert( v128.or( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), - v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + i8x16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) ) == - v128(1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 17) + i8x16(1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, 17) ); assert( v128.xor( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), - v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + i8x16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1 , 1 , 1 , 1 , 1 , 1 , 1) ) == - v128(0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17) + i8x16(0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, 17) ); assert( v128.not( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) ) == - v128(-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17) + i8x16(-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17) ); assert( v128.bitselect( - v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), - v128(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), - v128(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), + i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16), + i8x16(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1), + i8x16(0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1), ) == - v128(16, 2, 14, 4, 12, 6, 10, 8, 8, 10, 6, 12, 4, 14, 2, 16), + i8x16(16, 2, 14, 4, 12, 6, 10, 8, 8, 10, 6, 12, 4, 14, 2, 16), ); { let ptr = __alloc(64, 0); @@ -58,9 +58,9 @@ function test_v128(): void { function test_i8x16(): void { var a = i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 127); - assert(a == v128(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 127)); + assert(a == i8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 127)); var b = i8x16.splat(1); - assert(b == v128(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); + assert(b == i8x16(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); var c = i8x16.add(a, b); assert(c == i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -128)); assert(i8x16.sub(c, b) == a); @@ -164,9 +164,9 @@ function test_i8x16(): void { function test_i16x8(): void { var a = i16x8(1, 2, 3, 4, 5, 6, 7, 32767); - assert(a == v128(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, 127)); + assert(a == i8x16(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, 127)); var b = i16x8.splat(1); - assert(b == v128(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)); + assert(b == i8x16(1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)); var c = i16x8.add(a, b); assert(c == i16x8(2, 3, 4, 5, 6, 7, 8, -32768)); assert(i16x8.sub(c, b) == a); @@ -284,12 +284,12 @@ function test_i16x8(): void { // assert( // i16x8.load8x8_s(ptr) // == - // v128(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, -1) + // i8x16(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, -1) // ); // assert( // i16x8.load8x8_u(ptr) // == - // v128(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, 0) + // i8x16(1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, -1, 0) // ); // __free(ptr); // } @@ -297,9 +297,9 @@ function test_i16x8(): void { function test_i32x4(): void { var a = i32x4(1, 2, 3, 2147483647); - assert(a == v128(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, 127)); + assert(a == i8x16(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, 127)); var b = i32x4.splat(1); - assert(b == v128(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)); + assert(b == i8x16(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)); var c = i32x4.add(a, b); assert(c == i32x4(2, 3, 4, -2147483648)); assert(i32x4.sub(c, b) == a); @@ -404,12 +404,12 @@ function test_i32x4(): void { // assert( // i32x4.load16x4_s(ptr) // == - // v128(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, -1) + // i8x16(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, -1, -1) // ); // assert( // i32x4.load16x4_u(ptr) // == - // v128(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, 0, 0) + // i8x16(1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, -1, -1, 0, 0) // ); // __free(ptr); // } @@ -417,9 +417,9 @@ function test_i32x4(): void { function test_i64x2(): void { var a = i64x2(1, 9223372036854775807); - assert(a == v128(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 127)); + assert(a == i8x16(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 127)); var b = i64x2.splat(1); - assert(b == v128(1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + assert(b == i8x16(1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); var c = i64x2.add(a, b); assert(c == i64x2(2, -9223372036854775808)); assert(i64x2.sub(c, b) == a); @@ -463,12 +463,12 @@ function test_i64x2(): void { // assert( // i64x2.load32x2_s(ptr) // == - // v128(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1) + // i8x16(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1) // ); // assert( // i64x2.load32x2_u(ptr) // == - // v128(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0) + // i8x16(1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0) // ); // __free(ptr); // } @@ -476,9 +476,9 @@ function test_i64x2(): void { function test_f32x4(): void { var a = f32x4(1.5, 2.5, 3.5, 4.5); - assert(a == v128(0, 0, -64, 63, 0, 0, 32, 64, 0, 0, 96, 64, 0, 0, -112, 64)); + assert(a == i8x16(0, 0, -64, 63, 0, 0, 32, 64, 0, 0, 96, 64, 0, 0, -112, 64)); var b = f32x4.splat(1.0); - assert(b == v128(0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63)); + assert(b == i8x16(0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63, 0, 0, -128, 63)); var c = f32x4.add(a, b); assert(c == f32x4(2.5, 3.5, 4.5, 5.5)); assert(f32x4.sub(c, b) == a); @@ -538,9 +538,9 @@ function test_f32x4(): void { function test_f64x2(): void { var a = f64x2(1.5, 2.5); - assert(a == v128(0, 0, 0, 0, 0, 0, -8, 63, 0, 0, 0, 0, 0, 0, 4, 64)); + assert(a == i8x16(0, 0, 0, 0, 0, 0, -8, 63, 0, 0, 0, 0, 0, 0, 4, 64)); var b = f64x2.splat(1.0); - assert(b == v128(0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, -16, 63)); + assert(b == i8x16(0, 0, 0, 0, 0, 0, -16, 63, 0, 0, 0, 0, 0, 0, -16, 63)); var c = f64x2.add(a, b); assert(c == f64x2(2.5, 3.5)); assert(f64x2.sub(c, b) == a); @@ -599,18 +599,18 @@ function test_f64x2(): void { } function test_v8x16(): void { - var a = v128( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - var b = v128(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); + var a = i8x16( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + var b = i8x16(16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31); assert( v8x16.shuffle(a, b, 0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31) == - v128(0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31) + i8x16(0, 17, 2, 19, 4, 21, 6, 23, 8, 25, 10, 27, 12, 29, 14, 31) ); - var c = v128(16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + var c = i8x16(16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); assert( v8x16.swizzle(a, c) == - v128(0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + i8x16(0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) ); // TODO: not yet implemented in binaryen/src/wasm-interpreter.h // { @@ -619,7 +619,7 @@ function test_v8x16(): void { // assert( // v8x16.load_splat(ptr) // == - // v128(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42) + // i8x16(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42) // ); // __free(ptr); // } @@ -633,7 +633,7 @@ function test_v16x8(): void { // assert( // v16x8.load_splat(ptr) // == - // v128(42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0) + // i8x16(42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0, 42, 0) // ); // __free(ptr); // } @@ -647,7 +647,7 @@ function test_v32x4(): void { // assert( // v32x4.load_splat(ptr) // == - // v128(42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0) + // i8x16(42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0) // ); // __free(ptr); // } @@ -661,7 +661,7 @@ function test_v64x2(): void { // assert( // v64x2.load_splat(ptr) // == - // v128(42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0) + // i8x16(42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0) // ); // __free(ptr); // }