Smarter temp locals; Less binaryen boilerplate

This commit is contained in:
dcodeIO 2017-12-12 09:32:03 +01:00
parent 7a5f7dba50
commit f75b962c74
9 changed files with 219 additions and 319 deletions

8
assembly.d.ts vendored
View File

@ -115,4 +115,10 @@ interface IArguments {}
interface Number {} interface Number {}
interface Object {} interface Object {}
interface RegExp {} interface RegExp {}
interface String {}
declare class String {
static fromCharCode(ls: i32, hs?: i32): string;
static fromCharCodes(arr: u16[]): string;
static fromCodePoint(cp: i32): string;
static fromCodePoints(arr: i32[]): string;
}

3
portable.d.ts vendored
View File

@ -83,6 +83,9 @@ declare class Int32Array extends Array<i32> {}
declare class String { declare class String {
static fromCharCode(ls: i32, hs?: i32): string; static fromCharCode(ls: i32, hs?: i32): string;
static fromCharCodes(arr: u16[]): string;
static fromCodePoint(cp: i32): string;
static fromCodePoints(arr: i32[]): string;
readonly length: i32; readonly length: i32;
indexOf(subject: string): i32; indexOf(subject: string): i32;
charCodeAt(index: i32): i32; charCodeAt(index: i32): i32;

View File

@ -28,3 +28,6 @@ AssertionError.prototype.message = "assertion failed";
globalScope["assert"] = function assert(isTrue) { if (!isTrue) throw new AssertionError(); }; globalScope["assert"] = function assert(isTrue) { if (!isTrue) throw new AssertionError(); };
globalScope["changetype"] = function changetype(value) { return value; } globalScope["changetype"] = function changetype(value) { return value; }
String["fromCharCodes"] = function fromCharCodes(arr) { return String.fromCharCode.apply(String, arr); }
String["fromCodePoints"] = function fromCodePoints(arr) { return String.fromCodePoint.apply(String, arr); }

View File

@ -156,7 +156,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
: module.createUnary(UnaryOp.AbsF64, arg0); : module.createUnary(UnaryOp.AbsF64, arg0);
if (typeArguments[0].isAnyInteger) { if (typeArguments[0].isAnyInteger) {
if (typeArguments[0].isSignedInteger) { if (typeArguments[0].isSignedInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
if (typeArguments[0].isLongInteger) if (typeArguments[0].isLongInteger)
return module.createSelect( return module.createSelect(
module.createBinary(BinaryOp.SubI64, module.createBinary(BinaryOp.SubI64,
@ -198,8 +198,9 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
? module.createBinary(BinaryOp.MaxF32, arg0, arg1) ? module.createBinary(BinaryOp.MaxF32, arg0, arg1)
: module.createBinary(BinaryOp.MaxF64, arg0, arg1); : module.createBinary(BinaryOp.MaxF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) { if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); tempLocal0 = compiler.currentFunction.getTempLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]); tempLocal1 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
compiler.currentFunction.freeTempLocal(tempLocal0);
if (typeArguments[0].isLongInteger) if (typeArguments[0].isLongInteger)
return module.createSelect( return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0), module.createTeeLocal(tempLocal0.index, arg0),
@ -233,8 +234,9 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
? module.createBinary(BinaryOp.MinF32, arg0, arg1) ? module.createBinary(BinaryOp.MinF32, arg0, arg1)
: module.createBinary(BinaryOp.MinF64, arg0, arg1); : module.createBinary(BinaryOp.MinF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) { if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]); tempLocal0 = compiler.currentFunction.getTempLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]); tempLocal1 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
compiler.currentFunction.freeTempLocal(tempLocal0);
if (typeArguments[0].isLongInteger) if (typeArguments[0].isLongInteger)
return module.createSelect( return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0), module.createTeeLocal(tempLocal0.index, arg0),
@ -428,13 +430,13 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) { if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32); tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f32);
return module.createBinary(BinaryOp.NeF32, return module.createBinary(BinaryOp.NeF32,
module.createTeeLocal(tempLocal0.index, arg0), module.createTeeLocal(tempLocal0.index, arg0),
module.createGetLocal(tempLocal0.index, NativeType.F32) module.createGetLocal(tempLocal0.index, NativeType.F32)
); );
} else { } else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64); tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f64);
return module.createBinary(BinaryOp.NeF64, return module.createBinary(BinaryOp.NeF64,
module.createTeeLocal(tempLocal0.index, arg0), module.createTeeLocal(tempLocal0.index, arg0),
module.createGetLocal(tempLocal0.index, NativeType.F64) module.createGetLocal(tempLocal0.index, NativeType.F64)
@ -453,7 +455,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) { if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32); tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f32);
return module.createSelect( return module.createSelect(
module.createBinary(BinaryOp.NeF32, module.createBinary(BinaryOp.NeF32,
module.createUnary(UnaryOp.AbsF32, module.createUnary(UnaryOp.AbsF32,
@ -468,7 +470,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
) )
); );
} else { } else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64); tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f64);
return module.createSelect( return module.createSelect(
module.createBinary(BinaryOp.NeF64, module.createBinary(BinaryOp.NeF64,
module.createUnary(UnaryOp.AbsF64, module.createUnary(UnaryOp.AbsF64,

View File

@ -11,28 +11,7 @@ import {
NativeType, NativeType,
FunctionTypeRef, FunctionTypeRef,
FunctionRef, FunctionRef,
ExpressionId, ExpressionId
getExpressionId,
getExpressionType,
getFunctionBody,
getConstValueI32,
getConstValueI64Low,
getConstValueI64High,
getConstValueF32,
getConstValueF64,
getGetLocalIndex,
getGetGlobalName,
isLoadAtomic,
isLoadSigned,
getLoadBytes,
getLoadOffset,
getLoadPtr,
getUnaryOp,
getUnaryValue,
getBinaryOp,
getBinaryLeft,
getBinaryRight
} from "./module"; } from "./module";
import { import {
@ -373,10 +352,10 @@ export class Compiler extends DiagnosticEmitter {
} else if (declaration) { } else if (declaration) {
if (declaration.initializer) { if (declaration.initializer) {
initializer = this.compileExpression(declaration.initializer, type); initializer = this.compileExpression(declaration.initializer, type);
if (getExpressionId(initializer) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
if (!element.isMutable) { if (!element.isMutable) {
initializer = this.precomputeExpressionRef(initializer); initializer = this.precomputeExpressionRef(initializer);
if (getExpressionId(initializer) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
initializeInStart = true; initializeInStart = true;
} }
@ -395,19 +374,19 @@ export class Compiler extends DiagnosticEmitter {
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer); this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
if (!element.isMutable) { if (!element.isMutable) {
element.hasConstantValue = true; element.hasConstantValue = true;
const exprType: NativeType = getExpressionType(initializer); const exprType: NativeType = _BinaryenExpressionGetType(initializer);
switch (exprType) { switch (exprType) {
case NativeType.I32: case NativeType.I32:
element.constantIntegerValue = new I64(getConstValueI32(initializer), 0); element.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initializer), 0);
break; break;
case NativeType.I64: case NativeType.I64:
element.constantIntegerValue = new I64(getConstValueI64Low(initializer), getConstValueI64High(initializer)); element.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initializer), _BinaryenConstGetValueI64High(initializer));
break; break;
case NativeType.F32: case NativeType.F32:
element.constantFloatValue = getConstValueF32(initializer); element.constantFloatValue = _BinaryenConstGetValueF32(initializer);
break; break;
case NativeType.F64: case NativeType.F64:
element.constantFloatValue = getConstValueF64(initializer); element.constantFloatValue = _BinaryenConstGetValueF64(initializer);
break; break;
default: default:
throw new Error("unexpected initializer type"); throw new Error("unexpected initializer type");
@ -439,9 +418,9 @@ export class Compiler extends DiagnosticEmitter {
let initializeInStart: bool = false; let initializeInStart: bool = false;
if (declaration.value) { if (declaration.value) {
initializer = this.compileExpression(<Expression>declaration.value, Type.i32); initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
if (getExpressionId(initializer) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
initializer = this.precomputeExpressionRef(initializer); initializer = this.precomputeExpressionRef(initializer);
if (getExpressionId(initializer) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
if (element.isConstant) if (element.isConstant)
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
initializeInStart = true; initializeInStart = true;
@ -466,9 +445,9 @@ export class Compiler extends DiagnosticEmitter {
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer)); this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
} else { } else {
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer); this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
if (getExpressionType(initializer) == NativeType.I32) { if (_BinaryenExpressionGetType(initializer) == NativeType.I32) {
val.hasConstantValue = true; val.hasConstantValue = true;
val.constantValue = getConstValueI32(initializer); val.constantValue = _BinaryenConstGetValueI32(initializer);
} else } else
throw new Error("unexpected initializer type"); throw new Error("unexpected initializer type");
} }
@ -1068,7 +1047,7 @@ export class Compiler extends DiagnosticEmitter {
typeRef = this.module.addFunctionType(typeToSignatureNamePart(this.currentType), nativeType, []); typeRef = this.module.addFunctionType(typeToSignatureNamePart(this.currentType), nativeType, []);
const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr); const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr);
this.module.runPasses([ "precompute" ], funcRef); this.module.runPasses([ "precompute" ], funcRef);
const ret: ExpressionRef = getFunctionBody(funcRef); const ret: ExpressionRef = _BinaryenFunctionGetBody(funcRef);
this.module.removeFunction("__precompute"); this.module.removeFunction("__precompute");
// TODO: also remove the function type somehow if no longer used or make the C-API accept // TODO: also remove the function type somehow if no longer used or make the C-API accept
// a `null` typeRef, using an implicit type. // a `null` typeRef, using an implicit type.
@ -1240,41 +1219,6 @@ export class Compiler extends DiagnosticEmitter {
return expr; return expr;
} }
cloneExpressionRef(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = 0x7fffffff): ExpressionRef {
// currently supports side effect free expressions only
if (maxDepth < 0)
return 0;
let nested1: ExpressionRef,
nested2: ExpressionRef;
switch (getExpressionId(expr)) {
case ExpressionId.Const:
switch (getExpressionType(expr)) {
case NativeType.I32: return this.module.createI32(getConstValueI32(expr));
case NativeType.I64: return this.module.createI64(getConstValueI64Low(expr), getConstValueI64High(expr));
case NativeType.F32: return this.module.createF32(getConstValueF32(expr));
case NativeType.F64: return this.module.createF64(getConstValueF64(expr));
default: throw new Error("unexpected expression type");
}
case ExpressionId.GetLocal:
return this.module.createGetLocal(getGetLocalIndex(expr), getExpressionType(expr));
// case ExpressionId.GetGlobal: explodes if it doesn't have a name
// return this.module.createGetGlobal(getGetGlobalName(expr), getExpressionType(expr));
case ExpressionId.Load:
if (!(nested1 = this.cloneExpressionRef(getLoadPtr(expr), noSideEffects, maxDepth - 1))) break;
return isLoadAtomic(expr)
? this.module.createAtomicLoad(getLoadBytes(expr), nested1, getExpressionType(expr), getLoadOffset(expr))
: this.module.createLoad(getLoadBytes(expr), isLoadSigned(expr), nested1, getExpressionType(expr), getLoadOffset(expr));
case ExpressionId.Unary:
if (!(nested1 = this.cloneExpressionRef(getUnaryValue(expr), noSideEffects, maxDepth - 1))) break;
return this.module.createUnary(getUnaryOp(expr), nested1);
case ExpressionId.Binary:
if (!(nested1 = this.cloneExpressionRef(getBinaryLeft(expr), noSideEffects, maxDepth - 1))) break;
if (!(nested2 = this.cloneExpressionRef(getBinaryLeft(expr), noSideEffects, maxDepth - 1))) break;
return this.module.createBinary(getBinaryOp(expr), nested1, nested2);
}
return 0;
}
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef { compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (!toType) if (!toType)
@ -1537,7 +1481,7 @@ export class Compiler extends DiagnosticEmitter {
right = this.compileExpression(expression.right, this.currentType); right = this.compileExpression(expression.right, this.currentType);
// simplify if left is free of side effects while tolerating two levels of nesting, e.g., i32.load(i32.load(i32.const)) // simplify if left is free of side effects while tolerating two levels of nesting, e.g., i32.load(i32.load(i32.const))
// if (condition = this.cloneExpressionRef(left, true, 2)) // if (condition = this.module.cloneExpression(left, true, 2))
// return this.module.createIf( // return this.module.createIf(
// this.currentType.isLongInteger // this.currentType.isLongInteger
// ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0)) // ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))
@ -1570,7 +1514,7 @@ export class Compiler extends DiagnosticEmitter {
right = this.compileExpression(expression.right, this.currentType); right = this.compileExpression(expression.right, this.currentType);
// simplify if left is free of side effects while tolerating two levels of nesting // simplify if left is free of side effects while tolerating two levels of nesting
// if (condition = this.cloneExpressionRef(left, true, 2)) // if (condition = this.module.cloneExpression(left, true, 2))
// return this.module.createIf( // return this.module.createIf(
// this.currentType.isLongInteger // this.currentType.isLongInteger
// ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0)) // ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))

View File

@ -1,4 +1,5 @@
import { import {
Module, Module,
NativeType, NativeType,
ExpressionId, ExpressionId,
@ -9,7 +10,9 @@ import {
FunctionRef, FunctionRef,
ExpressionRef, ExpressionRef,
Index, Index,
readString readString
} from "./module"; } from "./module";
import { I64 } from "./util"; import { I64 } from "./util";

View File

@ -751,7 +751,7 @@ export class Module {
} }
interpret(): void { interpret(): void {
return _BinaryenModuleInterpret(this.ref); _BinaryenModuleInterpret(this.ref);
} }
write(output: usize, outputSize: usize = 1048576): usize { write(output: usize, outputSize: usize = 1048576): usize {
@ -759,11 +759,11 @@ export class Module {
} }
print(): void { print(): void {
return _BinaryenModulePrint(this.ref); _BinaryenModulePrint(this.ref);
} }
printAsmjs(): void { printAsmjs(): void {
return _BinaryenModulePrintAsmjs(this.ref); _BinaryenModulePrintAsmjs(this.ref);
} }
toBinary(bufferSize: usize = 1048576): Uint8Array { toBinary(bufferSize: usize = 1048576): Uint8Array {
@ -785,132 +785,48 @@ export class Module {
createRelooper(): Relooper { createRelooper(): Relooper {
return this.noEmit ? Relooper.createStub(this) : Relooper.create(this); return this.noEmit ? Relooper.createStub(this) : Relooper.create(this);
} }
}
export function getExpressionId(expr: ExpressionRef): ExpressionId { // currently supports side effect free expressions only
return _BinaryenExpressionGetId(expr); cloneExpression(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = 0x7fffffff): ExpressionRef {
} if (this.noEmit || maxDepth < 0) return 0;
export function getExpressionType(expr: ExpressionRef): NativeType { let nested1: ExpressionRef,
return _BinaryenExpressionGetType(expr); nested2: ExpressionRef;
}
export function printExpression(expr: ExpressionRef): void { switch (_BinaryenExpressionGetId(expr)) {
return _BinaryenExpressionPrint(expr);
}
export function getConstValueI32(expr: ExpressionRef): i32 { case ExpressionId.Const:
return _BinaryenConstGetValueI32(expr); switch (_BinaryenExpressionGetType(expr)) {
} case NativeType.I32: return this.createI32(_BinaryenConstGetValueI32(expr));
case NativeType.I64: return this.createI64(_BinaryenConstGetValueI64Low(expr), _BinaryenConstGetValueI64High(expr));
case NativeType.F32: return this.createF32(_BinaryenConstGetValueF32(expr));
case NativeType.F64: return this.createF64(_BinaryenConstGetValueF64(expr));
default: throw new Error("unexpected constant type");
}
export function getConstValueI64Low(expr: ExpressionRef): i32 { case ExpressionId.GetLocal:
return _BinaryenConstGetValueI64Low(expr); return _BinaryenGetLocal(this.ref, _BinaryenGetLocalGetIndex(expr), _BinaryenExpressionGetType(expr));
}
export function getConstValueI64High(expr: ExpressionRef): i32 { // case ExpressionId.GetGlobal: explodes if it doesn't have a name
return _BinaryenConstGetValueI64High(expr); // return _BinaryenGetGlobal(this.ref, _BinaryenGetGlobalGetName(expr), _BinaryenExpressionGetType(expr));
}
export function getConstValueI64(expr: ExpressionRef): I64 { case ExpressionId.Load:
return new I64( if (!(nested1 = this.cloneExpression(_BinaryenLoadGetPtr(expr), noSideEffects, maxDepth - 1))) break;
_BinaryenConstGetValueI64Low(expr), return _BinaryenLoadIsAtomic(expr)
_BinaryenConstGetValueI64High(expr) ? _BinaryenAtomicLoad(this.ref, _BinaryenLoadGetBytes(expr), _BinaryenLoadGetOffset(expr), _BinaryenExpressionGetType(expr), nested1)
); : _BinaryenLoad(this.ref, _BinaryenLoadGetBytes(expr), _BinaryenLoadIsSigned(expr) ? 1 : 0, _BinaryenLoadGetOffset(expr), _BinaryenLoadGetAlign(expr), _BinaryenExpressionGetType(expr), nested1);
}
export function getConstValueF32(expr: ExpressionRef): f32 { case ExpressionId.Unary:
return _BinaryenConstGetValueF32(expr); if (!(nested1 = this.cloneExpression(_BinaryenUnaryGetValue(expr), noSideEffects, maxDepth - 1))) break;
} return _BinaryenUnary(this.ref, _BinaryenUnaryGetOp(expr), nested1);
export function getConstValueF64(expr: ExpressionRef): f64 { case ExpressionId.Binary:
return _BinaryenConstGetValueF64(expr); if (!(nested1 = this.cloneExpression(_BinaryenBinaryGetLeft(expr), noSideEffects, maxDepth - 1))) break;
} if (!(nested2 = this.cloneExpression(_BinaryenBinaryGetRight(expr), noSideEffects, maxDepth - 1))) break;
return _BinaryenBinary(this.ref, _BinaryenBinaryGetOp(expr), nested1, nested2);
export function getGetLocalIndex(expr: ExpressionRef): Index { }
return _BinaryenGetLocalGetIndex(expr); return 0;
} }
export function getGetGlobalName(expr: ExpressionRef): string | null {
return readString(_BinaryenGetGlobalGetName(expr));
}
export function isLoadAtomic(expr: ExpressionRef): bool {
return _BinaryenLoadIsAtomic(expr);
}
export function isLoadSigned(expr: ExpressionRef): bool {
return _BinaryenLoadIsSigned(expr);
}
export function getLoadBytes(expr: ExpressionRef): u32 {
return _BinaryenLoadGetBytes(expr);
}
export function getLoadOffset(expr: ExpressionRef): u32 {
return _BinaryenLoadGetOffset(expr);
}
export function getLoadPtr(expr: ExpressionRef): ExpressionRef {
return _BinaryenLoadGetPtr(expr);
}
export function getFunctionBody(func: FunctionRef): ExpressionRef {
return _BinaryenFunctionGetBody(func);
}
export function getUnaryOp(expr: ExpressionRef): UnaryOp {
return _BinaryenUnaryGetOp(expr);
}
export function getUnaryValue(expr: ExpressionRef): ExpressionRef {
return _BinaryenUnaryGetValue(expr);
}
export function getBinaryOp(expr: ExpressionRef): BinaryOp {
return _BinaryenBinaryGetOp(expr);
}
export function getBinaryLeft(expr: ExpressionRef): ExpressionRef {
return _BinaryenBinaryGetLeft(expr);
}
export function getBinaryRight(expr: ExpressionRef): ExpressionRef {
return _BinaryenBinaryGetRight(expr);
}
export function getSelectIfTrue(expr: ExpressionRef): ExpressionRef {
return _BinaryenSelectGetIfTrue(expr);
}
export function getSelectIfFalse(expr: ExpressionRef): ExpressionRef {
return _BinaryenSelectGetIfFalse(expr);
}
export function getSelectCondition(expr: ExpressionRef): ExpressionRef {
return _BinaryenSelectGetCondition(expr);
}
export function getReturnValue(expr: ExpressionRef): ExpressionRef {
return _BinaryenReturnGetValue(expr);
}
export function getDropValue(expr: ExpressionRef): ExpressionRef {
return _BinaryenDropGetValue(expr);
}
export function getHostOp(expr: ExpressionRef): HostOp {
return _BinaryenHostGetOp(expr);
}
export function getHostNameOperand(expr: ExpressionRef): string | null {
return readString(_BinaryenHostGetNameOperand(expr));
}
export function getHostOperands(expr: ExpressionRef): BinaryenExpressionRef[] {
const num: Index = _BinaryenHostGetNumOperands(expr);
const arr: BinaryenExpressionRef[] = new Array(num);
for (let i: Index = 0; i < num; ++i) arr[i] = _BinaryenHostGetOperand(expr, i);
return arr;
} }
export class Relooper { export class Relooper {
@ -990,6 +906,7 @@ function allocI32Array(i32s: i32[] | null): usize {
let idx: usize = ptr; let idx: usize = ptr;
for (let i: i32 = 0, k: i32 = (<i32[]>i32s).length; i < k; ++i) { for (let i: i32 = 0, k: i32 = (<i32[]>i32s).length; i < k; ++i) {
let val: i32 = (<i32[]>i32s)[i]; let val: i32 = (<i32[]>i32s)[i];
// store<i32>(idx, val) is not portable
store<u8>(idx , ( val & 0xff) as u8); store<u8>(idx , ( val & 0xff) as u8);
store<u8>(idx + 1, ((val >> 8) & 0xff) as u8); store<u8>(idx + 1, ((val >> 8) & 0xff) as u8);
store<u8>(idx + 2, ((val >> 16) & 0xff) as u8); store<u8>(idx + 2, ((val >> 16) & 0xff) as u8);
@ -1022,7 +939,7 @@ function stringLengthUTF8(str: string): usize {
} }
function allocString(str: string | null): usize { function allocString(str: string | null): usize {
if (!str) return 0; if (str == null) return 0;
const ptr: usize = Heap.allocate(stringLengthUTF8((<string>str)) + 1); const ptr: usize = Heap.allocate(stringLengthUTF8((<string>str)) + 1);
let idx: usize = ptr; let idx: usize = ptr;
for (let i: i32 = 0, k: i32 = (<string>str).length; i < k; ++i) { for (let i: i32 = 0, k: i32 = (<string>str).length; i < k; ++i) {
@ -1064,18 +981,18 @@ function allocString(str: string | null): usize {
export function readString(ptr: usize): string | null { export function readString(ptr: usize): string | null {
if (!ptr) return null; if (!ptr) return null;
const utf16le: u32[] = []; const arr: i32[] = [];
// the following is based on Emscripten's UTF8ArrayToString // the following is based on Emscripten's UTF8ArrayToString
let cp: u32; let cp: u32;
let u1: u32, u2: u32, u3: u32, u4: u32, u5: u32; let u1: u32, u2: u32, u3: u32, u4: u32, u5: u32;
while (cp = load<u8>(ptr++)) { while (cp = load<u8>(ptr++)) {
if (!(cp & 0x80)) { if (!(cp & 0x80)) {
utf16le.push(cp); arr.push(cp);
continue; continue;
} }
u1 = load<u8>(ptr++) & 63; u1 = load<u8>(ptr++) & 63;
if ((cp & 0xE0) == 0xC0) { if ((cp & 0xE0) == 0xC0) {
utf16le.push(((cp & 31) << 6) | u1); arr.push(((cp & 31) << 6) | u1);
continue; continue;
} }
u2 = load<u8>(ptr++) & 63; u2 = load<u8>(ptr++) & 63;
@ -1095,14 +1012,14 @@ export function readString(ptr: usize): string | null {
} }
} }
} }
if (cp < 0x10000) { // if (cp < 0x10000) {
utf16le.push(cp); // arr.push(cp);
} else { // } else {
var ch = cp - 0x10000; // var ch = cp - 0x10000;
utf16le.push(0xD800 | (ch >> 10)); // arr.push(0xD800 | (ch >> 10));
utf16le.push(0xDC00 | (ch & 0x3FF)); // arr.push(0xDC00 | (ch & 0x3FF));
} // }
} }
// FIXME: not portable and prone to stack overflows. Maybe use CString from stdlib? // return String.fromCharCodes(arr);
return String.fromCharCode.apply(utf16le); return String.fromCodePoints(arr);
} }

View File

@ -1,5 +1,5 @@
import { initialize as initializeBuiltins } from "./builtins"; import { initialize as initializeBuiltins } from "./builtins";
import { Target } from "./compiler"; import { Target, typeToNativeType } from "./compiler";
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants"; import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics"; import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
import { Type, typesToString } from "./types"; import { Type, typesToString } from "./types";
@ -45,6 +45,7 @@ import {
mangleInternalName mangleInternalName
} from "./ast"; } from "./ast";
import { NativeType } from "./module";
class QueuedExport { class QueuedExport {
isReExport: bool; isReExport: bool;
@ -973,6 +974,53 @@ export class Function extends Element {
return local; return local;
} }
private tempI32s: Local[] = [];
private tempI64s: Local[] = [];
private tempF32s: Local[] = [];
private tempF64s: Local[] = [];
getTempLocal(type: Type): Local {
let temps: Local[];
switch (typeToNativeType(type)) {
case NativeType.I32: temps = this.tempI32s; break;
case NativeType.I64: temps = this.tempI64s; break;
case NativeType.F32: temps = this.tempF32s; break;
case NativeType.F64: temps = this.tempF64s; break;
default: throw new Error("unexpected type");
}
if (temps.length > 0)
return temps.pop();
return this.addLocal(type);
}
freeTempLocal(local: Local): void {
let temps: Local[];
switch (typeToNativeType(local.type)) {
case NativeType.I32: temps = this.tempI32s; break;
case NativeType.I64: temps = this.tempI64s; break;
case NativeType.F32: temps = this.tempF32s; break;
case NativeType.F64: temps = this.tempF64s; break;
default: throw new Error("unexpected type");
}
temps.push(local);
}
getAndFreeTempLocal(type: Type): Local {
let temps: Local[];
switch (typeToNativeType(type)) {
case NativeType.I32: temps = this.tempI32s; break;
case NativeType.I64: temps = this.tempI64s; break;
case NativeType.F32: temps = this.tempF32s; break;
case NativeType.F64: temps = this.tempF64s; break;
default: throw new Error("unexpected type");
}
if (temps.length > 0)
return temps[temps.length - 1];
let local: Local = this.addLocal(type);
temps.push(local);
return local;
}
/** Enters a(nother) break context. */ /** Enters a(nother) break context. */
enterBreakContext(): string { enterBreakContext(): string {
const id: i32 = this.nextBreakId++; const id: i32 = this.nextBreakId++;

View File

@ -13,36 +13,10 @@
(func $start (; 0 ;) (type $v) (func $start (; 0 ;) (type $v)
(local $0 i32) (local $0 i32)
(local $1 i32) (local $1 i32)
(local $2 i32) (local $2 i64)
(local $3 i32) (local $3 i64)
(local $4 i32) (local $4 f32)
(local $5 i32) (local $5 f64)
(local $6 i32)
(local $7 i32)
(local $8 i32)
(local $9 i32)
(local $10 i64)
(local $11 i64)
(local $12 i64)
(local $13 i64)
(local $14 i64)
(local $15 i64)
(local $16 f32)
(local $17 f32)
(local $18 f32)
(local $19 f32)
(local $20 f64)
(local $21 f64)
(local $22 f64)
(local $23 f64)
(local $24 f32)
(local $25 f64)
(local $26 f32)
(local $27 f32)
(local $28 f64)
(local $29 f64)
(local $30 f32)
(local $31 f64)
(drop (drop
(i32.clz (i32.clz
(i32.const 1) (i32.const 1)
@ -90,29 +64,29 @@
) )
(drop (drop
(select (select
(tee_local $1 (tee_local $0
(i32.const 1) (i32.const 1)
) )
(tee_local $2 (tee_local $1
(i32.const 2) (i32.const 2)
) )
(i32.gt_s (i32.gt_s
(get_local $0)
(get_local $1) (get_local $1)
(get_local $2)
) )
) )
) )
(drop (drop
(select (select
(tee_local $3 (tee_local $0
(i32.const 1) (i32.const 1)
) )
(tee_local $4 (tee_local $1
(i32.const 2) (i32.const 2)
) )
(i32.lt_s (i32.lt_s
(get_local $3) (get_local $0)
(get_local $4) (get_local $1)
) )
) )
) )
@ -147,16 +121,16 @@
(select (select
(i32.sub (i32.sub
(i32.const 0) (i32.const 0)
(tee_local $5 (tee_local $0
(i32.sub (i32.sub
(i32.const 0) (i32.const 0)
(i32.const 42) (i32.const 42)
) )
) )
) )
(get_local $5) (get_local $0)
(i32.lt_s (i32.lt_s
(get_local $5) (get_local $0)
(i32.const 0) (i32.const 0)
) )
) )
@ -172,15 +146,15 @@
) )
(set_global $builtins/i (set_global $builtins/i
(select (select
(tee_local $6 (tee_local $0
(i32.const 1) (i32.const 1)
) )
(tee_local $7 (tee_local $1
(i32.const 2) (i32.const 2)
) )
(i32.gt_s (i32.gt_s
(get_local $6) (get_local $0)
(get_local $7) (get_local $1)
) )
) )
) )
@ -195,15 +169,15 @@
) )
(set_global $builtins/i (set_global $builtins/i
(select (select
(tee_local $8 (tee_local $0
(i32.const 1) (i32.const 1)
) )
(tee_local $9 (tee_local $1
(i32.const 2) (i32.const 2)
) )
(i32.lt_s (i32.lt_s
(get_local $8) (get_local $0)
(get_local $9) (get_local $1)
) )
) )
) )
@ -247,16 +221,16 @@
(select (select
(i64.sub (i64.sub
(i64.const 0) (i64.const 0)
(tee_local $10 (tee_local $2
(i64.sub (i64.sub
(i64.const 0) (i64.const 0)
(i64.const 42) (i64.const 42)
) )
) )
) )
(get_local $10) (get_local $2)
(i64.lt_s (i64.lt_s
(get_local $10) (get_local $2)
(i64.const 0) (i64.const 0)
) )
) )
@ -292,16 +266,16 @@
(select (select
(i64.sub (i64.sub
(i64.const 0) (i64.const 0)
(tee_local $11 (tee_local $2
(i64.sub (i64.sub
(i64.const 0) (i64.const 0)
(i64.const 42) (i64.const 42)
) )
) )
) )
(get_local $11) (get_local $2)
(i64.lt_s (i64.lt_s
(get_local $11) (get_local $2)
(i64.const 0) (i64.const 0)
) )
) )
@ -317,15 +291,15 @@
) )
(set_global $builtins/I (set_global $builtins/I
(select (select
(tee_local $12 (tee_local $2
(i64.const 1) (i64.const 1)
) )
(tee_local $13 (tee_local $3
(i64.const 2) (i64.const 2)
) )
(i64.gt_s (i64.gt_s
(get_local $12) (get_local $2)
(get_local $13) (get_local $3)
) )
) )
) )
@ -340,15 +314,15 @@
) )
(set_global $builtins/I (set_global $builtins/I
(select (select
(tee_local $14 (tee_local $2
(i64.const 1) (i64.const 1)
) )
(tee_local $15 (tee_local $3
(i64.const 2) (i64.const 2)
) )
(i64.lt_s (i64.lt_s
(get_local $14) (get_local $2)
(get_local $15) (get_local $3)
) )
) )
) )
@ -417,17 +391,17 @@
) )
(drop (drop
(f32.ne (f32.ne
(tee_local $16 (tee_local $4
(f32.const 1.25) (f32.const 1.25)
) )
(get_local $16) (get_local $4)
) )
) )
(drop (drop
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $17 (tee_local $4
(f32.const 1.25) (f32.const 1.25)
) )
) )
@ -435,8 +409,8 @@
) )
(i32.const 0) (i32.const 0)
(f32.eq (f32.eq
(get_local $17) (get_local $4)
(get_local $17) (get_local $4)
) )
) )
) )
@ -496,17 +470,17 @@
) )
(set_global $builtins/b (set_global $builtins/b
(f32.ne (f32.ne
(tee_local $18 (tee_local $4
(f32.const 1.25) (f32.const 1.25)
) )
(get_local $18) (get_local $4)
) )
) )
(set_global $builtins/b (set_global $builtins/b
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $19 (tee_local $4
(f32.const 1.25) (f32.const 1.25)
) )
) )
@ -514,8 +488,8 @@
) )
(i32.const 0) (i32.const 0)
(f32.eq (f32.eq
(get_local $19) (get_local $4)
(get_local $19) (get_local $4)
) )
) )
) )
@ -581,17 +555,17 @@
) )
(drop (drop
(f64.ne (f64.ne
(tee_local $20 (tee_local $5
(f64.const 1.25) (f64.const 1.25)
) )
(get_local $20) (get_local $5)
) )
) )
(drop (drop
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $21 (tee_local $5
(f64.const 1.25) (f64.const 1.25)
) )
) )
@ -599,8 +573,8 @@
) )
(i32.const 0) (i32.const 0)
(f64.eq (f64.eq
(get_local $21) (get_local $5)
(get_local $21) (get_local $5)
) )
) )
) )
@ -660,17 +634,17 @@
) )
(set_global $builtins/b (set_global $builtins/b
(f64.ne (f64.ne
(tee_local $22 (tee_local $5
(f64.const 1.25) (f64.const 1.25)
) )
(get_local $22) (get_local $5)
) )
) )
(set_global $builtins/b (set_global $builtins/b
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $23 (tee_local $5
(f64.const 1.25) (f64.const 1.25)
) )
) )
@ -678,8 +652,8 @@
) )
(i32.const 0) (i32.const 0)
(f64.eq (f64.eq
(get_local $23) (get_local $5)
(get_local $23) (get_local $5)
) )
) )
) )
@ -910,10 +884,10 @@
(if (if
(i32.eqz (i32.eqz
(f32.ne (f32.ne
(tee_local $24 (tee_local $4
(f32.const nan:0x400000) (f32.const nan:0x400000)
) )
(get_local $24) (get_local $4)
) )
) )
(unreachable) (unreachable)
@ -921,10 +895,10 @@
(if (if
(i32.eqz (i32.eqz
(f64.ne (f64.ne
(tee_local $25 (tee_local $5
(f64.const nan:0x8000000000000) (f64.const nan:0x8000000000000)
) )
(get_local $25) (get_local $5)
) )
) )
(unreachable) (unreachable)
@ -935,7 +909,7 @@
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $26 (tee_local $4
(f32.const nan:0x400000) (f32.const nan:0x400000)
) )
) )
@ -943,8 +917,8 @@
) )
(i32.const 0) (i32.const 0)
(f32.eq (f32.eq
(get_local $26) (get_local $4)
(get_local $26) (get_local $4)
) )
) )
) )
@ -957,7 +931,7 @@
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $27 (tee_local $4
(f32.const inf) (f32.const inf)
) )
) )
@ -965,8 +939,8 @@
) )
(i32.const 0) (i32.const 0)
(f32.eq (f32.eq
(get_local $27) (get_local $4)
(get_local $27) (get_local $4)
) )
) )
) )
@ -979,7 +953,7 @@
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $28 (tee_local $5
(f64.const nan:0x8000000000000) (f64.const nan:0x8000000000000)
) )
) )
@ -987,8 +961,8 @@
) )
(i32.const 0) (i32.const 0)
(f64.eq (f64.eq
(get_local $28) (get_local $5)
(get_local $28) (get_local $5)
) )
) )
) )
@ -1001,7 +975,7 @@
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $29 (tee_local $5
(f64.const inf) (f64.const inf)
) )
) )
@ -1009,8 +983,8 @@
) )
(i32.const 0) (i32.const 0)
(f64.eq (f64.eq
(get_local $29) (get_local $5)
(get_local $29) (get_local $5)
) )
) )
) )
@ -1022,7 +996,7 @@
(select (select
(f32.ne (f32.ne
(f32.abs (f32.abs
(tee_local $30 (tee_local $4
(f32.const 0) (f32.const 0)
) )
) )
@ -1030,8 +1004,8 @@
) )
(i32.const 0) (i32.const 0)
(f32.eq (f32.eq
(get_local $30) (get_local $4)
(get_local $30) (get_local $4)
) )
) )
) )
@ -1042,7 +1016,7 @@
(select (select
(f64.ne (f64.ne
(f64.abs (f64.abs
(tee_local $31 (tee_local $5
(f64.const 0) (f64.const 0)
) )
) )
@ -1050,8 +1024,8 @@
) )
(i32.const 0) (i32.const 0)
(f64.eq (f64.eq
(get_local $31) (get_local $5)
(get_local $31) (get_local $5)
) )
) )
) )