Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.

Commit e1f1a3b

Browse files
authored
Implement v128 instructions (AssemblyScript#508)
1 parent cdf4057 commit e1f1a3b

25 files changed

+6673
-312
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ jobs:
2222
script:
2323
- npm run all
2424
env: Runs the tests on node.js stable
25+
- node_js: node
26+
script:
27+
- npm run clean && npm run test:compiler
28+
env:
29+
- ASC_FEATURES="simd"
30+
- NVM_NODEJS_ORG_MIRROR="https://nodejs.org/download/v8-canary/"

src/builtins.ts

Lines changed: 2308 additions & 72 deletions
Large diffs are not rendered by default.

src/common.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ export namespace CommonSymbols {
118118
export const f32 = "f32";
119119
export const f64 = "f64";
120120
export const v128 = "v128";
121+
export const i8x16 = "i8x16";
122+
export const u8x16 = "u8x16";
123+
export const i16x8 = "i16x8";
124+
export const u16x8 = "u16x8";
125+
export const i32x4 = "i32x4";
126+
export const u32x4 = "u32x4";
127+
export const i64x2 = "i64x2";
128+
export const u64x2 = "u64x2";
129+
export const f32x4 = "f32x4";
130+
export const f64x2 = "f64x2";
121131
export const void_ = "void";
122132
export const number = "number";
123133
export const boolean = "boolean";
@@ -146,6 +156,7 @@ export namespace LibrarySymbols {
146156
export const ASC_FEATURE_SIGN_EXTENSION = "ASC_FEATURE_SIGN_EXTENSION";
147157
export const ASC_FEATURE_BULK_MEMORY = "ASC_FEATURE_BULK_MEMORY";
148158
export const ASC_FEATURE_SIMD = "ASC_FEATURE_SIMD";
159+
export const ASC_FEATURE_THREADS = "ASC_FEATURE_THREADS";
149160
// classes
150161
export const I8 = "I8";
151162
export const I16 = "I16";

src/compiler.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,6 +3199,12 @@ export class Compiler extends DiagnosticEmitter {
31993199
expr = module.createBinary(BinaryOp.EqF64, leftExpr, rightExpr);
32003200
break;
32013201
}
3202+
case TypeKind.V128: {
3203+
expr = module.createUnary(UnaryOp.AllTrueVecI8x16,
3204+
module.createBinary(BinaryOp.EqVecI8x16, leftExpr, rightExpr)
3205+
);
3206+
break;
3207+
}
32023208
default: {
32033209
assert(false);
32043210
expr = module.createUnreachable();
@@ -3287,6 +3293,12 @@ export class Compiler extends DiagnosticEmitter {
32873293
expr = module.createBinary(BinaryOp.NeF64, leftExpr, rightExpr);
32883294
break;
32893295
}
3296+
case TypeKind.V128: {
3297+
expr = module.createUnary(UnaryOp.AnyTrueVecI8x16,
3298+
module.createBinary(BinaryOp.NeVecI8x16, leftExpr, rightExpr)
3299+
);
3300+
break;
3301+
}
32903302
default: {
32913303
assert(false);
32923304
expr = module.createUnreachable();

src/diagnosticMessages.generated.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export enum DiagnosticCode {
3232
Optional_properties_are_not_supported = 219,
3333
Expression_must_be_a_compile_time_constant = 220,
3434
Module_cannot_have_multiple_start_functions = 221,
35+
_0_must_be_a_value_between_1_and_2_inclusive = 222,
36+
_0_must_be_a_power_of_two = 223,
3537
Unterminated_string_literal = 1002,
3638
Identifier_expected = 1003,
3739
_0_expected = 1005,
@@ -165,6 +167,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
165167
case 219: return "Optional properties are not supported.";
166168
case 220: return "Expression must be a compile-time constant.";
167169
case 221: return "Module cannot have multiple start functions.";
170+
case 222: return "'{0}' must be a value between '{1}' and '{2}' inclusive.";
171+
case 223: return "'{0}' must be a power of two.";
168172
case 1002: return "Unterminated string literal.";
169173
case 1003: return "Identifier expected.";
170174
case 1005: return "'{0}' expected.";

src/diagnosticMessages.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"Optional properties are not supported.": 219,
2525
"Expression must be a compile-time constant.": 220,
2626
"Module cannot have multiple start functions.": 221,
27+
"'{0}' must be a value between '{1}' and '{2}' inclusive.": 222,
28+
"'{0}' must be a power of two.": 223,
2729

2830
"Unterminated string literal.": 1002,
2931
"Identifier expected.": 1003,

src/flow.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ export class Flow {
232232
case NativeType.I64: { temps = parentFunction.tempI64s; break; }
233233
case NativeType.F32: { temps = parentFunction.tempF32s; break; }
234234
case NativeType.F64: { temps = parentFunction.tempF64s; break; }
235+
case NativeType.V128: { temps = parentFunction.tempV128s; break; }
235236
default: throw new Error("concrete type expected");
236237
}
237238
var local: Local;
@@ -270,6 +271,10 @@ export class Flow {
270271
temps = parentFunction.tempF64s || (parentFunction.tempF64s = []);
271272
break;
272273
}
274+
case NativeType.V128: {
275+
temps = parentFunction.tempV128s || (parentFunction.tempV128s = []);
276+
break;
277+
}
273278
default: throw new Error("concrete type expected");
274279
}
275280
assert(local.index >= 0);
@@ -297,6 +302,10 @@ export class Flow {
297302
temps = parentFunction.tempF64s || (parentFunction.tempF64s = []);
298303
break;
299304
}
305+
case NativeType.V128: {
306+
temps = parentFunction.tempV128s || (parentFunction.tempV128s = []);
307+
break;
308+
}
300309
default: throw new Error("concrete type expected");
301310
}
302311
var local: Local;

src/module.ts

Lines changed: 146 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export enum UnaryOp {
122122
ExtendI16ToI32 = _BinaryenExtendS16Int32(),
123123
ExtendI8ToI64 = _BinaryenExtendS8Int64(),
124124
ExtendI16ToI64 = _BinaryenExtendS16Int64(),
125-
ExtendI32ToI64 = _BinaryenExtendS32Int64()
125+
ExtendI32ToI64 = _BinaryenExtendS32Int64(),
126126

127127
// see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions
128128
// TruncF32ToI32Sat
@@ -133,6 +133,41 @@ export enum UnaryOp {
133133
// TruncF32ToU64Sat
134134
// TruncF64ToI64Sat
135135
// TruncF64ToU64Sat
136+
137+
// see: https://github.com/WebAssembly/simd
138+
SplatVecI8x16 = _BinaryenSplatVecI8x16(),
139+
SplatVecI16x8 = _BinaryenSplatVecI16x8(),
140+
SplatVecI32x4 = _BinaryenSplatVecI32x4(),
141+
SplatVecI64x2 = _BinaryenSplatVecI64x2(),
142+
SplatVecF32x4 = _BinaryenSplatVecF32x4(),
143+
SplatVecF64x2 = _BinaryenSplatVecF64x2(),
144+
NotVec128 = _BinaryenNotVec128(),
145+
NegVecI8x16 = _BinaryenNegVecI8x16(),
146+
AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(),
147+
AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(),
148+
NegVecI16x8 = _BinaryenNegVecI16x8(),
149+
AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(),
150+
AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(),
151+
NegVecI32x4 = _BinaryenNegVecI32x4(),
152+
AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(),
153+
AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(),
154+
NegVecI64x2 = _BinaryenNegVecI64x2(),
155+
AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(),
156+
AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(),
157+
AbsVecF32x4 = _BinaryenAbsVecF32x4(),
158+
NegVecF32x4 = _BinaryenNegVecF32x4(),
159+
SqrtVecF32x4 = _BinaryenSqrtVecF32x4(),
160+
AbsVecF64x2 = _BinaryenAbsVecF64x2(),
161+
NegVecF64x2 = _BinaryenNegVecF64x2(),
162+
SqrtVecF64x2 = _BinaryenSqrtVecF64x2(),
163+
TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(),
164+
TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(),
165+
TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(),
166+
TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(),
167+
ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(),
168+
ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(),
169+
ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(),
170+
ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2()
136171
}
137172

138173
export enum BinaryOp {
@@ -211,61 +246,9 @@ export enum BinaryOp {
211246
LtF64 = _BinaryenLtFloat64(),
212247
LeF64 = _BinaryenLeFloat64(),
213248
GtF64 = _BinaryenGtFloat64(),
214-
GeF64 = _BinaryenGeFloat64()
215-
}
216-
217-
export enum HostOp {
218-
CurrentMemory = _BinaryenCurrentMemory(),
219-
GrowMemory = _BinaryenGrowMemory(),
220-
221-
// see: https://github.com/WebAssembly/bulk-memory-operations
222-
// MoveMemory
223-
// SetMemory
224-
}
225-
226-
export enum AtomicRMWOp {
227-
Add = _BinaryenAtomicRMWAdd(),
228-
Sub = _BinaryenAtomicRMWSub(),
229-
And = _BinaryenAtomicRMWAnd(),
230-
Or = _BinaryenAtomicRMWOr(),
231-
Xor = _BinaryenAtomicRMWXor(),
232-
Xchg = _BinaryenAtomicRMWXchg()
233-
}
249+
GeF64 = _BinaryenGeFloat64(),
234250

235-
export enum SIMDOp {
236-
SplatVecI8x16 = _BinaryenSplatVecI8x16(),
237-
SplatVecI16x8 = _BinaryenSplatVecI16x8(),
238-
SplatVecI32x4 = _BinaryenSplatVecI32x4(),
239-
SplatVecI64x2 = _BinaryenSplatVecI64x2(),
240-
SplatVecF32x4 = _BinaryenSplatVecF32x4(),
241-
SplatVecF64x2 = _BinaryenSplatVecF64x2(),
242-
NotVec128 = _BinaryenNotVec128(),
243-
NegVecI8x16 = _BinaryenNegVecI8x16(),
244-
AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(),
245-
AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(),
246-
NegVecI16x8 = _BinaryenNegVecI16x8(),
247-
AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(),
248-
AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(),
249-
NegVecI32x4 = _BinaryenNegVecI32x4(),
250-
AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(),
251-
AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(),
252-
NegVecI64x2 = _BinaryenNegVecI64x2(),
253-
AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(),
254-
AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(),
255-
AbsVecF32x4 = _BinaryenAbsVecF32x4(),
256-
NegVecF32x4 = _BinaryenNegVecF32x4(),
257-
SqrtVecF32x4 = _BinaryenSqrtVecF32x4(),
258-
AbsVecF64x2 = _BinaryenAbsVecF64x2(),
259-
NegVecF64x2 = _BinaryenNegVecF64x2(),
260-
SqrtVecF64x2 = _BinaryenSqrtVecF64x2(),
261-
TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(),
262-
TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(),
263-
TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(),
264-
TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(),
265-
ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(),
266-
ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(),
267-
ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(),
268-
ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2(),
251+
// see: https://github.com/WebAssembly/simd
269252
EqVecI8x16 = _BinaryenEqVecI8x16(),
270253
NeVecI8x16 = _BinaryenNeVecI8x16(),
271254
LtSVecI8x16 = _BinaryenLtSVecI8x16(),
@@ -344,6 +327,59 @@ export enum SIMDOp {
344327
MaxVecF64x2 = _BinaryenMaxVecF64x2()
345328
}
346329

330+
export enum HostOp {
331+
CurrentMemory = _BinaryenCurrentMemory(),
332+
GrowMemory = _BinaryenGrowMemory(),
333+
334+
// see: https://github.com/WebAssembly/bulk-memory-operations
335+
// MoveMemory
336+
// SetMemory
337+
}
338+
339+
export enum AtomicRMWOp {
340+
Add = _BinaryenAtomicRMWAdd(),
341+
Sub = _BinaryenAtomicRMWSub(),
342+
And = _BinaryenAtomicRMWAnd(),
343+
Or = _BinaryenAtomicRMWOr(),
344+
Xor = _BinaryenAtomicRMWXor(),
345+
Xchg = _BinaryenAtomicRMWXchg()
346+
}
347+
348+
export enum SIMDExtractOp {
349+
ExtractLaneSVecI8x16 = _BinaryenExtractLaneSVecI8x16(),
350+
ExtractLaneUVecI8x16 = _BinaryenExtractLaneUVecI8x16(),
351+
ExtractLaneSVecI16x8 = _BinaryenExtractLaneSVecI16x8(),
352+
ExtractLaneUVecI16x8 = _BinaryenExtractLaneUVecI16x8(),
353+
ExtractLaneVecI32x4 = _BinaryenExtractLaneVecI32x4(),
354+
ExtractLaneVecI64x2 = _BinaryenExtractLaneVecI64x2(),
355+
ExtractLaneVecF32x4 = _BinaryenExtractLaneVecF32x4(),
356+
ExtractLaneVecF64x2 = _BinaryenExtractLaneVecF64x2(),
357+
}
358+
359+
export enum SIMDReplaceOp {
360+
ReplaceLaneVecI8x16 = _BinaryenReplaceLaneVecI8x16(),
361+
ReplaceLaneVecI16x8 = _BinaryenReplaceLaneVecI16x8(),
362+
ReplaceLaneVecI32x4 = _BinaryenReplaceLaneVecI32x4(),
363+
ReplaceLaneVecI64x2 = _BinaryenReplaceLaneVecI64x2(),
364+
ReplaceLaneVecF32x4 = _BinaryenReplaceLaneVecF32x4(),
365+
ReplaceLaneVecF64x2 = _BinaryenReplaceLaneVecF64x2()
366+
}
367+
368+
export enum SIMDShiftOp { // FIXME: seems to be missing in binaryen-c.h
369+
ShlVecI8x16,
370+
ShrSVecI8x16,
371+
ShrUVecI8x16,
372+
ShlVecI16x8,
373+
ShrSVecI16x8,
374+
ShrUVecI16x8,
375+
ShlVecI32x4,
376+
ShrSVecI32x4,
377+
ShrUVecI32x4,
378+
ShlVecI64x2,
379+
ShrSVecI64x2,
380+
ShrUVecI64x2
381+
}
382+
347383
export class MemorySegment {
348384

349385
buffer: Uint8Array;
@@ -510,19 +546,21 @@ export class Module {
510546
signed: bool,
511547
ptr: ExpressionRef,
512548
type: NativeType,
513-
offset: Index = 0
549+
offset: Index = 0,
550+
align: Index = bytes // naturally aligned by default
514551
): ExpressionRef {
515-
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, /* always aligned */ bytes, type, ptr);
552+
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, ptr);
516553
}
517554

518555
createStore(
519556
bytes: Index,
520557
ptr: ExpressionRef,
521558
value: ExpressionRef,
522559
type: NativeType,
523-
offset: Index = 0
560+
offset: Index = 0,
561+
align: Index = bytes // naturally aligned by default
524562
): ExpressionRef {
525-
return _BinaryenStore(this.ref, bytes, offset, /* always aligned */ bytes, ptr, value, type);
563+
return _BinaryenStore(this.ref, bytes, offset, align, ptr, value, type);
526564
}
527565

528566
createAtomicLoad(
@@ -732,6 +770,55 @@ export class Module {
732770
return _BinaryenMemoryFill(this.ref, dest, value, size);
733771
}
734772

773+
// simd
774+
775+
createSIMDExtract(
776+
op: SIMDExtractOp,
777+
vec: ExpressionRef,
778+
idx: u8
779+
): ExpressionRef {
780+
return _BinaryenSIMDExtract(this.ref, op, vec, idx);
781+
}
782+
783+
createSIMDReplace(
784+
op: SIMDReplaceOp,
785+
vec: ExpressionRef,
786+
idx: u8,
787+
value: ExpressionRef
788+
): ExpressionRef {
789+
return _BinaryenSIMDReplace(this.ref, op, vec, idx, value);
790+
}
791+
792+
createSIMDShuffle(
793+
vec1: ExpressionRef,
794+
vec2: ExpressionRef,
795+
mask: Uint8Array
796+
): ExpressionRef {
797+
assert(mask.length == 16);
798+
var cArr = allocU8Array(mask);
799+
try {
800+
return _BinaryenSIMDShuffle(this.ref, vec1, vec2, cArr);
801+
} finally {
802+
memory.free(cArr);
803+
}
804+
}
805+
806+
createSIMDBitselect(
807+
vec1: ExpressionRef,
808+
vec2: ExpressionRef,
809+
cond: ExpressionRef
810+
): ExpressionRef {
811+
return _BinaryenSIMDBitselect(this.ref, vec1, vec2, cond);
812+
}
813+
814+
createSIMDShift(
815+
op: SIMDShiftOp,
816+
vec: ExpressionRef,
817+
shift: ExpressionRef
818+
): ExpressionRef {
819+
return _BinaryenSIMDShift(this.ref, op, vec, shift);
820+
}
821+
735822
// meta
736823

737824
addGlobal(

src/program.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@ export class Program extends DiagnosticEmitter {
523523
i64_new(options.hasFeature(Feature.BULK_MEMORY) ? 1 : 0, 0));
524524
this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_SIMD, Type.bool,
525525
i64_new(options.hasFeature(Feature.SIMD) ? 1 : 0, 0));
526+
this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_THREADS, Type.bool,
527+
i64_new(options.hasFeature(Feature.THREADS) ? 1 : 0, 0));
526528

527529
// remember deferred elements
528530
var queuedImports = new Array<QueuedImport>();
@@ -2564,6 +2566,7 @@ export class Function extends TypedElement {
25642566
tempI64s: Local[] | null = null;
25652567
tempF32s: Local[] | null = null;
25662568
tempF64s: Local[] | null = null;
2569+
tempV128s: Local[] | null = null;
25672570

25682571
// used by flows to keep track of break labels
25692572
nextBreakId: i32 = 0;

0 commit comments

Comments
 (0)