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 Object {}
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 {
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;
indexOf(subject: string): 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["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);
if (typeArguments[0].isAnyInteger) {
if (typeArguments[0].isSignedInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
if (typeArguments[0].isLongInteger)
return module.createSelect(
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.MaxF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal0 = compiler.currentFunction.getTempLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
compiler.currentFunction.freeTempLocal(tempLocal0);
if (typeArguments[0].isLongInteger)
return module.createSelect(
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.MinF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal0 = compiler.currentFunction.getTempLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.getAndFreeTempLocal(typeArguments[0]);
compiler.currentFunction.freeTempLocal(tempLocal0);
if (typeArguments[0].isLongInteger)
return module.createSelect(
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
compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32);
tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f32);
return module.createBinary(BinaryOp.NeF32,
module.createTeeLocal(tempLocal0.index, arg0),
module.createGetLocal(tempLocal0.index, NativeType.F32)
);
} else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64);
tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f64);
return module.createBinary(BinaryOp.NeF64,
module.createTeeLocal(tempLocal0.index, arg0),
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
compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32);
tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f32);
return module.createSelect(
module.createBinary(BinaryOp.NeF32,
module.createUnary(UnaryOp.AbsF32,
@ -468,7 +470,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
)
);
} else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64);
tempLocal0 = compiler.currentFunction.getAndFreeTempLocal(Type.f64);
return module.createSelect(
module.createBinary(BinaryOp.NeF64,
module.createUnary(UnaryOp.AbsF64,

View File

@ -11,28 +11,7 @@ import {
NativeType,
FunctionTypeRef,
FunctionRef,
ExpressionId,
getExpressionId,
getExpressionType,
getFunctionBody,
getConstValueI32,
getConstValueI64Low,
getConstValueI64High,
getConstValueF32,
getConstValueF64,
getGetLocalIndex,
getGetGlobalName,
isLoadAtomic,
isLoadSigned,
getLoadBytes,
getLoadOffset,
getLoadPtr,
getUnaryOp,
getUnaryValue,
getBinaryOp,
getBinaryLeft,
getBinaryRight
ExpressionId
} from "./module";
import {
@ -373,10 +352,10 @@ export class Compiler extends DiagnosticEmitter {
} else if (declaration) {
if (declaration.initializer) {
initializer = this.compileExpression(declaration.initializer, type);
if (getExpressionId(initializer) != ExpressionId.Const) {
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
if (!element.isMutable) {
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);
initializeInStart = true;
}
@ -395,19 +374,19 @@ export class Compiler extends DiagnosticEmitter {
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
if (!element.isMutable) {
element.hasConstantValue = true;
const exprType: NativeType = getExpressionType(initializer);
const exprType: NativeType = _BinaryenExpressionGetType(initializer);
switch (exprType) {
case NativeType.I32:
element.constantIntegerValue = new I64(getConstValueI32(initializer), 0);
element.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initializer), 0);
break;
case NativeType.I64:
element.constantIntegerValue = new I64(getConstValueI64Low(initializer), getConstValueI64High(initializer));
element.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initializer), _BinaryenConstGetValueI64High(initializer));
break;
case NativeType.F32:
element.constantFloatValue = getConstValueF32(initializer);
element.constantFloatValue = _BinaryenConstGetValueF32(initializer);
break;
case NativeType.F64:
element.constantFloatValue = getConstValueF64(initializer);
element.constantFloatValue = _BinaryenConstGetValueF64(initializer);
break;
default:
throw new Error("unexpected initializer type");
@ -439,9 +418,9 @@ export class Compiler extends DiagnosticEmitter {
let initializeInStart: bool = false;
if (declaration.value) {
initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
if (getExpressionId(initializer) != ExpressionId.Const) {
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
initializer = this.precomputeExpressionRef(initializer);
if (getExpressionId(initializer) != ExpressionId.Const) {
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
if (element.isConstant)
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
initializeInStart = true;
@ -466,9 +445,9 @@ export class Compiler extends DiagnosticEmitter {
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
} else {
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
if (getExpressionType(initializer) == NativeType.I32) {
if (_BinaryenExpressionGetType(initializer) == NativeType.I32) {
val.hasConstantValue = true;
val.constantValue = getConstValueI32(initializer);
val.constantValue = _BinaryenConstGetValueI32(initializer);
} else
throw new Error("unexpected initializer type");
}
@ -1068,7 +1047,7 @@ export class Compiler extends DiagnosticEmitter {
typeRef = this.module.addFunctionType(typeToSignatureNamePart(this.currentType), nativeType, []);
const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr);
this.module.runPasses([ "precompute" ], funcRef);
const ret: ExpressionRef = getFunctionBody(funcRef);
const ret: ExpressionRef = _BinaryenFunctionGetBody(funcRef);
this.module.removeFunction("__precompute");
// TODO: also remove the function type somehow if no longer used or make the C-API accept
// a `null` typeRef, using an implicit type.
@ -1240,41 +1219,6 @@ export class Compiler extends DiagnosticEmitter {
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 {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (!toType)
@ -1537,7 +1481,7 @@ export class Compiler extends DiagnosticEmitter {
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))
// if (condition = this.cloneExpressionRef(left, true, 2))
// if (condition = this.module.cloneExpression(left, true, 2))
// return this.module.createIf(
// this.currentType.isLongInteger
// ? 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);
// 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(
// this.currentType.isLongInteger
// ? this.module.createBinary(BinaryOp.NeI64, condition, this.module.createI64(0, 0))

View File

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

View File

@ -751,7 +751,7 @@ export class Module {
}
interpret(): void {
return _BinaryenModuleInterpret(this.ref);
_BinaryenModuleInterpret(this.ref);
}
write(output: usize, outputSize: usize = 1048576): usize {
@ -759,11 +759,11 @@ export class Module {
}
print(): void {
return _BinaryenModulePrint(this.ref);
_BinaryenModulePrint(this.ref);
}
printAsmjs(): void {
return _BinaryenModulePrintAsmjs(this.ref);
_BinaryenModulePrintAsmjs(this.ref);
}
toBinary(bufferSize: usize = 1048576): Uint8Array {
@ -785,132 +785,48 @@ export class Module {
createRelooper(): Relooper {
return this.noEmit ? Relooper.createStub(this) : Relooper.create(this);
}
// currently supports side effect free expressions only
cloneExpression(expr: ExpressionRef, noSideEffects: bool = false, maxDepth: i32 = 0x7fffffff): ExpressionRef {
if (this.noEmit || maxDepth < 0) return 0;
let nested1: ExpressionRef,
nested2: ExpressionRef;
switch (_BinaryenExpressionGetId(expr)) {
case ExpressionId.Const:
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 getExpressionId(expr: ExpressionRef): ExpressionId {
return _BinaryenExpressionGetId(expr);
}
case ExpressionId.GetLocal:
return _BinaryenGetLocal(this.ref, _BinaryenGetLocalGetIndex(expr), _BinaryenExpressionGetType(expr));
export function getExpressionType(expr: ExpressionRef): NativeType {
return _BinaryenExpressionGetType(expr);
}
// case ExpressionId.GetGlobal: explodes if it doesn't have a name
// return _BinaryenGetGlobal(this.ref, _BinaryenGetGlobalGetName(expr), _BinaryenExpressionGetType(expr));
export function printExpression(expr: ExpressionRef): void {
return _BinaryenExpressionPrint(expr);
}
case ExpressionId.Load:
if (!(nested1 = this.cloneExpression(_BinaryenLoadGetPtr(expr), noSideEffects, maxDepth - 1))) break;
return _BinaryenLoadIsAtomic(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 getConstValueI32(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI32(expr);
}
case ExpressionId.Unary:
if (!(nested1 = this.cloneExpression(_BinaryenUnaryGetValue(expr), noSideEffects, maxDepth - 1))) break;
return _BinaryenUnary(this.ref, _BinaryenUnaryGetOp(expr), nested1);
export function getConstValueI64Low(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64Low(expr);
case ExpressionId.Binary:
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 getConstValueI64High(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64High(expr);
return 0;
}
export function getConstValueI64(expr: ExpressionRef): I64 {
return new I64(
_BinaryenConstGetValueI64Low(expr),
_BinaryenConstGetValueI64High(expr)
);
}
export function getConstValueF32(expr: ExpressionRef): f32 {
return _BinaryenConstGetValueF32(expr);
}
export function getConstValueF64(expr: ExpressionRef): f64 {
return _BinaryenConstGetValueF64(expr);
}
export function getGetLocalIndex(expr: ExpressionRef): Index {
return _BinaryenGetLocalGetIndex(expr);
}
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 {
@ -990,6 +906,7 @@ function allocI32Array(i32s: i32[] | null): usize {
let idx: usize = ptr;
for (let i: i32 = 0, k: i32 = (<i32[]>i32s).length; i < k; ++i) {
let val: i32 = (<i32[]>i32s)[i];
// store<i32>(idx, val) is not portable
store<u8>(idx , ( val & 0xff) as u8);
store<u8>(idx + 1, ((val >> 8) & 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 {
if (!str) return 0;
if (str == null) return 0;
const ptr: usize = Heap.allocate(stringLengthUTF8((<string>str)) + 1);
let idx: usize = ptr;
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 {
if (!ptr) return null;
const utf16le: u32[] = [];
const arr: i32[] = [];
// the following is based on Emscripten's UTF8ArrayToString
let cp: u32;
let u1: u32, u2: u32, u3: u32, u4: u32, u5: u32;
while (cp = load<u8>(ptr++)) {
if (!(cp & 0x80)) {
utf16le.push(cp);
arr.push(cp);
continue;
}
u1 = load<u8>(ptr++) & 63;
if ((cp & 0xE0) == 0xC0) {
utf16le.push(((cp & 31) << 6) | u1);
arr.push(((cp & 31) << 6) | u1);
continue;
}
u2 = load<u8>(ptr++) & 63;
@ -1095,14 +1012,14 @@ export function readString(ptr: usize): string | null {
}
}
}
if (cp < 0x10000) {
utf16le.push(cp);
} else {
var ch = cp - 0x10000;
utf16le.push(0xD800 | (ch >> 10));
utf16le.push(0xDC00 | (ch & 0x3FF));
// if (cp < 0x10000) {
// arr.push(cp);
// } else {
// var ch = cp - 0x10000;
// arr.push(0xD800 | (ch >> 10));
// arr.push(0xDC00 | (ch & 0x3FF));
// }
}
}
// FIXME: not portable and prone to stack overflows. Maybe use CString from stdlib?
return String.fromCharCode.apply(utf16le);
// return String.fromCharCodes(arr);
return String.fromCodePoints(arr);
}

View File

@ -1,5 +1,5 @@
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 { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
import { Type, typesToString } from "./types";
@ -45,6 +45,7 @@ import {
mangleInternalName
} from "./ast";
import { NativeType } from "./module";
class QueuedExport {
isReExport: bool;
@ -973,6 +974,53 @@ export class Function extends Element {
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. */
enterBreakContext(): string {
const id: i32 = this.nextBreakId++;

View File

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