mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 07:02:13 +00:00
Make sure constant locals are inlined, see #6
This commit is contained in:
parent
2ed3c22031
commit
8d894d0827
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
124
src/compiler.ts
124
src/compiler.ts
@ -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);
|
||||
if (global.hasConstantValue)
|
||||
return makeInlineConstant(global, this.module);
|
||||
else
|
||||
throw new Error("concrete type expected");
|
||||
} 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,11 +2088,8 @@ 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 makeInlineConstant(<Global>element, this.module);
|
||||
else
|
||||
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
|
||||
|
||||
case ElementKind.PROPERTY: // getter
|
||||
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
20
tests/compiler/inlining.optimized.wast
Normal file
20
tests/compiler/inlining.optimized.wast
Normal 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)
|
||||
)
|
||||
)
|
||||
)
|
8
tests/compiler/inlining.ts
Normal file
8
tests/compiler/inlining.ts
Normal file
@ -0,0 +1,8 @@
|
||||
const constantGlobal = 1;
|
||||
|
||||
export function test(): i32 {
|
||||
const constantLocal = 2;
|
||||
return constantGlobal + constantLocal;
|
||||
}
|
||||
|
||||
assert(test() == 3);
|
81
tests/compiler/inlining.wast
Normal file
81
tests/compiler/inlining.wast
Normal 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
|
||||
;)
|
Loading…
x
Reference in New Issue
Block a user