Skip to content

Add concrete SIMD types #953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 90 additions & 40 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -597,6 +601,7 @@ export function compileCall(
isAsm: bool = false
): ExpressionRef {
var module = compiler.module;
var alt: bool = false;

switch (prototype.internalName) {

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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: {
Expand All @@ -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);
Expand All @@ -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: {
Expand All @@ -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);
Expand All @@ -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<T!>(x: T) -> v128
Expand All @@ -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()
Expand Down
11 changes: 11 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down
34 changes: 32 additions & 2 deletions src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading