mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-14 23:41:30 +00:00
Always try to eliminate branches if tree-shaking is enabled
This commit is contained in:
@ -1053,8 +1053,7 @@ export enum DecoratorKind {
|
||||
OPERATOR,
|
||||
UNMANAGED,
|
||||
SEALED,
|
||||
INLINE,
|
||||
PRECOMPUTE
|
||||
INLINE
|
||||
}
|
||||
|
||||
/** Returns the decorator kind represented by the specified string. */
|
||||
@ -1065,7 +1064,6 @@ export function stringToDecoratorKind(str: string): DecoratorKind {
|
||||
case "unmanaged": return DecoratorKind.UNMANAGED;
|
||||
case "sealed": return DecoratorKind.SEALED;
|
||||
case "inline": return DecoratorKind.INLINE;
|
||||
case "precompute": return DecoratorKind.PRECOMPUTE;
|
||||
default: return DecoratorKind.CUSTOM;
|
||||
}
|
||||
}
|
||||
|
@ -1634,21 +1634,30 @@ export class Compiler extends DiagnosticEmitter {
|
||||
module
|
||||
);
|
||||
|
||||
// Eliminate unnecesssary branches in generic contexts if the condition is constant
|
||||
if (
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT) &&
|
||||
_BinaryenExpressionGetId(condExpr = this.precomputeExpressionRef(condExpr)) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExpr) == NativeType.I32
|
||||
!this.options.noTreeShaking ||
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT)
|
||||
) {
|
||||
let ret: ExpressionRef;
|
||||
if (_BinaryenConstGetValueI32(condExpr)) {
|
||||
ret = this.compileStatement(ifTrue);
|
||||
} else if (ifFalse) {
|
||||
ret = this.compileStatement(ifFalse);
|
||||
} else {
|
||||
ret = module.createNop();
|
||||
// Try to eliminate unnecesssary branches if the condition is constant
|
||||
let condExprPrecomp = this.precomputeExpressionRef(condExpr);
|
||||
if (
|
||||
_BinaryenExpressionGetId(condExprPrecomp) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExprPrecomp) == NativeType.I32
|
||||
) {
|
||||
return _BinaryenConstGetValueI32(condExprPrecomp)
|
||||
? this.compileStatement(ifTrue)
|
||||
: ifFalse
|
||||
? this.compileStatement(ifFalse)
|
||||
: module.createNop();
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Each arm initiates a branch
|
||||
@ -1992,14 +2001,25 @@ export class Compiler extends DiagnosticEmitter {
|
||||
module
|
||||
);
|
||||
|
||||
// Eliminate unnecesssary loops in generic contexts if the condition is constant
|
||||
if (
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT) &&
|
||||
_BinaryenExpressionGetId(condExpr = this.precomputeExpressionRef(condExpr)) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExpr) == NativeType.I32
|
||||
!this.options.noTreeShaking ||
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT)
|
||||
) {
|
||||
if (!_BinaryenConstGetValueI32(condExpr)) {
|
||||
return module.createNop();
|
||||
// Try to eliminate unnecesssary loops if the condition is constant
|
||||
let condExprPrecomp = this.precomputeExpressionRef(condExpr);
|
||||
if (
|
||||
_BinaryenExpressionGetId(condExprPrecomp) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExprPrecomp) == NativeType.I32
|
||||
) {
|
||||
if (!_BinaryenConstGetValueI32(condExprPrecomp)) return module.createNop();
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
this.compileExpression(statement.condition, Type.i32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
module
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6050,6 +6070,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
compileTernaryExpression(expression: TernaryExpression, contextualType: Type): ExpressionRef {
|
||||
var ifThen = expression.ifThen;
|
||||
var ifElse = expression.ifElse;
|
||||
var currentFunction = this.currentFunction;
|
||||
|
||||
var condExpr = makeIsTrueish(
|
||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||
@ -6057,18 +6078,30 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.module
|
||||
);
|
||||
|
||||
// Eliminate unnecesssary branches in generic contexts if the condition is constant
|
||||
if (
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT) &&
|
||||
_BinaryenExpressionGetId(condExpr = this.precomputeExpressionRef(condExpr)) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExpr) == NativeType.I32
|
||||
!this.options.noTreeShaking ||
|
||||
this.currentFunction.isAny(CommonFlags.GENERIC | CommonFlags.GENERIC_CONTEXT)
|
||||
) {
|
||||
return _BinaryenConstGetValueI32(condExpr)
|
||||
? this.compileExpression(ifThen, contextualType)
|
||||
: this.compileExpression(ifElse, contextualType);
|
||||
// Try to eliminate unnecesssary branches if the condition is constant
|
||||
let condExprPrecomp = this.precomputeExpressionRef(condExpr);
|
||||
if (
|
||||
_BinaryenExpressionGetId(condExprPrecomp) == ExpressionId.Const &&
|
||||
_BinaryenExpressionGetType(condExprPrecomp) == NativeType.I32
|
||||
) {
|
||||
return _BinaryenConstGetValueI32(condExprPrecomp)
|
||||
? this.compileExpression(ifThen, contextualType)
|
||||
: this.compileExpression(ifElse, contextualType);
|
||||
|
||||
// Otherwise recompile to the original and let the optimizer decide
|
||||
} else /* if (condExpr != condExprPrecomp) <- not guaranteed */ {
|
||||
condExpr = makeIsTrueish(
|
||||
this.compileExpression(expression.condition, Type.u32, ConversionKind.NONE),
|
||||
this.currentType,
|
||||
this.module
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var currentFunction = this.currentFunction;
|
||||
var ifThenExpr: ExpressionRef;
|
||||
var ifElseExpr: ExpressionRef;
|
||||
var ifThenType: Type;
|
||||
@ -6891,3 +6924,8 @@ export function makeConditionalAllocate(compiler: Compiler, classInstance: Class
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function isI32Const(expr: ExpressionRef): bool {
|
||||
return _BinaryenExpressionGetId(expr) == ExpressionId.Const
|
||||
&& _BinaryenExpressionGetType(expr) == NativeType.I32;
|
||||
}
|
||||
|
@ -629,6 +629,7 @@ export class Program extends DiagnosticEmitter {
|
||||
): void {
|
||||
var name = declaration.name.text;
|
||||
var internalName = declaration.fileLevelInternalName;
|
||||
var decorators = declaration.decorators;
|
||||
|
||||
// static fields become global variables
|
||||
if (declaration.is(CommonFlags.STATIC)) {
|
||||
@ -655,7 +656,10 @@ export class Program extends DiagnosticEmitter {
|
||||
name,
|
||||
internalName,
|
||||
Type.void, // resolved later on
|
||||
declaration
|
||||
declaration,
|
||||
decorators
|
||||
? this.filterDecorators(decorators, DecoratorFlags.NONE)
|
||||
: DecoratorFlags.NONE
|
||||
);
|
||||
staticField.parent = classPrototype;
|
||||
classPrototype.members.set(name, staticField);
|
||||
@ -683,6 +687,7 @@ export class Program extends DiagnosticEmitter {
|
||||
internalName,
|
||||
declaration
|
||||
);
|
||||
if (decorators) this.filterDecorators(decorators, DecoratorFlags.NONE);
|
||||
classPrototype.instanceMembers.set(name, instanceField);
|
||||
// TBD: no need to mark as MODULE_EXPORT
|
||||
}
|
||||
@ -700,6 +705,7 @@ export class Program extends DiagnosticEmitter {
|
||||
var decoratorFlags = DecoratorFlags.NONE;
|
||||
if (decorators) {
|
||||
decoratorFlags = this.filterDecorators(decorators,
|
||||
DecoratorFlags.OPERATOR |
|
||||
DecoratorFlags.INLINE
|
||||
);
|
||||
}
|
||||
@ -1548,6 +1554,7 @@ export class Program extends DiagnosticEmitter {
|
||||
var declarations = statement.declarations;
|
||||
for (let i = 0, k = declarations.length; i < k; ++i) {
|
||||
let declaration = declarations[i];
|
||||
let decorators = declaration.decorators;
|
||||
let internalName = declaration.fileLevelInternalName;
|
||||
if (this.elementsLookup.has(internalName)) {
|
||||
this.error(
|
||||
@ -1562,7 +1569,12 @@ export class Program extends DiagnosticEmitter {
|
||||
simpleName,
|
||||
internalName,
|
||||
Type.void, // resolved later on
|
||||
declaration
|
||||
declaration,
|
||||
decorators
|
||||
? this.filterDecorators(decorators,
|
||||
DecoratorFlags.GLOBAL
|
||||
)
|
||||
: DecoratorFlags.NONE
|
||||
);
|
||||
global.parent = namespace;
|
||||
this.elementsLookup.set(internalName, global);
|
||||
@ -2274,6 +2286,8 @@ export enum DecoratorFlags {
|
||||
NONE = 0,
|
||||
/** Is a program global. */
|
||||
GLOBAL = 1 << 0,
|
||||
/** Is an operator overload. */
|
||||
OPERATOR = 1 << 1,
|
||||
/** Is an unmanaged class. */
|
||||
UNMANAGED = 1 << 2,
|
||||
/** Is a sealed class. */
|
||||
@ -2285,6 +2299,7 @@ export enum DecoratorFlags {
|
||||
export function decoratorKindToFlag(kind: DecoratorKind): DecoratorFlags {
|
||||
switch (kind) {
|
||||
case DecoratorKind.GLOBAL: return DecoratorFlags.GLOBAL;
|
||||
case DecoratorKind.OPERATOR: return DecoratorFlags.OPERATOR;
|
||||
case DecoratorKind.UNMANAGED: return DecoratorFlags.UNMANAGED;
|
||||
case DecoratorKind.SEALED: return DecoratorFlags.SEALED;
|
||||
case DecoratorKind.INLINE: return DecoratorFlags.INLINE;
|
||||
@ -2453,10 +2468,12 @@ export class Global extends VariableLikeElement {
|
||||
simpleName: string,
|
||||
internalName: string,
|
||||
type: Type,
|
||||
declaration: VariableLikeDeclarationStatement | null
|
||||
declaration: VariableLikeDeclarationStatement | null,
|
||||
decoratorFlags: DecoratorFlags
|
||||
) {
|
||||
super(program, simpleName, internalName, type, declaration);
|
||||
this.flags = declaration ? declaration.flags : CommonFlags.NONE;
|
||||
this.decoratorFlags = decoratorFlags;
|
||||
this.type = type; // resolved later if `void`
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user