Make sure constant locals are inlined, see #6

This commit is contained in:
dcodeIO 2017-12-28 15:17:35 +01:00
parent 2ed3c22031
commit 8d894d0827
7 changed files with 251 additions and 101 deletions

View File

@ -1,8 +1,8 @@
// A simplified version of the game of life as seen on http://dcode.io
let w: u32; // width
let h: u32; // height
let s: u32; // total size
var w: u32; // width
var h: u32; // height
var s: u32; // total size
/** Initializes width and height. */
export function init(w_: u32, h_: u32): void {
@ -13,10 +13,10 @@ export function init(w_: u32, h_: u32): void {
/** Performs one step. */
export function step(): void {
let y: u32, ym1: u32, yp1: u32; // y, y-1 and y+1
let x: u32, xm1: u32, xp1: u32; // x, x-1 and x+1
let hm1: u32 = h - 1, wm1: u32 = w - 1;
let n: u32, v: u8, c: u32 = 0;
var y: u32, ym1: u32, yp1: u32; // y, y-1 and y+1
var x: u32, xm1: u32, xp1: u32; // x, x-1 and x+1
var hm1: u32 = h - 1, wm1: u32 = w - 1;
var n: u32, v: u8, c: u32 = 0;
for (y = 0; y < h; ++y) {
ym1 = select<u32>(hm1, y - 1, y == 0);
yp1 = select<u32>(0, y + 1, y == hm1);

View File

@ -10,180 +10,180 @@ export function getHi(): u32 {
}
function clz_(loLeft: u32, hiLeft: u32): void {
const ret: u64 = clz<u64>(<u64>loLeft | <u64>hiLeft << 32);
var ret = clz<u64>(<u64>loLeft | <u64>hiLeft << 32);
lo = <u32>ret;
hi = 0;
}
export { clz_ as clz };
function ctz_(loLeft: u32, hiLeft: u32): void {
const ret: u64 = ctz<u64>(<u64>loLeft | <u64>hiLeft << 32);
var ret = ctz<u64>(<u64>loLeft | <u64>hiLeft << 32);
lo = <u32>ret;
hi = 0;
}
export { ctz_ as ctz };
function popcnt_(loLeft: u32, hiLeft: u32): void {
const ret: u64 = popcnt<u64>(<u64>loLeft | <u64>hiLeft << 32);
var ret = popcnt<u64>(<u64>loLeft | <u64>hiLeft << 32);
lo = <u32>ret;
hi = 0;
}
export { popcnt_ as popcnt };
export function eqz(loLeft: u32, hiLeft: u32): void {
const ret: bool = !(<u64>loLeft | <u64>hiLeft << 32);
var ret: bool = !(<u64>loLeft | <u64>hiLeft << 32);
lo = <u32>ret;
hi = 0;
}
export function add(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) + (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) + (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function sub(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) - (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) - (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function mul(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) * (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) * (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function div_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) / <i64>(<u64>loRight | <u64>hiRight << 32));
var ret = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) / <i64>(<u64>loRight | <u64>hiRight << 32));
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function div_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) / (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) / (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function rem_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) % <i64>(<u64>loRight | <u64>hiRight << 32));
var ret = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) % <i64>(<u64>loRight | <u64>hiRight << 32));
lo = <u32>ret;
hi = <u32>(ret >> 32);
}
export function rem_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) % (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) % (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function and(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) & (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) & (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function or(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) | (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) | (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function xor(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) ^ (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) ^ (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function shl(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) << (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) << (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function shr_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) >> <i64>(<u64>loRight | <u64>hiRight << 32));
var ret = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) >> <i64>(<u64>loRight | <u64>hiRight << 32));
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export function shr_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) >> (<u64>loRight | <u64>hiRight << 32);
var ret = (<u64>loLeft | <u64>hiLeft << 32) >> (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
function rotl_(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = rotl<u64>(<u64>loLeft | <u64>hiLeft << 32, <u64>loRight | <u64>hiRight << 32);
var ret = rotl<u64>(<u64>loLeft | <u64>hiLeft << 32, <u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export { rotl_ as rotl };
function rotr_(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: u64 = rotr<u64>(<u64>loLeft | <u64>hiLeft << 32, <u64>loRight | <u64>hiRight << 32);
var ret = rotr<u64>(<u64>loLeft | <u64>hiLeft << 32, <u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = <u32>(ret >>> 32);
}
export { rotr_ as rotr };
export function eq(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) == (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) == (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function ne(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) != (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) != (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function lt_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) < <i64>(<u64>loRight | <u64>hiRight << 32);
var ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) < <i64>(<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function lt_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) < (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) < (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function le_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) <= <i64>(<u64>loRight | <u64>hiRight << 32);
var ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) <= <i64>(<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function le_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) <= (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) <= (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function gt_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) > <i64>(<u64>loRight | <u64>hiRight << 32);
var ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) > <i64>(<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function gt_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) > (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) > (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function ge_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) >= <i64>(<u64>loRight | <u64>hiRight << 32);
var ret: bool = <i64>(<u64>loLeft | <u64>hiLeft << 32) >= <i64>(<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}
export function ge_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
const ret: bool = (<u64>loLeft | <u64>hiLeft << 32) >= (<u64>loRight | <u64>hiRight << 32);
var ret: bool = (<u64>loLeft | <u64>hiLeft << 32) >= (<u64>loRight | <u64>hiRight << 32);
lo = <u32>ret;
hi = 0;
}

View File

@ -38,7 +38,8 @@ import {
Namespace,
Parameter,
EnumValue,
Property
Property,
VariableLikeElement
} from "./program";
import {
@ -376,20 +377,7 @@ export class Compiler extends DiagnosticEmitter {
var initializeInStart = false;
if (global.hasConstantValue) {
if (global.type.isLongInteger)
initExpr = global.constantIntegerValue ? this.module.createI64(global.constantIntegerValue.lo, global.constantIntegerValue.hi) : this.module.createI64(0, 0);
else if (global.type.kind == TypeKind.F32)
initExpr = this.module.createF32(global.constantFloatValue);
else if (global.type.kind == TypeKind.F64)
initExpr = this.module.createF64(global.constantFloatValue);
else if (global.type.isSmallInteger) {
if (global.type.isSignedInteger) {
var shift = global.type.smallIntegerShift;
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0);
} else
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & global.type.smallIntegerMask: 0);
} else
initExpr = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() : 0);
initExpr = makeInlineConstant(global, this.module);
} else if (declaration) {
if (declaration.initializer) {
if (!initExpr)
@ -1018,6 +1006,34 @@ export class Compiler extends DiagnosticEmitter {
if (this.currentFunction.locals.has(name))
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); // recoverable
else {
if (hasModifier(ModifierKind.CONST, declaration.modifiers)) {
if (init) {
init = this.precomputeExpressionRef(init);
if (_BinaryenExpressionGetId(init) == ExpressionId.Const) {
var local = new Local(this.program, name, -1, type);
switch (_BinaryenExpressionGetType(init)) {
case NativeType.I32:
local = local.withConstantIntegerValue(_BinaryenConstGetValueI32(init), 0);
break;
case NativeType.I64:
local = local.withConstantIntegerValue(_BinaryenConstGetValueI64Low(init), _BinaryenConstGetValueI64High(init));
break;
case NativeType.F32:
local = local.withConstantFloatValue(<f64>_BinaryenConstGetValueF32(init));
break;
case NativeType.F64:
local = local.withConstantFloatValue(_BinaryenConstGetValueF64(init));
break;
default:
throw new Error("concrete type expected");
}
this.currentFunction.locals.set(name, local);
continue;
}
} else {
this.error(DiagnosticCode._const_declarations_must_be_initialized, declaration.range);
}
}
this.currentFunction.addLocal(type, name);
if (init)
initializers.push(this.compileAssignmentWithValue(declaration.name, init));
@ -1582,7 +1598,7 @@ export class Compiler extends DiagnosticEmitter {
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
: this.module.createTeeLocal(tempLocal.index, left),
right,
this.module.createGetLocal(tempLocal.index, tempLocal.type.toNativeType())
this.module.createGetLocal(tempLocal.index, this.currentType.toNativeType())
);
case Token.BAR_BAR: // left || right
@ -1614,7 +1630,7 @@ export class Compiler extends DiagnosticEmitter {
: this.currentType == Type.f32
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
: this.module.createTeeLocal(tempLocal.index, left),
this.module.createGetLocal(tempLocal.index, tempLocal.type.toNativeType()),
this.module.createGetLocal(tempLocal.index, this.currentType.toNativeType()),
right
);
@ -1712,8 +1728,9 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
if (element.kind == ElementKind.LOCAL) {
assert((<Local>element).type != null);
if (tee) {
this.currentType = (<Local>element).type;
this.currentType = <Type>(<Local>element).type;
return this.module.createTeeLocal((<Local>element).index, valueWithCorrectType);
}
this.currentType = Type.void;
@ -1896,7 +1913,11 @@ export class Compiler extends DiagnosticEmitter {
// local
if (element.kind == ElementKind.LOCAL) {
this.currentType = (<Local>element).type;
assert((<Local>element).type != null);
this.currentType = <Type>(<Local>element).type;
if ((<Local>element).hasConstantValue)
return makeInlineConstant(<Local>element, this.module);
assert((<Local>element).index >= 0);
return this.module.createGetLocal((<Local>element).index, this.currentType.toNativeType());
}
@ -1910,18 +1931,9 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
assert(global.type != null);
this.currentType = <Type>global.type;
if (global.hasConstantValue) {
if (global.type == Type.f32)
return this.module.createF32((<Global>element).constantFloatValue);
else if (global.type == Type.f64)
return this.module.createF64((<Global>element).constantFloatValue);
else if ((<Type>global.type).isLongInteger)
return this.module.createI64((<I64>global.constantIntegerValue).lo, (<I64>global.constantIntegerValue).hi);
else if ((<Type>global.type).isAnyInteger)
return this.module.createI32((<I64>global.constantIntegerValue).lo);
else
throw new Error("concrete type expected");
} else
if (global.hasConstantValue)
return makeInlineConstant(global, this.module);
else
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
}
@ -2020,9 +2032,10 @@ export class Compiler extends DiagnosticEmitter {
switch (target.kind) {
case ElementKind.LOCAL:
element = (<Local>target).type.classType;
assert((<Local>target).type != null);
element = (<Type>(<Local>target).type).classType;
if (!element) {
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, (<Local>target).type.toString());
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, (<Type>(<Local>target).type).toString());
return this.module.createUnreachable();
}
target = element;
@ -2033,7 +2046,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
element = (<Type>(<Global>target).type).classType;
if (!element) {
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, (<Local>target).type.toString());
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, (<Type>(<Local>target).type).toString());
return this.module.createUnreachable();
}
target = element;
@ -2066,7 +2079,8 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) {
case ElementKind.LOCAL:
return this.module.createGetLocal((<Local>element).index, (this.currentType = (<Local>element).type).toNativeType());
assert((<Local>element).type != null);
return this.module.createGetLocal((<Local>element).index, (this.currentType = <Type>(<Local>element).type).toNativeType());
case ElementKind.GLOBAL:
if (!this.compileGlobal(<Global>element))
@ -2074,12 +2088,9 @@ export class Compiler extends DiagnosticEmitter {
assert((<Global>element).type != null);
this.currentType = <Type>(<Global>element).type;
if ((<Global>element).hasConstantValue)
return this.currentType== Type.f32 ? this.module.createF32((<Global>element).constantFloatValue)
: this.currentType == Type.f64 ? this.module.createF64((<Global>element).constantFloatValue)
: this.currentType.isLongInteger
? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi)
: this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo);
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
return makeInlineConstant(<Global>element, this.module);
else
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
case ElementKind.PROPERTY: // getter
var getterPrototype = (<Property>element).getterPrototype;
@ -2114,22 +2125,23 @@ export class Compiler extends DiagnosticEmitter {
// use a temp local for the intermediate value
var tempLocal = this.currentFunction.getTempLocal(this.currentType);
assert(tempLocal.type != null);
var op: BinaryOp;
var nativeType: NativeType;
var nativeOne: ExpressionRef;
if (tempLocal.type == Type.f32) {
if (<Type>tempLocal.type == Type.f32) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32;
nativeType = NativeType.F32;
nativeOne = this.module.createF32(1);
} else if (tempLocal.type == Type.f64) {
} else if (<Type>tempLocal.type == Type.f64) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64;
nativeType = NativeType.F64;
nativeOne = this.module.createF64(1);
} else if (tempLocal.type.isLongInteger) {
} else if ((<Type>tempLocal.type).isLongInteger) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64;
nativeType = NativeType.I64;
nativeOne = this.module.createI64(1, 0);
@ -2150,7 +2162,7 @@ export class Compiler extends DiagnosticEmitter {
// NOTE: can't preemptively tee_local the return value on the stack because binaryen expects
// this to be well-formed. becomes a tee_local when optimizing, though.
this.currentType = tempLocal.type;
this.currentType = <Type>tempLocal.type;
this.currentFunction.freeTempLocal(tempLocal);
return this.module.createBlock(null, [
this.module.createSetLocal(tempLocal.index, getValue), // +++ this.module.createTeeLocal(tempLocal.index, getValue),
@ -2233,6 +2245,7 @@ export class Compiler extends DiagnosticEmitter {
// helpers
/** Tests whether an element is a module-level export from the entry file. */
function isModuleExport(element: Element, declaration: DeclarationStatement): bool {
if (!element.isExported)
return false;
@ -2251,3 +2264,28 @@ function isModuleExport(element: Element, declaration: DeclarationStatement): bo
return false;
return isModuleExport(parent, <DeclarationStatement>parentNode);
}
/** Creates an inlined expression of a constant variable-like element. */
function makeInlineConstant(element: VariableLikeElement, module: Module): ExpressionRef {
assert(element.hasConstantValue);
assert(element.type != null);
if (<Type>element.type == Type.f32)
return module.createF32((<Global>element).constantFloatValue);
else if (<Type>element.type == Type.f64)
return module.createF64((<Global>element).constantFloatValue);
else if ((<Type>element.type).isLongInteger)
return element.constantIntegerValue
? module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi)
: module.createI64(0, 0);
else if ((<Type>element.type).isSmallInteger) {
if ((<Type>element.type).isSignedInteger) {
var shift = (<Type>element.type).smallIntegerShift;
return module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() << shift >> shift : 0);
} else
return module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() & (<Type>element.type).smallIntegerMask: 0);
} else if ((<Type>element.type).isAnyInteger)
return element.constantIntegerValue
? module.createI32(element.constantIntegerValue.lo)
: module.createI32(0);
throw new Error("concrete type expected");
}

View File

@ -1173,10 +1173,9 @@ export class EnumValue extends Element {
}
}
/** A global variable. */
export class Global extends Element {
export class VariableLikeElement extends Element {
kind = ElementKind.GLOBAL;
// kind varies
/** Declaration reference. */
declaration: VariableLikeDeclarationStatement | null;
@ -1187,6 +1186,26 @@ export class Global extends Element {
/** Constant float value, if applicable. */
constantFloatValue: f64 = 0;
withConstantIntegerValue(lo: i32, hi: i32): this {
this.constantIntegerValue = new I64(lo, hi);
this.hasConstantValue = true;
this.isMutable = false;
return this;
}
withConstantFloatValue(value: f64): this {
this.constantFloatValue = value;
this.hasConstantValue = true;
this.isMutable = false;
return this;
}
}
/** A global variable. */
export class Global extends VariableLikeElement {
kind = ElementKind.GLOBAL;
constructor(program: Program, simpleName: string, internalName: string, declaration: VariableLikeDeclarationStatement | null = null, type: Type | null = null) {
super(program, simpleName, internalName);
if (this.declaration = declaration) {
@ -1207,20 +1226,6 @@ export class Global extends Element {
}
this.type = type; // resolved later if `null`
}
withConstantIntegerValue(lo: i32, hi: i32): this {
this.constantIntegerValue = new I64(lo, hi);
this.hasConstantValue = true;
this.isMutable = false;
return this;
}
withConstantFloatValue(value: f64): this {
this.constantFloatValue = value;
this.hasConstantValue = true;
this.isMutable = false;
return this;
}
}
/** A function parameter. */
@ -1244,14 +1249,12 @@ export class Parameter {
}
/** A function local. */
export class Local extends Element {
export class Local extends VariableLikeElement {
kind = ElementKind.LOCAL;
/** Local index. */
index: i32;
/** Local type. */
type: Type;
constructor(program: Program, simpleName: string, index: i32, type: Type) {
super(program, simpleName, simpleName);

View File

@ -0,0 +1,20 @@
(module
(type $i (func (result i32)))
(type $v (func))
(memory $0 1)
(export "test" (func $inlining/test))
(export "memory" (memory $0))
(start $start)
(func $inlining/test (; 0 ;) (type $i) (result i32)
(i32.const 3)
)
(func $start (; 1 ;) (type $v)
(if
(i32.ne
(call $inlining/test)
(i32.const 3)
)
(unreachable)
)
)
)

View File

@ -0,0 +1,8 @@
const constantGlobal = 1;
export function test(): i32 {
const constantLocal = 2;
return constantGlobal + constantLocal;
}
assert(test() == 3);

View File

@ -0,0 +1,81 @@
(module
(type $i (func (result i32)))
(type $v (func))
(global $inlining/constantGlobal i32 (i32.const 1))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "test" (func $inlining/test))
(export "memory" (memory $0))
(start $start)
(func $inlining/test (; 0 ;) (type $i) (result i32)
(nop)
(return
(i32.add
(i32.const 1)
(i32.const 2)
)
)
)
(func $start (; 1 ;) (type $v)
(if
(i32.eqz
(i32.eq
(call $inlining/test)
(i32.const 3)
)
)
(unreachable)
)
)
)
(;
[program.elements]
GLOBAL: NaN
GLOBAL: Infinity
FUNCTION_PROTOTYPE: isNaN
FUNCTION_PROTOTYPE: isFinite
FUNCTION_PROTOTYPE: clz
FUNCTION_PROTOTYPE: ctz
FUNCTION_PROTOTYPE: popcnt
FUNCTION_PROTOTYPE: rotl
FUNCTION_PROTOTYPE: rotr
FUNCTION_PROTOTYPE: abs
FUNCTION_PROTOTYPE: max
FUNCTION_PROTOTYPE: min
FUNCTION_PROTOTYPE: ceil
FUNCTION_PROTOTYPE: floor
FUNCTION_PROTOTYPE: copysign
FUNCTION_PROTOTYPE: nearest
FUNCTION_PROTOTYPE: reinterpret
FUNCTION_PROTOTYPE: sqrt
FUNCTION_PROTOTYPE: trunc
FUNCTION_PROTOTYPE: load
FUNCTION_PROTOTYPE: store
FUNCTION_PROTOTYPE: sizeof
FUNCTION_PROTOTYPE: select
FUNCTION_PROTOTYPE: unreachable
FUNCTION_PROTOTYPE: current_memory
FUNCTION_PROTOTYPE: grow_memory
FUNCTION_PROTOTYPE: parseInt
FUNCTION_PROTOTYPE: parseFloat
FUNCTION_PROTOTYPE: changetype
FUNCTION_PROTOTYPE: assert
FUNCTION_PROTOTYPE: i8
FUNCTION_PROTOTYPE: i16
FUNCTION_PROTOTYPE: i32
FUNCTION_PROTOTYPE: i64
FUNCTION_PROTOTYPE: u8
FUNCTION_PROTOTYPE: u16
FUNCTION_PROTOTYPE: u32
FUNCTION_PROTOTYPE: u64
FUNCTION_PROTOTYPE: bool
FUNCTION_PROTOTYPE: f32
FUNCTION_PROTOTYPE: f64
FUNCTION_PROTOTYPE: isize
FUNCTION_PROTOTYPE: usize
GLOBAL: HEAP_BASE
GLOBAL: inlining/constantGlobal
FUNCTION_PROTOTYPE: inlining/test
[program.exports]
FUNCTION_PROTOTYPE: inlining/test
;)