mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-14 15:31:31 +00:00
Implement v128 instructions (#508)
This commit is contained in:
2328
src/builtins.ts
2328
src/builtins.ts
File diff suppressed because it is too large
Load Diff
@ -118,6 +118,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 void_ = "void";
|
||||
export const number = "number";
|
||||
export const boolean = "boolean";
|
||||
@ -146,6 +156,7 @@ export namespace LibrarySymbols {
|
||||
export const ASC_FEATURE_SIGN_EXTENSION = "ASC_FEATURE_SIGN_EXTENSION";
|
||||
export const ASC_FEATURE_BULK_MEMORY = "ASC_FEATURE_BULK_MEMORY";
|
||||
export const ASC_FEATURE_SIMD = "ASC_FEATURE_SIMD";
|
||||
export const ASC_FEATURE_THREADS = "ASC_FEATURE_THREADS";
|
||||
// classes
|
||||
export const I8 = "I8";
|
||||
export const I16 = "I16";
|
||||
|
@ -3199,6 +3199,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = module.createBinary(BinaryOp.EqF64, leftExpr, rightExpr);
|
||||
break;
|
||||
}
|
||||
case TypeKind.V128: {
|
||||
expr = module.createUnary(UnaryOp.AllTrueVecI8x16,
|
||||
module.createBinary(BinaryOp.EqVecI8x16, leftExpr, rightExpr)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
expr = module.createUnreachable();
|
||||
@ -3287,6 +3293,12 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = module.createBinary(BinaryOp.NeF64, leftExpr, rightExpr);
|
||||
break;
|
||||
}
|
||||
case TypeKind.V128: {
|
||||
expr = module.createUnary(UnaryOp.AnyTrueVecI8x16,
|
||||
module.createBinary(BinaryOp.NeVecI8x16, leftExpr, rightExpr)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false);
|
||||
expr = module.createUnreachable();
|
||||
|
@ -32,6 +32,8 @@ export enum DiagnosticCode {
|
||||
Optional_properties_are_not_supported = 219,
|
||||
Expression_must_be_a_compile_time_constant = 220,
|
||||
Module_cannot_have_multiple_start_functions = 221,
|
||||
_0_must_be_a_value_between_1_and_2_inclusive = 222,
|
||||
_0_must_be_a_power_of_two = 223,
|
||||
Unterminated_string_literal = 1002,
|
||||
Identifier_expected = 1003,
|
||||
_0_expected = 1005,
|
||||
@ -165,6 +167,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 219: return "Optional properties are not supported.";
|
||||
case 220: return "Expression must be a compile-time constant.";
|
||||
case 221: return "Module cannot have multiple start functions.";
|
||||
case 222: return "'{0}' must be a value between '{1}' and '{2}' inclusive.";
|
||||
case 223: return "'{0}' must be a power of two.";
|
||||
case 1002: return "Unterminated string literal.";
|
||||
case 1003: return "Identifier expected.";
|
||||
case 1005: return "'{0}' expected.";
|
||||
|
@ -24,6 +24,8 @@
|
||||
"Optional properties are not supported.": 219,
|
||||
"Expression must be a compile-time constant.": 220,
|
||||
"Module cannot have multiple start functions.": 221,
|
||||
"'{0}' must be a value between '{1}' and '{2}' inclusive.": 222,
|
||||
"'{0}' must be a power of two.": 223,
|
||||
|
||||
"Unterminated string literal.": 1002,
|
||||
"Identifier expected.": 1003,
|
||||
|
@ -232,6 +232,7 @@ export class Flow {
|
||||
case NativeType.I64: { temps = parentFunction.tempI64s; break; }
|
||||
case NativeType.F32: { temps = parentFunction.tempF32s; break; }
|
||||
case NativeType.F64: { temps = parentFunction.tempF64s; break; }
|
||||
case NativeType.V128: { temps = parentFunction.tempV128s; break; }
|
||||
default: throw new Error("concrete type expected");
|
||||
}
|
||||
var local: Local;
|
||||
@ -270,6 +271,10 @@ export class Flow {
|
||||
temps = parentFunction.tempF64s || (parentFunction.tempF64s = []);
|
||||
break;
|
||||
}
|
||||
case NativeType.V128: {
|
||||
temps = parentFunction.tempV128s || (parentFunction.tempV128s = []);
|
||||
break;
|
||||
}
|
||||
default: throw new Error("concrete type expected");
|
||||
}
|
||||
assert(local.index >= 0);
|
||||
@ -297,6 +302,10 @@ export class Flow {
|
||||
temps = parentFunction.tempF64s || (parentFunction.tempF64s = []);
|
||||
break;
|
||||
}
|
||||
case NativeType.V128: {
|
||||
temps = parentFunction.tempV128s || (parentFunction.tempV128s = []);
|
||||
break;
|
||||
}
|
||||
default: throw new Error("concrete type expected");
|
||||
}
|
||||
var local: Local;
|
||||
|
205
src/module.ts
205
src/module.ts
@ -122,7 +122,7 @@ export enum UnaryOp {
|
||||
ExtendI16ToI32 = _BinaryenExtendS16Int32(),
|
||||
ExtendI8ToI64 = _BinaryenExtendS8Int64(),
|
||||
ExtendI16ToI64 = _BinaryenExtendS16Int64(),
|
||||
ExtendI32ToI64 = _BinaryenExtendS32Int64()
|
||||
ExtendI32ToI64 = _BinaryenExtendS32Int64(),
|
||||
|
||||
// see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions
|
||||
// TruncF32ToI32Sat
|
||||
@ -133,6 +133,41 @@ export enum UnaryOp {
|
||||
// TruncF32ToU64Sat
|
||||
// TruncF64ToI64Sat
|
||||
// TruncF64ToU64Sat
|
||||
|
||||
// see: https://github.com/WebAssembly/simd
|
||||
SplatVecI8x16 = _BinaryenSplatVecI8x16(),
|
||||
SplatVecI16x8 = _BinaryenSplatVecI16x8(),
|
||||
SplatVecI32x4 = _BinaryenSplatVecI32x4(),
|
||||
SplatVecI64x2 = _BinaryenSplatVecI64x2(),
|
||||
SplatVecF32x4 = _BinaryenSplatVecF32x4(),
|
||||
SplatVecF64x2 = _BinaryenSplatVecF64x2(),
|
||||
NotVec128 = _BinaryenNotVec128(),
|
||||
NegVecI8x16 = _BinaryenNegVecI8x16(),
|
||||
AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(),
|
||||
AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(),
|
||||
NegVecI16x8 = _BinaryenNegVecI16x8(),
|
||||
AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(),
|
||||
AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(),
|
||||
NegVecI32x4 = _BinaryenNegVecI32x4(),
|
||||
AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(),
|
||||
AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(),
|
||||
NegVecI64x2 = _BinaryenNegVecI64x2(),
|
||||
AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(),
|
||||
AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(),
|
||||
AbsVecF32x4 = _BinaryenAbsVecF32x4(),
|
||||
NegVecF32x4 = _BinaryenNegVecF32x4(),
|
||||
SqrtVecF32x4 = _BinaryenSqrtVecF32x4(),
|
||||
AbsVecF64x2 = _BinaryenAbsVecF64x2(),
|
||||
NegVecF64x2 = _BinaryenNegVecF64x2(),
|
||||
SqrtVecF64x2 = _BinaryenSqrtVecF64x2(),
|
||||
TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(),
|
||||
TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(),
|
||||
TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(),
|
||||
TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(),
|
||||
ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(),
|
||||
ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(),
|
||||
ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(),
|
||||
ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2()
|
||||
}
|
||||
|
||||
export enum BinaryOp {
|
||||
@ -211,61 +246,9 @@ export enum BinaryOp {
|
||||
LtF64 = _BinaryenLtFloat64(),
|
||||
LeF64 = _BinaryenLeFloat64(),
|
||||
GtF64 = _BinaryenGtFloat64(),
|
||||
GeF64 = _BinaryenGeFloat64()
|
||||
}
|
||||
GeF64 = _BinaryenGeFloat64(),
|
||||
|
||||
export enum HostOp {
|
||||
CurrentMemory = _BinaryenCurrentMemory(),
|
||||
GrowMemory = _BinaryenGrowMemory(),
|
||||
|
||||
// see: https://github.com/WebAssembly/bulk-memory-operations
|
||||
// MoveMemory
|
||||
// SetMemory
|
||||
}
|
||||
|
||||
export enum AtomicRMWOp {
|
||||
Add = _BinaryenAtomicRMWAdd(),
|
||||
Sub = _BinaryenAtomicRMWSub(),
|
||||
And = _BinaryenAtomicRMWAnd(),
|
||||
Or = _BinaryenAtomicRMWOr(),
|
||||
Xor = _BinaryenAtomicRMWXor(),
|
||||
Xchg = _BinaryenAtomicRMWXchg()
|
||||
}
|
||||
|
||||
export enum SIMDOp {
|
||||
SplatVecI8x16 = _BinaryenSplatVecI8x16(),
|
||||
SplatVecI16x8 = _BinaryenSplatVecI16x8(),
|
||||
SplatVecI32x4 = _BinaryenSplatVecI32x4(),
|
||||
SplatVecI64x2 = _BinaryenSplatVecI64x2(),
|
||||
SplatVecF32x4 = _BinaryenSplatVecF32x4(),
|
||||
SplatVecF64x2 = _BinaryenSplatVecF64x2(),
|
||||
NotVec128 = _BinaryenNotVec128(),
|
||||
NegVecI8x16 = _BinaryenNegVecI8x16(),
|
||||
AnyTrueVecI8x16 = _BinaryenAnyTrueVecI8x16(),
|
||||
AllTrueVecI8x16 = _BinaryenAllTrueVecI8x16(),
|
||||
NegVecI16x8 = _BinaryenNegVecI16x8(),
|
||||
AnyTrueVecI16x8 = _BinaryenAnyTrueVecI16x8(),
|
||||
AllTrueVecI16x8 = _BinaryenAllTrueVecI16x8(),
|
||||
NegVecI32x4 = _BinaryenNegVecI32x4(),
|
||||
AnyTrueVecI32x4 = _BinaryenAnyTrueVecI32x4(),
|
||||
AllTrueVecI32x4 = _BinaryenAllTrueVecI32x4(),
|
||||
NegVecI64x2 = _BinaryenNegVecI64x2(),
|
||||
AnyTrueVecI64x2 = _BinaryenAnyTrueVecI64x2(),
|
||||
AllTrueVecI64x2 = _BinaryenAllTrueVecI64x2(),
|
||||
AbsVecF32x4 = _BinaryenAbsVecF32x4(),
|
||||
NegVecF32x4 = _BinaryenNegVecF32x4(),
|
||||
SqrtVecF32x4 = _BinaryenSqrtVecF32x4(),
|
||||
AbsVecF64x2 = _BinaryenAbsVecF64x2(),
|
||||
NegVecF64x2 = _BinaryenNegVecF64x2(),
|
||||
SqrtVecF64x2 = _BinaryenSqrtVecF64x2(),
|
||||
TruncSatSVecF32x4ToVecI32x4 = _BinaryenTruncSatSVecF32x4ToVecI32x4(),
|
||||
TruncSatUVecF32x4ToVecI32x4 = _BinaryenTruncSatUVecF32x4ToVecI32x4(),
|
||||
TruncSatSVecF64x2ToVecI64x2 = _BinaryenTruncSatSVecF64x2ToVecI64x2(),
|
||||
TruncSatUVecF64x2ToVecI64x2 = _BinaryenTruncSatUVecF64x2ToVecI64x2(),
|
||||
ConvertSVecI32x4ToVecF32x4 = _BinaryenConvertSVecI32x4ToVecF32x4(),
|
||||
ConvertUVecI32x4ToVecF32x4 = _BinaryenConvertUVecI32x4ToVecF32x4(),
|
||||
ConvertSVecI64x2ToVecF64x2 = _BinaryenConvertSVecI64x2ToVecF64x2(),
|
||||
ConvertUVecI64x2ToVecF64x2 = _BinaryenConvertUVecI64x2ToVecF64x2(),
|
||||
// see: https://github.com/WebAssembly/simd
|
||||
EqVecI8x16 = _BinaryenEqVecI8x16(),
|
||||
NeVecI8x16 = _BinaryenNeVecI8x16(),
|
||||
LtSVecI8x16 = _BinaryenLtSVecI8x16(),
|
||||
@ -344,6 +327,59 @@ export enum SIMDOp {
|
||||
MaxVecF64x2 = _BinaryenMaxVecF64x2()
|
||||
}
|
||||
|
||||
export enum HostOp {
|
||||
CurrentMemory = _BinaryenCurrentMemory(),
|
||||
GrowMemory = _BinaryenGrowMemory(),
|
||||
|
||||
// see: https://github.com/WebAssembly/bulk-memory-operations
|
||||
// MoveMemory
|
||||
// SetMemory
|
||||
}
|
||||
|
||||
export enum AtomicRMWOp {
|
||||
Add = _BinaryenAtomicRMWAdd(),
|
||||
Sub = _BinaryenAtomicRMWSub(),
|
||||
And = _BinaryenAtomicRMWAnd(),
|
||||
Or = _BinaryenAtomicRMWOr(),
|
||||
Xor = _BinaryenAtomicRMWXor(),
|
||||
Xchg = _BinaryenAtomicRMWXchg()
|
||||
}
|
||||
|
||||
export enum SIMDExtractOp {
|
||||
ExtractLaneSVecI8x16 = _BinaryenExtractLaneSVecI8x16(),
|
||||
ExtractLaneUVecI8x16 = _BinaryenExtractLaneUVecI8x16(),
|
||||
ExtractLaneSVecI16x8 = _BinaryenExtractLaneSVecI16x8(),
|
||||
ExtractLaneUVecI16x8 = _BinaryenExtractLaneUVecI16x8(),
|
||||
ExtractLaneVecI32x4 = _BinaryenExtractLaneVecI32x4(),
|
||||
ExtractLaneVecI64x2 = _BinaryenExtractLaneVecI64x2(),
|
||||
ExtractLaneVecF32x4 = _BinaryenExtractLaneVecF32x4(),
|
||||
ExtractLaneVecF64x2 = _BinaryenExtractLaneVecF64x2(),
|
||||
}
|
||||
|
||||
export enum SIMDReplaceOp {
|
||||
ReplaceLaneVecI8x16 = _BinaryenReplaceLaneVecI8x16(),
|
||||
ReplaceLaneVecI16x8 = _BinaryenReplaceLaneVecI16x8(),
|
||||
ReplaceLaneVecI32x4 = _BinaryenReplaceLaneVecI32x4(),
|
||||
ReplaceLaneVecI64x2 = _BinaryenReplaceLaneVecI64x2(),
|
||||
ReplaceLaneVecF32x4 = _BinaryenReplaceLaneVecF32x4(),
|
||||
ReplaceLaneVecF64x2 = _BinaryenReplaceLaneVecF64x2()
|
||||
}
|
||||
|
||||
export enum SIMDShiftOp { // FIXME: seems to be missing in binaryen-c.h
|
||||
ShlVecI8x16,
|
||||
ShrSVecI8x16,
|
||||
ShrUVecI8x16,
|
||||
ShlVecI16x8,
|
||||
ShrSVecI16x8,
|
||||
ShrUVecI16x8,
|
||||
ShlVecI32x4,
|
||||
ShrSVecI32x4,
|
||||
ShrUVecI32x4,
|
||||
ShlVecI64x2,
|
||||
ShrSVecI64x2,
|
||||
ShrUVecI64x2
|
||||
}
|
||||
|
||||
export class MemorySegment {
|
||||
|
||||
buffer: Uint8Array;
|
||||
@ -510,9 +546,10 @@ export class Module {
|
||||
signed: bool,
|
||||
ptr: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
offset: Index = 0,
|
||||
align: Index = bytes // naturally aligned by default
|
||||
): ExpressionRef {
|
||||
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, /* always aligned */ bytes, type, ptr);
|
||||
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, align, type, ptr);
|
||||
}
|
||||
|
||||
createStore(
|
||||
@ -520,9 +557,10 @@ export class Module {
|
||||
ptr: ExpressionRef,
|
||||
value: ExpressionRef,
|
||||
type: NativeType,
|
||||
offset: Index = 0
|
||||
offset: Index = 0,
|
||||
align: Index = bytes // naturally aligned by default
|
||||
): ExpressionRef {
|
||||
return _BinaryenStore(this.ref, bytes, offset, /* always aligned */ bytes, ptr, value, type);
|
||||
return _BinaryenStore(this.ref, bytes, offset, align, ptr, value, type);
|
||||
}
|
||||
|
||||
createAtomicLoad(
|
||||
@ -732,6 +770,55 @@ export class Module {
|
||||
return _BinaryenMemoryFill(this.ref, dest, value, size);
|
||||
}
|
||||
|
||||
// simd
|
||||
|
||||
createSIMDExtract(
|
||||
op: SIMDExtractOp,
|
||||
vec: ExpressionRef,
|
||||
idx: u8
|
||||
): ExpressionRef {
|
||||
return _BinaryenSIMDExtract(this.ref, op, vec, idx);
|
||||
}
|
||||
|
||||
createSIMDReplace(
|
||||
op: SIMDReplaceOp,
|
||||
vec: ExpressionRef,
|
||||
idx: u8,
|
||||
value: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenSIMDReplace(this.ref, op, vec, idx, value);
|
||||
}
|
||||
|
||||
createSIMDShuffle(
|
||||
vec1: ExpressionRef,
|
||||
vec2: ExpressionRef,
|
||||
mask: Uint8Array
|
||||
): ExpressionRef {
|
||||
assert(mask.length == 16);
|
||||
var cArr = allocU8Array(mask);
|
||||
try {
|
||||
return _BinaryenSIMDShuffle(this.ref, vec1, vec2, cArr);
|
||||
} finally {
|
||||
memory.free(cArr);
|
||||
}
|
||||
}
|
||||
|
||||
createSIMDBitselect(
|
||||
vec1: ExpressionRef,
|
||||
vec2: ExpressionRef,
|
||||
cond: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenSIMDBitselect(this.ref, vec1, vec2, cond);
|
||||
}
|
||||
|
||||
createSIMDShift(
|
||||
op: SIMDShiftOp,
|
||||
vec: ExpressionRef,
|
||||
shift: ExpressionRef
|
||||
): ExpressionRef {
|
||||
return _BinaryenSIMDShift(this.ref, op, vec, shift);
|
||||
}
|
||||
|
||||
// meta
|
||||
|
||||
addGlobal(
|
||||
|
@ -523,6 +523,8 @@ export class Program extends DiagnosticEmitter {
|
||||
i64_new(options.hasFeature(Feature.BULK_MEMORY) ? 1 : 0, 0));
|
||||
this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_SIMD, Type.bool,
|
||||
i64_new(options.hasFeature(Feature.SIMD) ? 1 : 0, 0));
|
||||
this.registerConstantInteger(LibrarySymbols.ASC_FEATURE_THREADS, Type.bool,
|
||||
i64_new(options.hasFeature(Feature.THREADS) ? 1 : 0, 0));
|
||||
|
||||
// remember deferred elements
|
||||
var queuedImports = new Array<QueuedImport>();
|
||||
@ -2564,6 +2566,7 @@ export class Function extends TypedElement {
|
||||
tempI64s: Local[] | null = null;
|
||||
tempF32s: Local[] | null = null;
|
||||
tempF64s: Local[] | null = null;
|
||||
tempV128s: Local[] | null = null;
|
||||
|
||||
// used by flows to keep track of break labels
|
||||
nextBreakId: i32 = 0;
|
||||
|
@ -74,7 +74,8 @@ import {
|
||||
} from "./common";
|
||||
|
||||
import {
|
||||
makeMap
|
||||
makeMap,
|
||||
isPowerOf2
|
||||
} from "./util";
|
||||
|
||||
import {
|
||||
@ -1572,13 +1573,9 @@ export class Resolver extends DiagnosticEmitter {
|
||||
}
|
||||
if (!fieldType) break; // did report above
|
||||
let fieldInstance = new Field(<FieldPrototype>member, instance, fieldType);
|
||||
switch (fieldType.byteSize) { // align
|
||||
case 1: break;
|
||||
case 2: { if (memoryOffset & 1) ++memoryOffset; break; }
|
||||
case 4: { if (memoryOffset & 3) memoryOffset = (memoryOffset | 3) + 1; break; }
|
||||
case 8: { if (memoryOffset & 7) memoryOffset = (memoryOffset | 7) + 1; break; }
|
||||
default: assert(false);
|
||||
}
|
||||
assert(isPowerOf2(fieldType.byteSize));
|
||||
let mask = fieldType.byteSize - 1;
|
||||
if (memoryOffset & mask) memoryOffset = (memoryOffset | mask) + 1;
|
||||
fieldInstance.memoryOffset = memoryOffset;
|
||||
memoryOffset += fieldType.byteSize;
|
||||
instance.add(member.name, fieldInstance); // reports
|
||||
|
@ -55,6 +55,8 @@ export const enum TypeKind {
|
||||
F64,
|
||||
|
||||
// vectors
|
||||
|
||||
/** A 128-bit vector. */
|
||||
V128,
|
||||
|
||||
// other
|
||||
|
@ -10,3 +10,8 @@ export * from "./collections";
|
||||
export * from "./path";
|
||||
export * from "./text";
|
||||
export * from "./binary";
|
||||
|
||||
/** Tests if `x` is a power of two. */
|
||||
export function isPowerOf2(x: i32): bool {
|
||||
return x != 0 && (x & (x - 1)) == 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user