Implement v128 instructions (#508)

This commit is contained in:
Daniel Wirtz
2019-02-28 17:36:22 +01:00
committed by GitHub
parent cdf40578b6
commit e1f1a3b49c
25 changed files with 6647 additions and 286 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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";

View File

@ -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();

View File

@ -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.";

View File

@ -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,

View File

@ -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;

View File

@ -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(

View File

@ -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;

View File

@ -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

View File

@ -55,6 +55,8 @@ export const enum TypeKind {
F64,
// vectors
/** A 128-bit vector. */
V128,
// other

View File

@ -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;
}