diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 188f6fb6f0..ba171dbd43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -141,3 +141,20 @@ jobs: cd lib/loader npm run asbuild npm run test + test-bootstrap: + name: "Test self-compilation on node: node" + runs-on: ubuntu-latest + needs: check + steps: + - uses: actions/checkout@v1.0.0 + - uses: dcodeIO/setup-node-nvm@v1.0.0 + with: + node-version: node + - name: Install dependencies + run: npm ci --no-audit + - name: Clean distribution files + run: npm run clean + - name: Test self-compilation + run: | + npm run asbuild + npm run astest diff --git a/cli/asc.js b/cli/asc.js index c88ec45bd3..7832b2ba32 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -390,7 +390,8 @@ exports.main = function main(argv, options, callback) { if ((sourceText = readFile(sourcePath = internalPath + ".ts", baseDir)) == null) { if ((sourceText = readFile(sourcePath = internalPath + "/index.ts", baseDir)) == null) { // portable d.ts: uses the .js file next to it in JS or becomes an import in Wasm - sourceText = readFile(sourcePath = internalPath + ".d.ts", baseDir); + sourcePath = internalPath + ".ts"; + sourceText = readFile(internalPath + ".d.ts", baseDir); } } @@ -478,13 +479,16 @@ exports.main = function main(argv, options, callback) { var internalPath; while ((internalPath = assemblyscript.nextFile(program)) != null) { let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath)); - if (!file) return callback(Error("Import file '" + internalPath + ".ts' not found.")) + if (!file) return callback(Error("Import '" + internalPath + "' not found.")) stats.parseCount++; stats.parseTime += measure(() => { assemblyscript.parse(program, file.sourceText, file.sourcePath, false); }); } - if (checkDiagnostics(program, stderr)) return callback(Error("Parse error")); + var numErrors = checkDiagnostics(program, stderr); + if (numErrors) { + return callback(Error(numErrors + " parse error(s)")); + } } // Include runtime template before entry files so its setup runs first @@ -579,9 +583,10 @@ exports.main = function main(argv, options, callback) { } catch (e) { return callback(e); } - if (checkDiagnostics(program, stderr)) { + var numErrors = checkDiagnostics(program, stderr); + if (numErrors) { if (module) module.dispose(); - return callback(Error("Compile error")); + return callback(Error(numErrors + " compile error(s)")); } // Call afterCompile transform hook @@ -1023,7 +1028,7 @@ exports.main = function main(argv, options, callback) { /** Checks diagnostics emitted so far for errors. */ function checkDiagnostics(program, stderr) { var diagnostic; - var hasErrors = false; + var numErrors = 0; while ((diagnostic = assemblyscript.nextDiagnostic(program)) != null) { if (stderr) { stderr.write( @@ -1031,9 +1036,9 @@ function checkDiagnostics(program, stderr) { EOL + EOL ); } - if (assemblyscript.isError(diagnostic)) hasErrors = true; + if (assemblyscript.isError(diagnostic)) ++numErrors; } - return hasErrors; + return numErrors; } exports.checkDiagnostics = checkDiagnostics; diff --git a/package.json b/package.json index 591c8bf439..fea8b37574 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,11 @@ "all": "npm run check && npm run make", "docs": "typedoc --tsconfig tsconfig-docs.json --mode modules --name \"AssemblyScript Compiler API\" --out ./docs/api --ignoreCompilerErrors --excludeNotExported --excludePrivate --excludeExternals --exclude **/std/** --includeDeclarations --readme src/README.md", "prepublishOnly": "node scripts/prepublish", - "postpublish": "node scripts/postpublish" + "postpublish": "node scripts/postpublish", + "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized", + "asbuild:untouched": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.untouched.wat -b out/assemblyscript.untouched.wasm -d out/assemblyscript.d.ts --validate --debug --measure", + "asbuild:optimized": "node bin/asc src/glue/wasm/index.ts src/index.ts -t out/assemblyscript.optimized.wat -b out/assemblyscript.optimized.wasm -O3 --validate --measure", + "astest": "ts-node tests/bootstrap" }, "releaseFiles": [ "lib/rtrace/index.d.ts", diff --git a/src/ast.ts b/src/ast.ts index 009c756f58..440fc0efb2 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -21,8 +21,6 @@ import { CharCode } from "./util"; -export { Token, Range }; - /** Indicates the kind of a node. */ export enum NodeKind { @@ -70,6 +68,7 @@ export enum NodeKind { EXPORTIMPORT, EXPRESSION, FOR, + FOROF, IF, IMPORT, RETURN, @@ -114,7 +113,6 @@ export function nodeIsConstantValue(kind: NodeKind): bool { /** Base class of all nodes. */ export abstract class Node { - /** Node kind indicator. */ kind: NodeKind; /** Source range. */ @@ -126,11 +124,12 @@ export abstract class Node { name: IdentifierExpression, range: Range ): TypeName { - var typeName = new TypeName(); - typeName.range = range; - typeName.identifier = name; - typeName.next = null; - return typeName; + var node = new TypeName(); + node.kind = NodeKind.TYPENAME; + node.range = range; + node.identifier = name; + node.next = null; + return node; } static createSimpleTypeName( @@ -146,12 +145,13 @@ export abstract class Node { isNullable: bool, range: Range ): NamedTypeNode { - var type = new NamedTypeNode(); - type.range = range; - type.name = name; - type.typeArguments = typeArguments; - type.isNullable = isNullable; - return type; + var node = new NamedTypeNode(); + node.kind = NodeKind.NAMEDTYPE; + node.range = range; + node.name = name; + node.typeArguments = typeArguments; + node.isNullable = isNullable; + return node; } static createFunctionType( @@ -161,13 +161,14 @@ export abstract class Node { isNullable: bool, range: Range ): FunctionTypeNode { - var type = new FunctionTypeNode(); - type.range = range; - type.parameters = parameters; - type.returnType = returnType; - type.explicitThisType = explicitThisType; - type.isNullable = isNullable; - return type; + var node = new FunctionTypeNode(); + node.kind = NodeKind.FUNCTIONTYPE; + node.range = range; + node.parameters = parameters; + node.returnType = returnType; + node.explicitThisType = explicitThisType; + node.isNullable = isNullable; + return node; } static createOmittedType( @@ -187,12 +188,13 @@ export abstract class Node { defaultType: NamedTypeNode | null, range: Range ): TypeParameterNode { - var elem = new TypeParameterNode(); - elem.range = range; - elem.name = name; - elem.extendsType = extendsType; - elem.defaultType = defaultType; - return elem; + var node = new TypeParameterNode(); + node.kind = NodeKind.TYPEPARAMETER; + node.range = range; + node.name = name; + node.extendsType = extendsType; + node.defaultType = defaultType; + return node; } static createParameter( @@ -202,13 +204,14 @@ export abstract class Node { kind: ParameterKind, range: Range ): ParameterNode { - var elem = new ParameterNode(); - elem.range = range; - elem.name = name; - elem.type = type; - elem.initializer = initializer; - elem.parameterKind = kind; - return elem; + var node = new ParameterNode(); + node.kind = NodeKind.PARAMETER; + node.range = range; + node.name = name; + node.type = type; + node.initializer = initializer; + node.parameterKind = kind; + return node; } // special @@ -218,12 +221,13 @@ export abstract class Node { args: Expression[] | null, range: Range ): DecoratorNode { - var stmt = new DecoratorNode(); - stmt.range = range; - stmt.name = name; - stmt.arguments = args; - stmt.decoratorKind = DecoratorKind.fromNode(name); - return stmt; + var node = new DecoratorNode(); + node.kind = NodeKind.DECORATOR; + node.range = range; + node.name = name; + node.arguments = args; + node.decoratorKind = DecoratorKind.fromNode(name); + return node; } static createComment( @@ -232,6 +236,7 @@ export abstract class Node { range: Range ): CommentNode { var node = new CommentNode(); + node.kind = NodeKind.COMMENT; node.range = range; node.commentKind = kind; node.text = text; @@ -245,30 +250,34 @@ export abstract class Node { range: Range, isQuoted: bool = false ): IdentifierExpression { - var expr = new IdentifierExpression(); - expr.range = range; - expr.text = name; - expr.isQuoted = isQuoted; - return expr; + var node = new IdentifierExpression(); + node.kind = NodeKind.IDENTIFIER; + node.range = range; + node.text = name; + node.isQuoted = isQuoted; + return node; } static createEmptyIdentifierExpression( range: Range ): IdentifierExpression { - var expr = new IdentifierExpression(); - expr.range = range; - expr.text = ""; - return expr; + var node = new IdentifierExpression(); + node.kind = NodeKind.IDENTIFIER; + node.range = range; + node.text = ""; + return node; } static createArrayLiteralExpression( elements: (Expression | null)[], range: Range ): ArrayLiteralExpression { - var expr = new ArrayLiteralExpression(); - expr.range = range; - expr.elementExpressions = elements; - return expr; + var node = new ArrayLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.range = range; + node.literalKind = LiteralKind.ARRAY; + node.elementExpressions = elements; + return node; } static createAssertionExpression( @@ -277,12 +286,13 @@ export abstract class Node { toType: TypeNode | null, range: Range ): AssertionExpression { - var expr = new AssertionExpression(); - expr.range = range; - expr.assertionKind = assertionKind; - expr.expression = expression; - expr.toType = toType; - return expr; + var node = new AssertionExpression(); + node.kind = NodeKind.ASSERTION; + node.range = range; + node.assertionKind = assertionKind; + node.expression = expression; + node.toType = toType; + return node; } static createBinaryExpression( @@ -291,12 +301,13 @@ export abstract class Node { right: Expression, range: Range ): BinaryExpression { - var expr = new BinaryExpression(); - expr.range = range; - expr.operator = operator; - expr.left = left; - expr.right = right; - return expr; + var node = new BinaryExpression(); + node.kind = NodeKind.BINARY; + node.range = range; + node.operator = operator; + node.left = left; + node.right = right; + return node; } static createCallExpression( @@ -305,39 +316,44 @@ export abstract class Node { args: Expression[], range: Range ): CallExpression { - var expr = new CallExpression(); - expr.range = range; - expr.expression = expression; - expr.typeArguments = typeArgs; - expr.arguments = args; - return expr; + var node = new CallExpression(); + node.kind = NodeKind.CALL; + node.range = range; + node.expression = expression; + node.typeArguments = typeArgs; + node.arguments = args; + return node; } static createClassExpression( declaration: ClassDeclaration ): ClassExpression { - var expr = new ClassExpression(); - expr.range = declaration.range; - expr.declaration = declaration; - return expr; + var node = new ClassExpression(); + node.kind = NodeKind.CLASS; + node.range = declaration.range; + node.declaration = declaration; + return node; } static createCommaExpression( expressions: Expression[], range: Range ): CommaExpression { - var expr = new CommaExpression(); - expr.range = range; - expr.expressions = expressions; - return expr; + var node = new CommaExpression(); + node.kind = NodeKind.COMMA; + node.range = range; + node.expressions = expressions; + return node; } static createConstructorExpression( range: Range ): ConstructorExpression { - var expr = new ConstructorExpression(); - expr.range = range; - return expr; + var node = new ConstructorExpression(); + node.kind = NodeKind.CONSTRUCTOR; + node.range = range; + node.text = "constructor"; + return node; } static createElementAccessExpression( @@ -345,38 +361,44 @@ export abstract class Node { element: Expression, range: Range ): ElementAccessExpression { - var expr = new ElementAccessExpression(); - expr.range = range; - expr.expression = expression; - expr.elementExpression = element; - return expr; + var node = new ElementAccessExpression(); + node.kind = NodeKind.ELEMENTACCESS; + node.range = range; + node.expression = expression; + node.elementExpression = element; + return node; } static createFalseExpression( range: Range ): FalseExpression { - var expr = new FalseExpression(); - expr.range = range; - return expr; + var node = new FalseExpression(); + node.kind = NodeKind.FALSE; + node.range = range; + node.text = "false"; + return node; } static createFloatLiteralExpression( value: f64, range: Range ): FloatLiteralExpression { - var expr = new FloatLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new FloatLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.FLOAT; + node.range = range; + node.value = value; + return node; } static createFunctionExpression( declaration: FunctionDeclaration ): FunctionExpression { - var expr = new FunctionExpression(); - expr.range = declaration.range; - expr.declaration = declaration; - return expr; + var node = new FunctionExpression(); + node.kind = NodeKind.FUNCTION; + node.range = declaration.range; + node.declaration = declaration; + return node; } static createInstanceOfExpression( @@ -384,21 +406,24 @@ export abstract class Node { isType: TypeNode, range: Range ): InstanceOfExpression { - var expr = new InstanceOfExpression(); - expr.range = range; - expr.expression = expression; - expr.isType = isType; - return expr; + var node = new InstanceOfExpression(); + node.kind = NodeKind.INSTANCEOF; + node.range = range; + node.expression = expression; + node.isType = isType; + return node; } static createIntegerLiteralExpression( - value: I64, + value: i64, range: Range ): IntegerLiteralExpression { - var expr = new IntegerLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new IntegerLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.INTEGER; + node.range = range; + node.value = value; + return node; } static createNewExpression( @@ -407,20 +432,23 @@ export abstract class Node { args: Expression[], range: Range ): NewExpression { - var expr = new NewExpression(); - expr.range = range; - expr.typeName = typeName; - expr.typeArguments = typeArgs; - expr.arguments = args; - return expr; + var node = new NewExpression(); + node.kind = NodeKind.NEW; + node.range = range; + node.typeName = typeName; + node.typeArguments = typeArgs; + node.arguments = args; + return node; } static createNullExpression( range: Range ): NullExpression { - var expr = new NullExpression(); - expr.range = range; - return expr; + var node = new NullExpression(); + node.kind = NodeKind.NULL; + node.range = range; + node.text = "null"; + return node; } static createObjectLiteralExpression( @@ -428,21 +456,24 @@ export abstract class Node { values: Expression[], range: Range ): ObjectLiteralExpression { - var expr = new ObjectLiteralExpression(); - expr.range = range; - expr.names = names; - expr.values = values; - return expr; + var node = new ObjectLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.OBJECT; + node.range = range; + node.names = names; + node.values = values; + return node; } static createParenthesizedExpression( expression: Expression, range: Range ): ParenthesizedExpression { - var expr = new ParenthesizedExpression(); - expr.range = range; - expr.expression = expression; - return expr; + var node = new ParenthesizedExpression(); + node.kind = NodeKind.PARENTHESIZED; + node.range = range; + node.expression = expression; + return node; } static createPropertyAccessExpression( @@ -450,11 +481,12 @@ export abstract class Node { property: IdentifierExpression, range: Range ): PropertyAccessExpression { - var expr = new PropertyAccessExpression(); - expr.range = range; - expr.expression = expression; - expr.property = property; - return expr; + var node = new PropertyAccessExpression(); + node.kind = NodeKind.PROPERTYACCESS; + node.range = range; + node.expression = expression; + node.property = property; + return node; } static createRegexpLiteralExpression( @@ -462,11 +494,13 @@ export abstract class Node { flags: string, range: Range ): RegexpLiteralExpression { - var expr = new RegexpLiteralExpression(); - expr.range = range; - expr.pattern = pattern; - expr.patternFlags = flags; - return expr; + var node = new RegexpLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.REGEXP; + node.range = range; + node.pattern = pattern; + node.patternFlags = flags; + return node; } static createTernaryExpression( @@ -475,46 +509,55 @@ export abstract class Node { ifElse: Expression, range: Range ): TernaryExpression { - var expr = new TernaryExpression(); - expr.range = range; - expr.condition = condition; - expr.ifThen = ifThen; - expr.ifElse = ifElse; - return expr; + var node = new TernaryExpression(); + node.kind = NodeKind.TERNARY; + node.range = range; + node.condition = condition; + node.ifThen = ifThen; + node.ifElse = ifElse; + return node; } static createStringLiteralExpression( value: string, range: Range ): StringLiteralExpression { - var expr = new StringLiteralExpression(); - expr.range = range; - expr.value = value; - return expr; + var node = new StringLiteralExpression(); + node.kind = NodeKind.LITERAL; + node.literalKind = LiteralKind.STRING; + node.range = range; + node.value = value; + return node; } static createSuperExpression( range: Range ): SuperExpression { - var expr = new SuperExpression(); - expr.range = range; - return expr; + var node = new SuperExpression(); + node.kind = NodeKind.SUPER; + node.range = range; + node.text = "super"; + return node; } static createThisExpression( range: Range ): ThisExpression { - var expr = new ThisExpression(); - expr.range = range; - return expr; + var node = new ThisExpression(); + node.kind = NodeKind.THIS; + node.range = range; + node.text = "this"; + return node; } static createTrueExpression( range: Range ): TrueExpression { - var expr = new TrueExpression(); - expr.range = range; - return expr; + var node = new TrueExpression(); + node.kind = NodeKind.TRUE; + node.range = range; + node.text = "true"; + return node; } static createUnaryPostfixExpression( @@ -522,11 +565,12 @@ export abstract class Node { operand: Expression, range: Range ): UnaryPostfixExpression { - var expr = new UnaryPostfixExpression(); - expr.range = range; - expr.operator = operator; - expr.operand = operand; - return expr; + var node = new UnaryPostfixExpression(); + node.kind = NodeKind.UNARYPOSTFIX; + node.range = range; + node.operator = operator; + node.operand = operand; + return node; } static createUnaryPrefixExpression( @@ -534,11 +578,12 @@ export abstract class Node { operand: Expression, range: Range ): UnaryPrefixExpression { - var expr = new UnaryPrefixExpression(); - expr.range = range; - expr.operator = operator; - expr.operand = operand; - return expr; + var node = new UnaryPrefixExpression(); + node.kind = NodeKind.UNARYPREFIX; + node.range = range; + node.operator = operator; + node.operand = operand; + return node; } // statements @@ -547,20 +592,22 @@ export abstract class Node { statements: Statement[], range: Range ): BlockStatement { - var stmt = new BlockStatement(); - stmt.range = range; - stmt.statements = statements; - return stmt; + var node = new BlockStatement(); + node.kind = NodeKind.BLOCK; + node.range = range; + node.statements = statements; + return node; } static createBreakStatement( label: IdentifierExpression | null, range: Range ): BreakStatement { - var stmt = new BreakStatement(); - stmt.range = range; - stmt.label = label; - return stmt; + var node = new BreakStatement(); + node.kind = NodeKind.BREAK; + node.range = range; + node.label = label; + return node; } static createClassDeclaration( @@ -573,26 +620,28 @@ export abstract class Node { flags: CommonFlags, range: Range ): ClassDeclaration { - var stmt = new ClassDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = identifier; - stmt.typeParameters = typeParameters; - stmt.extendsType = extendsType; - stmt.implementsTypes = implementsTypes; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new ClassDeclaration(); + node.kind = NodeKind.CLASSDECLARATION; + node.range = range; + node.flags = flags; + node.name = identifier; + node.typeParameters = typeParameters; + node.extendsType = extendsType; + node.implementsTypes = implementsTypes; + node.members = members; + node.decorators = decorators; + return node; } static createContinueStatement( label: IdentifierExpression | null, range: Range ): ContinueStatement { - var stmt = new ContinueStatement(); - stmt.range = range; - stmt.label = label; - return stmt; + var node = new ContinueStatement(); + node.kind = NodeKind.CONTINUE; + node.range = range; + node.label = label; + return node; } static createDoStatement( @@ -600,19 +649,21 @@ export abstract class Node { condition: Expression, range: Range ): DoStatement { - var stmt = new DoStatement(); - stmt.range = range; - stmt.statement = statement; - stmt.condition = condition; - return stmt; + var node = new DoStatement(); + node.kind = NodeKind.DO; + node.range = range; + node.statement = statement; + node.condition = condition; + return node; } static createEmptyStatement( range: Range ): EmptyStatement { - var stmt = new EmptyStatement(); - stmt.range = range; - return stmt; + var node = new EmptyStatement(); + node.kind = NodeKind.EMPTY; + node.range = range; + return node; } static createEnumDeclaration( @@ -622,13 +673,14 @@ export abstract class Node { flags: CommonFlags, range: Range ): EnumDeclaration { - var stmt = new EnumDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.values = members; - stmt.decorators = decorators; - return stmt; + var node = new EnumDeclaration(); + node.kind = NodeKind.ENUMDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.values = members; + node.decorators = decorators; + return node; } static createEnumValueDeclaration( @@ -637,12 +689,13 @@ export abstract class Node { flags: CommonFlags, range: Range ): EnumValueDeclaration { - var stmt = new EnumValueDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.value = value; - return stmt; + var node = new EnumValueDeclaration(); + node.kind = NodeKind.ENUMVALUEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.value = value; + return node; } static createExportStatement( @@ -651,10 +704,11 @@ export abstract class Node { isDeclare: bool, range: Range ): ExportStatement { - var stmt = new ExportStatement(); - stmt.range = range; - stmt.members = members; - stmt.path = path; + var node = new ExportStatement(); + node.kind = NodeKind.EXPORT; + node.range = range; + node.members = members; + node.path = path; if (path) { let normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { // relative @@ -662,22 +716,23 @@ export abstract class Node { } else { // absolute if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); + node.internalPath = mangleInternalPath(normalizedPath); } else { - stmt.internalPath = null; + node.internalPath = null; } - stmt.isDeclare = isDeclare; - return stmt; + node.isDeclare = isDeclare; + return node; } static createExportDefaultStatement( declaration: DeclarationStatement, range: Range ): ExportDefaultStatement { - var stmt = new ExportDefaultStatement(); - stmt.declaration = declaration; - stmt.range = range; - return stmt; + var node = new ExportDefaultStatement(); + node.kind = NodeKind.EXPORTDEFAULT; + node.declaration = declaration; + node.range = range; + return node; } static createExportImportStatement( @@ -685,11 +740,12 @@ export abstract class Node { externalName: IdentifierExpression, range: Range ): ExportImportStatement { - var stmt = new ExportImportStatement(); - stmt.range = range; - stmt.name = name; - stmt.externalName = externalName; - return stmt; + var node = new ExportImportStatement(); + node.kind = NodeKind.EXPORTIMPORT; + node.range = range; + node.name = name; + node.externalName = externalName; + return node; } static createExportMember( @@ -697,21 +753,23 @@ export abstract class Node { externalName: IdentifierExpression | null, range: Range ): ExportMember { - var elem = new ExportMember(); - elem.range = range; - elem.localName = name; + var node = new ExportMember(); + node.kind = NodeKind.EXPORTMEMBER; + node.range = range; + node.localName = name; if (!externalName) externalName = name; - elem.exportedName = externalName; - return elem; + node.exportedName = externalName; + return node; } static createExpressionStatement( expression: Expression ): ExpressionStatement { - var stmt = new ExpressionStatement(); - stmt.range = expression.range; - stmt.expression = expression; - return stmt; + var node = new ExpressionStatement(); + node.kind = NodeKind.EXPRESSION; + node.range = expression.range; + node.expression = expression; + return node; } static createIfStatement( @@ -720,12 +778,13 @@ export abstract class Node { ifFalse: Statement | null, range: Range ): IfStatement { - var stmt = new IfStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.ifTrue = ifTrue; - stmt.ifFalse = ifFalse; - return stmt; + var node = new IfStatement(); + node.kind = NodeKind.IF; + node.range = range; + node.condition = condition; + node.ifTrue = ifTrue; + node.ifFalse = ifFalse; + return node; } static createImportStatement( @@ -733,19 +792,20 @@ export abstract class Node { path: StringLiteralExpression, range: Range ): ImportStatement { - var stmt = new ImportStatement(); - stmt.range = range; - stmt.declarations = decls; - stmt.namespaceName = null; - stmt.path = path; + var node = new ImportStatement(); + node.kind = NodeKind.IMPORT; + node.range = range; + node.declarations = decls; + node.namespaceName = null; + node.path = path; var normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { // relative in project normalizedPath = resolvePath(normalizedPath, range.source.internalPath); } else { // absolute in library if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); - return stmt; + node.internalPath = mangleInternalPath(normalizedPath); + return node; } static createImportStatementWithWildcard( @@ -753,19 +813,20 @@ export abstract class Node { path: StringLiteralExpression, range: Range ): ImportStatement { - var stmt = new ImportStatement(); - stmt.range = range; - stmt.declarations = null; - stmt.namespaceName = identifier; - stmt.path = path; + var node = new ImportStatement(); + node.kind = NodeKind.IMPORT; + node.range = range; + node.declarations = null; + node.namespaceName = identifier; + node.path = path; var normalizedPath = normalizePath(path.value); if (path.value.startsWith(".")) { normalizedPath = resolvePath(normalizedPath, range.source.internalPath); } else { if (!normalizedPath.startsWith(LIBRARY_PREFIX)) normalizedPath = LIBRARY_PREFIX + normalizedPath; } - stmt.internalPath = mangleInternalPath(normalizedPath); - return stmt; + node.internalPath = mangleInternalPath(normalizedPath); + return node; } static createImportDeclaration( @@ -773,12 +834,13 @@ export abstract class Node { name: IdentifierExpression | null, range: Range ): ImportDeclaration { - var elem = new ImportDeclaration(); - elem.range = range; - elem.foreignName = foreignName; + var node = new ImportDeclaration(); + node.kind = NodeKind.IMPORTDECLARATION; + node.range = range; + node.foreignName = foreignName; if (!name) name = foreignName; - elem.name = name; - return elem; + node.name = name; + return node; } static createInterfaceDeclaration( @@ -790,15 +852,16 @@ export abstract class Node { flags: CommonFlags, range: Range ): InterfaceDeclaration { - var stmt = new InterfaceDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.extendsType = extendsType; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new InterfaceDeclaration(); + node.kind = NodeKind.INTERFACEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.extendsType = extendsType; + node.members = members; + node.decorators = decorators; + return node; } static createFieldDeclaration( @@ -809,14 +872,15 @@ export abstract class Node { flags: CommonFlags, range: Range ): FieldDeclaration { - var stmt = new FieldDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.type = type; - stmt.initializer = initializer; - stmt.decorators = decorators; - return stmt; + var node = new FieldDeclaration(); + node.kind = NodeKind.FIELDDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.type = type; + node.initializer = initializer; + node.decorators = decorators; + return node; } static createForStatement( @@ -826,13 +890,29 @@ export abstract class Node { statement: Statement, range: Range ): ForStatement { - var stmt = new ForStatement(); - stmt.range = range; - stmt.initializer = initializer; - stmt.condition = condition; - stmt.incrementor = incrementor; - stmt.statement = statement; - return stmt; + var node = new ForStatement(); + node.kind = NodeKind.FOR; + node.range = range; + node.initializer = initializer; + node.condition = condition; + node.incrementor = incrementor; + node.statement = statement; + return node; + } + + static createForOfStatement( + variable: Statement, + iterable: Expression, + statement: Statement, + range: Range + ): ForOfStatement { + var node = new ForOfStatement(); + node.kind = NodeKind.FOROF; + node.range = range; + node.variable = variable; + node.iterable = iterable; + node.statement = statement; + return node; } static createFunctionDeclaration( @@ -845,16 +925,17 @@ export abstract class Node { arrowKind: ArrowKind, range: Range ): FunctionDeclaration { - var stmt = new FunctionDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.signature = signature; - stmt.body = body; - stmt.decorators = decorators; - stmt.arrowKind = arrowKind; - return stmt; + var node = new FunctionDeclaration(); + node.kind = NodeKind.FUNCTIONDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.signature = signature; + node.body = body; + node.decorators = decorators; + node.arrowKind = arrowKind; + return node; } static createIndexSignatureDeclaration( @@ -863,12 +944,13 @@ export abstract class Node { flags: CommonFlags, range: Range ): IndexSignatureDeclaration { - var elem = new IndexSignatureDeclaration(); - elem.range = range; - elem.keyType = keyType; - elem.valueType = valueType; - elem.flags = flags; - return elem; + var node = new IndexSignatureDeclaration(); + node.kind = NodeKind.INDEXSIGNATUREDECLARATION; + node.range = range; + node.keyType = keyType; + node.valueType = valueType; + node.flags = flags; + return node; } static createMethodDeclaration( @@ -880,15 +962,16 @@ export abstract class Node { flags: CommonFlags, range: Range ): MethodDeclaration { - var stmt = new MethodDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.signature = signature; - stmt.body = body; - stmt.decorators = decorators; - return stmt; + var node = new MethodDeclaration(); + node.kind = NodeKind.METHODDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.signature = signature; + node.body = body; + node.decorators = decorators; + return node; } static createNamespaceDeclaration( @@ -898,23 +981,25 @@ export abstract class Node { flags: CommonFlags, range: Range ): NamespaceDeclaration { - var stmt = new NamespaceDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.members = members; - stmt.decorators = decorators; - return stmt; + var node = new NamespaceDeclaration(); + node.kind = NodeKind.NAMESPACEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.members = members; + node.decorators = decorators; + return node; } static createReturnStatement( value: Expression | null, range: Range ): ReturnStatement { - var stmt = new ReturnStatement(); - stmt.range = range; - stmt.value = value; - return stmt; + var node = new ReturnStatement(); + node.kind = NodeKind.RETURN; + node.range = range; + node.value = value; + return node; } static createSwitchStatement( @@ -922,11 +1007,12 @@ export abstract class Node { cases: SwitchCase[], range: Range ): SwitchStatement { - var stmt = new SwitchStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.cases = cases; - return stmt; + var node = new SwitchStatement(); + node.kind = NodeKind.SWITCH; + node.range = range; + node.condition = condition; + node.cases = cases; + return node; } static createSwitchCase( @@ -934,21 +1020,23 @@ export abstract class Node { statements: Statement[], range: Range ): SwitchCase { - var elem = new SwitchCase(); - elem.range = range; - elem.label = label; - elem.statements = statements; - return elem; + var node = new SwitchCase(); + node.kind = NodeKind.SWITCHCASE; + node.range = range; + node.label = label; + node.statements = statements; + return node; } static createThrowStatement( value: Expression, range: Range ): ThrowStatement { - var stmt = new ThrowStatement(); - stmt.range = range; - stmt.value = value; - return stmt; + var node = new ThrowStatement(); + node.kind = NodeKind.THROW; + node.range = range; + node.value = value; + return node; } static createTryStatement( @@ -958,13 +1046,14 @@ export abstract class Node { finallyStatements: Statement[] | null, range: Range ): TryStatement { - var stmt = new TryStatement(); - stmt.range = range; - stmt.statements = statements; - stmt.catchVariable = catchVariable; - stmt.catchStatements = catchStatements; - stmt.finallyStatements = finallyStatements; - return stmt; + var node = new TryStatement(); + node.kind = NodeKind.TRY; + node.range = range; + node.statements = statements; + node.catchVariable = catchVariable; + node.catchStatements = catchStatements; + node.finallyStatements = finallyStatements; + return node; } static createTypeDeclaration( @@ -975,14 +1064,15 @@ export abstract class Node { flags: CommonFlags, range: Range ): TypeDeclaration { - var stmt = new TypeDeclaration(); - stmt.range = range; - stmt.flags = flags; - stmt.name = name; - stmt.typeParameters = typeParameters; - stmt.type = alias; - stmt.decorators = decorators; - return stmt; + var node = new TypeDeclaration(); + node.kind = NodeKind.TYPEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.typeParameters = typeParameters; + node.type = alias; + node.decorators = decorators; + return node; } static createVariableStatement( @@ -990,11 +1080,12 @@ export abstract class Node { decorators: DecoratorNode[] | null, range: Range ): VariableStatement { - var stmt = new VariableStatement(); - stmt.range = range; - stmt.declarations = declarations; - stmt.decorators = decorators; - return stmt; + var node = new VariableStatement(); + node.kind = NodeKind.VARIABLE; + node.range = range; + node.declarations = declarations; + node.decorators = decorators; + return node; } static createVariableDeclaration( @@ -1005,24 +1096,26 @@ export abstract class Node { flags: CommonFlags, range: Range ): VariableDeclaration { - var elem = new VariableDeclaration(); - elem.range = range; - elem.flags = flags; - elem.name = name; - elem.type = type; - elem.initializer = initializer; - elem.decorators = decorators; // inherited - return elem; + var node = new VariableDeclaration(); + node.kind = NodeKind.VARIABLEDECLARATION; + node.range = range; + node.flags = flags; + node.name = name; + node.type = type; + node.initializer = initializer; + node.decorators = decorators; // inherited + return node; } static createVoidStatement( expression: Expression, range: Range ): VoidStatement { - var stmt = new VoidStatement(); - stmt.range = range; - stmt.expression = expression; - return stmt; + var node = new VoidStatement(); + node.kind = NodeKind.VOID; + node.range = range; + node.expression = expression; + return node; } static createWhileStatement( @@ -1030,11 +1123,12 @@ export abstract class Node { statement: Statement, range: Range ): WhileStatement { - var stmt = new WhileStatement(); - stmt.range = range; - stmt.condition = condition; - stmt.statement = statement; - return stmt; + var node = new WhileStatement(); + node.kind = NodeKind.WHILE; + node.range = range; + node.condition = condition; + node.statement = statement; + return node; } } @@ -1052,7 +1146,7 @@ export abstract class TypeNode extends Node { if (this.kind == NodeKind.NAMEDTYPE) { if (!(self).name.next) { let typeArgumentNodes = (self).typeArguments; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { for (let i = 0, k = typeArgumentNodes.length; i < k; ++i) { if (typeArgumentNodes[i].hasGenericComponent(typeParameterNodes)) return true; } @@ -1080,8 +1174,6 @@ export abstract class TypeNode extends Node { /** Represents a type name. */ export class TypeName extends Node { - kind = NodeKind.TYPENAME; - /** Identifier of this part. */ identifier: IdentifierExpression; /** Next part of the type name or `null` if this is the last part. */ @@ -1090,8 +1182,6 @@ export class TypeName extends Node { /** Represents a named type. */ export class NamedTypeNode extends TypeNode { - kind = NodeKind.NAMEDTYPE; - /** Type name. */ name: TypeName; /** Type argument references. */ @@ -1105,8 +1195,6 @@ export class NamedTypeNode extends TypeNode { /** Represents a function type. */ export class FunctionTypeNode extends TypeNode { - kind = NodeKind.FUNCTIONTYPE; - /** Accepted parameters. */ parameters: ParameterNode[]; /** Return type. */ @@ -1117,8 +1205,6 @@ export class FunctionTypeNode extends TypeNode { /** Represents a type parameter. */ export class TypeParameterNode extends Node { - kind = NodeKind.TYPEPARAMETER; - /** Identifier reference. */ name: IdentifierExpression; /** Extended type reference, if any. */ @@ -1139,8 +1225,6 @@ export enum ParameterKind { /** Represents a function parameter. */ export class ParameterNode extends Node { - kind = NodeKind.PARAMETER; - /** Parameter kind. */ parameterKind: ParameterKind; /** Parameter name. */ @@ -1240,10 +1324,8 @@ export namespace DecoratorKind { break; } case CharCode.p: { - switch (propStr) { - case "prefix": return DecoratorKind.OPERATOR_PREFIX; - case "postfix": return DecoratorKind.OPERATOR_POSTFIX; - } + if (propStr == "prefix") return DecoratorKind.OPERATOR_PREFIX; + if (propStr == "postfix") return DecoratorKind.OPERATOR_POSTFIX; break; } } @@ -1255,8 +1337,6 @@ export namespace DecoratorKind { /** Represents a decorator. */ export class DecoratorNode extends Node { - kind = NodeKind.DECORATOR; - /** Built-in kind, if applicable. */ decoratorKind: DecoratorKind; /** Name expression. */ @@ -1277,8 +1357,6 @@ export enum CommentKind { /** Represents a comment. */ export class CommentNode extends Node { - kind = NodeKind.COMMENT; - /** Comment kind. */ commentKind: CommentKind; /** Comment text. */ @@ -1292,8 +1370,6 @@ export abstract class Expression extends Node { } /** Represents an identifier expression. */ export class IdentifierExpression extends Expression { - kind = NodeKind.IDENTIFIER; - /** Textual name. */ text: string; /** Whether quoted or not. */ @@ -1323,16 +1399,12 @@ export function isNumericLiteral(node: Expression): bool { /** Base class of all literal expressions. */ export abstract class LiteralExpression extends Expression { - kind = NodeKind.LITERAL; - /** Specific literal kind. */ literalKind: LiteralKind; } /** Represents an `[]` literal expression. */ export class ArrayLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.ARRAY; - /** Nested element expressions. */ elementExpressions: (Expression | null)[]; } @@ -1347,8 +1419,6 @@ export enum AssertionKind { /** Represents an assertion expression. */ export class AssertionExpression extends Expression { - kind = NodeKind.ASSERTION; - /** Specific kind of this assertion. */ assertionKind: AssertionKind; /** Expression being asserted. */ @@ -1359,8 +1429,6 @@ export class AssertionExpression extends Expression { /** Represents a binary expression. */ export class BinaryExpression extends Expression { - kind = NodeKind.BINARY; - /** Operator token. */ operator: Token; /** Left-hand side expression */ @@ -1371,8 +1439,6 @@ export class BinaryExpression extends Expression { /** Represents a call expression. */ export class CallExpression extends Expression { - kind = NodeKind.CALL; - /** Called expression. Usually an identifier or property access expression. */ expression: Expression; /** Provided type arguments. */ @@ -1384,8 +1450,10 @@ export class CallExpression extends Expression { get typeArgumentsRange(): Range { var typeArguments = this.typeArguments; var numTypeArguments: i32; - if (typeArguments && (numTypeArguments = typeArguments.length)) { - return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); + if (typeArguments) { + if (numTypeArguments = typeArguments.length) { + return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); + } } return this.expression.range; } @@ -1403,30 +1471,22 @@ export class CallExpression extends Expression { /** Represents a class expression using the 'class' keyword. */ export class ClassExpression extends Expression { - kind = NodeKind.CLASS; - /** Inline class declaration. */ declaration: ClassDeclaration; } /** Represents a comma expression composed of multiple expressions. */ export class CommaExpression extends Expression { - kind = NodeKind.COMMA; - /** Sequential expressions. */ expressions: Expression[]; } /** Represents a `constructor` expression. */ export class ConstructorExpression extends IdentifierExpression { - kind = NodeKind.CONSTRUCTOR; - text = "constructor"; } /** Represents an element access expression, e.g., array access. */ export class ElementAccessExpression extends Expression { - kind = NodeKind.ELEMENTACCESS; - /** Expression being accessed. */ expression: Expression; /** Element of the expression being accessed. */ @@ -1435,24 +1495,18 @@ export class ElementAccessExpression extends Expression { /** Represents a float literal expression. */ export class FloatLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.FLOAT; - /** Float value. */ value: f64; } /** Represents a function expression using the 'function' keyword. */ export class FunctionExpression extends Expression { - kind = NodeKind.FUNCTION; - /** Inline function declaration. */ declaration: FunctionDeclaration; } /** Represents an `instanceof` expression. */ export class InstanceOfExpression extends Expression { - kind = NodeKind.INSTANCEOF; - /** Expression being asserted. */ expression: Expression; /** Type to test for. */ @@ -1461,16 +1515,12 @@ export class InstanceOfExpression extends Expression { /** Represents an integer literal expression. */ export class IntegerLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.INTEGER; - /** Integer value. */ - value: I64; + value: i64; } /** Represents a `new` expression. Like a call but with its own kind. */ export class NewExpression extends Expression { - kind = NodeKind.NEW; - /** Type being constructed. */ typeName: TypeName; /** Provided type arguments. */ @@ -1482,7 +1532,7 @@ export class NewExpression extends Expression { get typeArgumentsRange(): Range { var typeArguments = this.typeArguments; var numTypeArguments: i32; - if (typeArguments && (numTypeArguments = typeArguments.length)) { + if (typeArguments !== null && (numTypeArguments = typeArguments.length) > 0) { return Range.join(typeArguments[0].range, typeArguments[numTypeArguments - 1].range); } return this.typeName.range; @@ -1501,14 +1551,10 @@ export class NewExpression extends Expression { /** Represents a `null` expression. */ export class NullExpression extends IdentifierExpression { - kind = NodeKind.NULL; - text = "null"; } /** Represents an object literal expression. */ export class ObjectLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.OBJECT; - /** Field names. */ names: IdentifierExpression[]; /** Field values. */ @@ -1517,16 +1563,12 @@ export class ObjectLiteralExpression extends LiteralExpression { /** Represents a parenthesized expression. */ export class ParenthesizedExpression extends Expression { - kind = NodeKind.PARENTHESIZED; - /** Expression in parenthesis. */ expression: Expression; } /** Represents a property access expression. */ export class PropertyAccessExpression extends Expression { - kind = NodeKind.PROPERTYACCESS; - /** Expression being accessed. */ expression: Expression; /** Property of the expression being accessed. */ @@ -1535,8 +1577,6 @@ export class PropertyAccessExpression extends Expression { /** Represents a regular expression literal expression. */ export class RegexpLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.REGEXP; - /** Regular expression pattern. */ pattern: string; /** Regular expression flags. */ @@ -1545,8 +1585,6 @@ export class RegexpLiteralExpression extends LiteralExpression { /** Represents a ternary expression, i.e., short if notation. */ export class TernaryExpression extends Expression { - kind = NodeKind.TERNARY; - /** Condition expression. */ condition: Expression; /** Expression executed when condition is `true`. */ @@ -1557,39 +1595,28 @@ export class TernaryExpression extends Expression { /** Represents a string literal expression. */ export class StringLiteralExpression extends LiteralExpression { - literalKind = LiteralKind.STRING; - /** String value without quotes. */ value: string; } /** Represents a `super` expression. */ export class SuperExpression extends IdentifierExpression { - kind = NodeKind.SUPER; - text = "super"; } /** Represents a `this` expression. */ export class ThisExpression extends IdentifierExpression { - kind = NodeKind.THIS; - text = "this"; } /** Represents a `true` expression. */ export class TrueExpression extends IdentifierExpression { - kind = NodeKind.TRUE; - text = "true"; } /** Represents a `false` expression. */ export class FalseExpression extends IdentifierExpression { - kind = NodeKind.FALSE; - text = "false"; } /** Base class of all unary expressions. */ export abstract class UnaryExpression extends Expression { - /** Operator token. */ operator: Token; /** Operand expression. */ @@ -1598,12 +1625,10 @@ export abstract class UnaryExpression extends Expression { /** Represents a unary postfix expression, e.g. a postfix increment. */ export class UnaryPostfixExpression extends UnaryExpression { - kind = NodeKind.UNARYPOSTFIX; } /** Represents a unary prefix expression, e.g. a negation. */ export class UnaryPrefixExpression extends UnaryExpression { - kind = NodeKind.UNARYPREFIX; } // statements @@ -1625,9 +1650,6 @@ export enum SourceKind { /** A top-level source node. */ export class Source extends Node { - kind = NodeKind.SOURCE; - parent = null; - /** Source kind. */ sourceKind: SourceKind; /** Normalized path with file extension. */ @@ -1648,6 +1670,7 @@ export class Source extends Node { /** Constructs a new source node. */ constructor(normalizedPath: string, text: string, kind: SourceKind) { super(); + this.kind = NodeKind.SOURCE; this.sourceKind = kind; this.normalizedPath = normalizedPath; var internalPath = mangleInternalPath(this.normalizedPath); @@ -1690,8 +1713,6 @@ export abstract class DeclarationStatement extends Statement { /** Represents an index signature declaration. */ export class IndexSignatureDeclaration extends DeclarationStatement { - kind = NodeKind.INDEXSIGNATUREDECLARATION; - /** Key type. */ keyType: NamedTypeNode; /** Value type. */ @@ -1700,7 +1721,6 @@ export class IndexSignatureDeclaration extends DeclarationStatement { /** Base class of all variable-like declaration statements. */ export abstract class VariableLikeDeclarationStatement extends DeclarationStatement { - /** Variable type. */ type: TypeNode | null; /** Variable initializer. */ @@ -1709,24 +1729,18 @@ export abstract class VariableLikeDeclarationStatement extends DeclarationStatem /** Represents a block statement. */ export class BlockStatement extends Statement { - kind = NodeKind.BLOCK; - /** Contained statements. */ statements: Statement[]; } /** Represents a `break` statement. */ export class BreakStatement extends Statement { - kind = NodeKind.BREAK; - /** Target label, if applicable. */ label: IdentifierExpression | null; } /** Represents a `class` declaration. */ export class ClassDeclaration extends DeclarationStatement { - kind = NodeKind.CLASSDECLARATION; - /** Accepted type parameters. */ typeParameters: TypeParameterNode[] | null; /** Base class type being extended, if any. */ @@ -1744,16 +1758,12 @@ export class ClassDeclaration extends DeclarationStatement { /** Represents a `continue` statement. */ export class ContinueStatement extends Statement { - kind = NodeKind.CONTINUE; - /** Target label, if applicable. */ label: IdentifierExpression | null; } /** Represents a `do` statement. */ export class DoStatement extends Statement { - kind = NodeKind.DO; - /** Statement being looped over. */ statement: Statement; /** Condition when to repeat. */ @@ -1762,30 +1772,22 @@ export class DoStatement extends Statement { /** Represents an empty statement, i.e., a semicolon terminating nothing. */ export class EmptyStatement extends Statement { - kind = NodeKind.EMPTY; } /** Represents an `enum` declaration. */ export class EnumDeclaration extends DeclarationStatement { - kind = NodeKind.ENUMDECLARATION; - /** Enum value declarations. */ values: EnumValueDeclaration[]; } /** Represents a value of an `enum` declaration. */ export class EnumValueDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.ENUMVALUEDECLARATION; - // name is inherited - /** Value expression. */ value: Expression | null; } /** Represents an `export import` statement of an interface. */ -export class ExportImportStatement extends Node { - kind = NodeKind.EXPORTIMPORT; - +export class ExportImportStatement extends Statement { /** Identifier being imported. */ name: IdentifierExpression; /** Identifier being exported. */ @@ -1794,8 +1796,6 @@ export class ExportImportStatement extends Node { /** Represents a member of an `export` statement. */ export class ExportMember extends Node { - kind = NodeKind.EXPORTMEMBER; - /** Local identifier. */ localName: IdentifierExpression; /** Exported identifier. */ @@ -1804,8 +1804,6 @@ export class ExportMember extends Node { /** Represents an `export` statement. */ export class ExportStatement extends Statement { - kind = NodeKind.EXPORT; - /** Array of members if a set of named exports, or `null` if a file export. */ members: ExportMember[] | null; /** Path being exported from, if applicable. */ @@ -1818,36 +1816,25 @@ export class ExportStatement extends Statement { /** Represents an `export default` statement. */ export class ExportDefaultStatement extends Statement { - kind = NodeKind.EXPORTDEFAULT; - /** Declaration being exported as default. */ declaration: DeclarationStatement; } /** Represents an expression that is used as a statement. */ export class ExpressionStatement extends Statement { - kind = NodeKind.EXPRESSION; - /** Expression being used as a statement.*/ expression: Expression; } /** Represents a field declaration within a `class`. */ export class FieldDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.FIELDDECLARATION; - /** Parameter index if declared as a constructor parameter, otherwise `-1`. */ parameterIndex: i32 = -1; } /** Represents a `for` statement. */ export class ForStatement extends Statement { - kind = NodeKind.FOR; - - /** - * Initializer statement, if present. - * Either a {@link VariableStatement} or {@link ExpressionStatement}. - */ + /** Initializer statement, if present. Either a `VariableStatement` or `ExpressionStatement`. */ initializer: Statement | null; /** Condition expression, if present. */ condition: Expression | null; @@ -1857,6 +1844,16 @@ export class ForStatement extends Statement { statement: Statement; } +/** Represents a `for..of` statement. */ +export class ForOfStatement extends Statement { + /** Variable statement. Either a `VariableStatement` or `ExpressionStatement` of `IdentifierExpression`. */ + variable: Statement; + /** Iterable expression being iterated. */ + iterable: Expression; + /** Statement being looped over. */ + statement: Statement; +} + /** Indicates the kind of an array function. */ export const enum ArrowKind { /** Not an arrow function. */ @@ -1869,8 +1866,6 @@ export const enum ArrowKind { /** Represents a `function` declaration. */ export class FunctionDeclaration extends DeclarationStatement { - kind = NodeKind.FUNCTIONDECLARATION; - /** Type parameters, if any. */ typeParameters: TypeParameterNode[] | null; /** Function signature. */ @@ -1902,8 +1897,6 @@ export class FunctionDeclaration extends DeclarationStatement { /** Represents an `if` statement. */ export class IfStatement extends Statement { - kind = NodeKind.IF; - /** Condition. */ condition: Expression; /** Statement executed when condition is `true`. */ @@ -1914,16 +1907,12 @@ export class IfStatement extends Statement { /** Represents an `import` declaration part of an {@link ImportStatement}. */ export class ImportDeclaration extends DeclarationStatement { - kind = NodeKind.IMPORTDECLARATION; - /** Identifier being imported. */ foreignName: IdentifierExpression; } /** Represents an `import` statement. */ export class ImportStatement extends Statement { - kind = NodeKind.IMPORT; - /** Array of member declarations or `null` if an asterisk import. */ declarations: ImportDeclaration[] | null; /** Name of the local namespace, if an asterisk import. */ @@ -1936,34 +1925,26 @@ export class ImportStatement extends Statement { /** Represents an `interfarce` declaration. */ export class InterfaceDeclaration extends ClassDeclaration { - kind = NodeKind.INTERFACEDECLARATION; } /** Represents a method declaration within a `class`. */ export class MethodDeclaration extends FunctionDeclaration { - kind = NodeKind.METHODDECLARATION; } /** Represents a `namespace` declaration. */ export class NamespaceDeclaration extends DeclarationStatement { - kind = NodeKind.NAMESPACEDECLARATION; - /** Array of namespace members. */ members: Statement[]; } /** Represents a `return` statement. */ export class ReturnStatement extends Statement { - kind = NodeKind.RETURN; - /** Value expression being returned, if present. */ value: Expression | null; } /** Represents a single `case` within a `switch` statement. */ export class SwitchCase extends Node { - kind = NodeKind.SWITCHCASE; - /** Label expression. `null` indicates the default case. */ label: Expression | null; /** Contained statements. */ @@ -1972,8 +1953,6 @@ export class SwitchCase extends Node { /** Represents a `switch` statement. */ export class SwitchStatement extends Statement { - kind = NodeKind.SWITCH; - /** Condition expression. */ condition: Expression; /** Contained cases. */ @@ -1982,16 +1961,12 @@ export class SwitchStatement extends Statement { /** Represents a `throw` statement. */ export class ThrowStatement extends Statement { - kind = NodeKind.THROW; - /** Value expression being thrown. */ value: Expression; } /** Represents a `try` statement. */ export class TryStatement extends Statement { - kind = NodeKind.TRY; - /** Contained statements. */ statements: Statement[]; /** Exception variable name, if a `catch` clause is present. */ @@ -2004,8 +1979,6 @@ export class TryStatement extends Statement { /** Represents a `type` declaration. */ export class TypeDeclaration extends DeclarationStatement { - kind = NodeKind.TYPEDECLARATION; - /** Type parameters, if any. */ typeParameters: TypeParameterNode[] | null; /** Type being aliased. */ @@ -2014,13 +1987,10 @@ export class TypeDeclaration extends DeclarationStatement { /** Represents a variable declaration part of a {@link VariableStatement}. */ export class VariableDeclaration extends VariableLikeDeclarationStatement { - kind = NodeKind.VARIABLEDECLARATION; } /** Represents a variable statement wrapping {@link VariableDeclaration}s. */ export class VariableStatement extends Statement { - kind = NodeKind.VARIABLE; - /** Array of decorators. */ decorators: DecoratorNode[] | null; /** Array of member declarations. */ @@ -2029,16 +1999,12 @@ export class VariableStatement extends Statement { /** Represents a void statement dropping an expression's value. */ export class VoidStatement extends Statement { - kind = NodeKind.VOID; - /** Expression being dropped. */ expression: Expression; } /** Represents a `while` statement. */ export class WhileStatement extends Statement { - kind = NodeKind.WHILE; - /** Condition expression. */ condition: Expression; /** Statement being looped over. */ @@ -2066,7 +2032,7 @@ export function mangleInternalPath(path: string): string { export function isTypeOmitted(type: TypeNode): bool { if (type.kind == NodeKind.NAMEDTYPE) { let name = (type).name; - return !(name.next || name.identifier.text.length); + return !(name.next !== null || name.identifier.text.length > 0); } return false; } diff --git a/src/builtins.ts b/src/builtins.ts index 2684afe098..d6feedaf4a 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -10,11 +10,11 @@ } from "./compiler"; import { - DiagnosticCode + DiagnosticCode, + DiagnosticCategory } from "./diagnostics"; import { - Node, NodeKind, Expression, LiteralKind, @@ -568,4165 +568,7098 @@ export namespace BuiltinNames { export const Float64Array = "~lib/typedarray/Float64Array"; } -/** Compiles a call to a built-in function. */ -export function compileCall( - /* Compiler reference. */ - compiler: Compiler, - /** Respective function prototype. */ - prototype: FunctionPrototype, - /** Pre-resolved type arguments. */ - typeArguments: Type[] | null, - /** Operand expressions. */ - operands: Expression[], +/** Builtin compilation context. */ +export class BuiltinContext { + /** Compiler reference. */ + compiler: Compiler; + /** Prototype being called. */ + prototype: FunctionPrototype; + /** Provided type arguments. */ + typeArguments: Type[] | null; + /** Provided operands. */ + operands: Expression[]; /** Contextual type. */ - contextualType: Type, + contextualType: Type; /** Respective call expression. */ - reportNode: CallExpression, - /** Indicates that contextual type is ASM type. */ - isAsm: bool = false -): ExpressionRef { + reportNode: CallExpression; + /** Whether originating from inline assembly. */ + contextIsExact: bool; +} + +/** Registered builtins. */ +export const builtins = new Map ExpressionRef>(); + +// === Static type evaluation ================================================================= + +// isInteger() / isInteger(value: T) -> bool +function builtin_isInteger(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) ? 1 : 0); +} +builtins.set(BuiltinNames.isInteger, builtin_isInteger); + +// isFloat() / isFloat(value: T) -> bool +function builtin_isFloat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.FLOAT) ? 1 : 0); +} +builtins.set(BuiltinNames.isFloat, builtin_isFloat); - switch (prototype.internalName) { +// isBoolean() / isBoolean(value: T) -> bool +function builtin_isBoolean(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type == Type.bool ? 1 : 0); +} +builtins.set(BuiltinNames.isBoolean, builtin_isBoolean); - // === Static type evaluation ================================================================= +// isSigned() / isSigned(value: T) -> bool +function builtin_isSigned(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.SIGNED) ? 1 : 0); +} +builtins.set(BuiltinNames.isSigned, builtin_isSigned); - case BuiltinNames.isInteger: { // isInteger() / isInteger(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isFloat: { // isFloat() / isFloat(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.FLOAT) - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isBoolean: { // isBoolean() / isBoolean(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type == Type.bool - ? module.i32(1) - : module.i32(0); - } - case BuiltinNames.isSigned: { // isSigned() / isSigned(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.SIGNED) - ? module.i32(1) - : module.i32(0); +// isReference() / isReference(value: T) -> bool +function builtin_isReference(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.REFERENCE) ? 1 : 0); +} +builtins.set(BuiltinNames.isReference, builtin_isReference); + +// isString() / isString(value: T) -> bool +function builtin_isString(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + let stringInstance = compiler.program.stringInstance; + if (stringInstance !== null && classReference.isAssignableTo(stringInstance)) return module.i32(1); } - case BuiltinNames.isReference: { // isReference() / isReference(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return type.is(TypeFlags.REFERENCE) - ? module.i32(1) - : module.i32(0); + } + return module.i32(0); +} +builtins.set(BuiltinNames.isString, builtin_isString); + +// isArray() / isArray(value: T) -> bool +function builtin_isArray(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0); } - case BuiltinNames.isString: { // isString() / isString(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - let stringInstance = compiler.program.stringInstance; - if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1); - } - } - return module.i32(0); + } + return module.i32(0); +} +builtins.set(BuiltinNames.isArray, builtin_isArray); + +// isArrayLike() / isArrayLike(value: T) -> bool +function builtin_isArrayLike(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let classReference = type.classReference; + if (classReference) { + return module.i32(classReference.isArrayLike ? 1 : 0); } - case BuiltinNames.isArray: { // isArray() / isArray(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0); - } + } + return module.i32(0); +} +builtins.set(BuiltinNames.isArrayLike, builtin_isArrayLike); + +// isFunction / isFunction(value: T) -> bool +function builtin_isFunction(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.signatureReference ? 1 : 0); +} +builtins.set(BuiltinNames.isFunction, builtin_isFunction); + +// isNullable / isNullable(value: T) -> bool +function builtin_isNullable(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.is(TypeFlags.NULLABLE) ? 1 : 0); +} +builtins.set(BuiltinNames.isNullable, builtin_isNullable); + +// isDefined(expression) -> bool +function builtin_isDefined(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.bool; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var element = compiler.resolver.lookupExpression( + ctx.operands[0], + compiler.currentFlow, + Type.auto, + ReportMode.SWALLOW + ); + return module.i32(element ? 1 : 0); +} +builtins.set(BuiltinNames.isDefined, builtin_isDefined); + +// isConstant(expression) -> bool +function builtin_isConstant(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.bool; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var expr = compiler.compileExpression(ctx.operands[0], Type.auto); + compiler.currentType = Type.bool; + return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0); +} +builtins.set(BuiltinNames.isConstant, builtin_isConstant); + +// isManaged() -> bool +function builtin_isManaged(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.isManaged ? 1 : 0); +} +builtins.set(BuiltinNames.isManaged, builtin_isManaged); + +// isVoid() -> bool +function builtin_isVoid(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.bool; + if (!type) return module.unreachable(); + return module.i32(type.kind == TypeKind.VOID ? 1 : 0); +} +builtins.set(BuiltinNames.isVoid, builtin_isVoid); + +// lengthof() -> i32 +function builtin_lengthof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.i32; + if (!type) return module.unreachable(); + var signatureReference = type.signatureReference; + if (!signatureReference) { + compiler.error( + DiagnosticCode.Type_0_has_no_call_signatures, + ctx.reportNode.range, type.toString() + ); + return module.unreachable(); + } + return module.i32(signatureReference.parameterTypes.length); +} +builtins.set(BuiltinNames.lengthof, builtin_lengthof); + +// sizeof() -> usize* +function builtin_sizeof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + var type = ctx.typeArguments![0]; + var byteSize = type.byteSize; + if (!byteSize) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "sizeof", type.toString() + ); + return module.unreachable(); + } + return contextualUsize(compiler, i64_new(byteSize), ctx.contextualType); +} +builtins.set(BuiltinNames.sizeof, builtin_sizeof); + +// alignof() -> usize* +function builtin_alignof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + var type = ctx.typeArguments![0]; + var byteSize = type.byteSize; + if (!isPowerOf2(byteSize)) { // implies == 0 + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "alignof", type.toString() + ); + return module.unreachable(); + } + return contextualUsize(compiler, i64_new(ctz(byteSize)), ctx.contextualType); +} +builtins.set(BuiltinNames.alignof, builtin_alignof); + +// offsetof(fieldName?: string) -> usize* +function builtin_offsetof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = compiler.options.usizeType; + if ( + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 0, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var contextualType = ctx.contextualType; + var type = ctx.typeArguments![0]; + var classType = type.classReference; + if (!(type.is(TypeFlags.REFERENCE) && classType !== null)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "offsetof", type.toString() + ); + if (compiler.options.isWasm64) { + if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { + compiler.currentType = Type.u32; } - return module.i32(0); - } - case BuiltinNames.isArrayLike: { // isArrayLike() / isArrayLike(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let classReference = type.classReference; - if (classReference) { - return module.i32(classReference.isArrayLike ? 1 : 0); - } + } else { + if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { + compiler.currentType = Type.u64; } - return module.i32(0); - } - case BuiltinNames.isFunction: { // isFunction / isFunction(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.signatureReference ? 1 : 0); - } - case BuiltinNames.isNullable: { // isNullable / isNullable(value: T) -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.is(TypeFlags.NULLABLE) ? 1 : 0); } - case BuiltinNames.isDefined: { // isDefined(expression) -> bool - compiler.currentType = Type.bool; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let element = compiler.resolver.lookupExpression( - operands[0], - compiler.currentFlow, - Type.auto, - ReportMode.SWALLOW + return module.unreachable(); + } + if (operands.length) { + if ( + operands[0].kind != NodeKind.LITERAL || + (operands[0]).literalKind != LiteralKind.STRING + ) { + compiler.error( + DiagnosticCode.String_literal_expected, + operands[0].range ); - return module.i32(element ? 1 : 0); + return module.unreachable(); + } + let fieldName = (operands[0]).value; + let classMembers = classType.members; + if (classMembers !== null && classMembers.has(fieldName)) { + let member = assert(classMembers.get(fieldName)); + if (member.kind == ElementKind.FIELD) { + return contextualUsize(compiler, i64_new((member).memoryOffset), contextualType); + } } - case BuiltinNames.isConstant: { // isConstant(expression) -> bool - compiler.currentType = Type.bool; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let expr = compiler.compileExpression(operands[0], Type.auto); - compiler.currentType = Type.bool; - return module.i32(getExpressionId(expr) == ExpressionId.Const ? 1 : 0); + compiler.error( + DiagnosticCode.Type_0_has_no_property_1, + operands[0].range, classType.internalName, fieldName + ); + return module.unreachable(); + } + return contextualUsize(compiler, i64_new(classType.nextMemoryOffset), contextualType); +} +builtins.set(BuiltinNames.offsetof, builtin_offsetof); + +// nameof -> string +function builtin_nameof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var resultType = evaluateConstantType(ctx); + if (!resultType) { + compiler.currentType = compiler.program.stringInstance.type; + return module.unreachable(); + } + var value: string; + if (resultType.is(TypeFlags.REFERENCE)) { + let classReference = resultType.classReference; + if (classReference) { + value = classReference.name; + } else { + let signatureReference = resultType.signatureReference; + if (signatureReference) { + value = "Function"; + } else { + value = "Anyref"; + } } - case BuiltinNames.isManaged: { // isManaged() -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.isManaged ? 1 : 0); + } else { + switch (resultType.kind) { + case TypeKind.BOOL: { value = "bool"; break; } + case TypeKind.I8: { value = "i8"; break; } + case TypeKind.U8: { value = "u8"; break; } + case TypeKind.I16: { value = "i16"; break; } + case TypeKind.U16: { value = "u16"; break; } + case TypeKind.I32: { value = "i32"; break; } + case TypeKind.U32: { value = "u32"; break; } + case TypeKind.F32: { value = "f32"; break; } + case TypeKind.I64: { value = "i64"; break; } + case TypeKind.U64: { value = "u64"; break; } + case TypeKind.F64: { value = "f64"; break; } + case TypeKind.ISIZE: { value = "isize"; break; } + case TypeKind.USIZE: { value = "usize"; break; } + case TypeKind.V128: { value = "v128"; break; } + case TypeKind.ANYREF: { value = "anyref"; break; } + default: assert(false); + case TypeKind.VOID: { value = "void"; break; } } - case BuiltinNames.isVoid: { // isVoid() -> bool - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.bool; - if (!type) return module.unreachable(); - return module.i32(type.kind == TypeKind.VOID ? 1 : 0); + } + return compiler.ensureStaticString(value); +} +builtins.set(BuiltinNames.nameof, builtin_nameof); + +// idof -> u32 +function builtin_idof(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var type = evaluateConstantType(ctx); + compiler.currentType = Type.u32; + if (!type) return module.unreachable(); + if (type.is(TypeFlags.REFERENCE)) { + let signatureReference = type.signatureReference; + if (signatureReference) { + return module.i32(signatureReference.id); + } + let classReference = type.classReference; + if (classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { + return module.i32(classReference.id); } - case BuiltinNames.lengthof: { // lengthof() -> i32 - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.i32; - if (!type) return module.unreachable(); - let signatureReference = type.signatureReference; - if (!signatureReference) { - compiler.error( - DiagnosticCode.Type_0_has_no_call_signatures, - reportNode.range, type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "idof", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.idof, builtin_idof); + +// === Math =================================================================================== + +// clz(value: T) -> T +function builtin_clz(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(ctx.operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(ctx.operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.ClzI32, arg0); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.ClzI64 + : UnaryOp.ClzI32, + arg0 ); - return module.unreachable(); } - return module.i32(signatureReference.parameterTypes.length); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.ClzI64, arg0); } - case BuiltinNames.sizeof: { // sizeof() -> usize - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let byteSize = type.byteSize; - if (!byteSize) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "sizeof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "clz", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.clz, builtin_clz); + +// ctz(value: T) -> T +function builtin_ctz(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.CtzI32, arg0); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.CtzI64 + : UnaryOp.CtzI32, + arg0 ); - return module.unreachable(); - } - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(byteSize); - } - return module.i64(byteSize, 0); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(byteSize, 0); - } - return module.i32(byteSize); } + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.CtzI64, arg0); } - case BuiltinNames.alignof: { // alignof() -> usize - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let byteSize = type.byteSize; - if (!isPowerOf2(byteSize)) { // implies == 0 - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "alignof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "ctz", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.ctz, builtin_ctz); + +// popcnt(value: T) -> T +function builtin_popcnt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (compiler.currentType.kind) { + case TypeKind.BOOL: // not wrapped + case TypeKind.I8: + case TypeKind.U8: + case TypeKind.I16: + case TypeKind.U16: + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.PopcntI32, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.PopcntI64, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.PopcntI64 + : UnaryOp.PopcntI32, + arg0 ); - return module.unreachable(); - } - let alignLog2 = ctz(byteSize); - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(alignLog2); - } - return module.i64(alignLog2, 0); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(alignLog2, 0); - } - return module.i32(alignLog2); } } - case BuiltinNames.offsetof: { // offsetof(fieldName?: string) -> usize - compiler.currentType = compiler.options.usizeType; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 0, 1, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let classType = type.classReference; - if (!(type.is(TypeFlags.REFERENCE) && classType !== null)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "offsetof", type.toString() + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "popcnt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.popcnt, builtin_popcnt); + +// rotl(value: T, shift: T) -> T +function builtin_rotl(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.RotlI32, arg0, arg1), + type ); - if (compiler.options.isWasm64) { - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - } - } else { - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - } - } - return module.unreachable(); } - let offset: i32; - if (operands.length) { - if ( - operands[0].kind != NodeKind.LITERAL || - (operands[0]).literalKind != LiteralKind.STRING - ) { - compiler.error( - DiagnosticCode.String_literal_expected, - operands[0].range - ); - return module.unreachable(); - } - let fieldName = (operands[0]).value; - let field = classType.members ? classType.members.get(fieldName) : null; - if (!(field && field.kind == ElementKind.FIELD)) { - compiler.error( - DiagnosticCode.Type_0_has_no_property_1, - operands[0].range, classType.internalName, fieldName - ); - return module.unreachable(); - } - offset = (field).memoryOffset; - } else { - offset = classType.nextMemoryOffset; - } - if (compiler.options.isWasm64) { - // implicitly wrap if contextual type is a 32-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) { - compiler.currentType = Type.u32; - return module.i32(offset); - } - return module.i64(offset); - } else { - // implicitly extend if contextual type is a 64-bit integer - if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) { - compiler.currentType = Type.u64; - return module.i64(offset); - } - return module.i32(offset); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.RotlI32, arg0, arg1); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.RotlI64 + : BinaryOp.RotlI32, + arg0, arg1 + ); } + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.RotlI64, arg0, arg1); } - case BuiltinNames.nameof: { - let resultType = evaluateConstantType(compiler, typeArguments, operands, reportNode); - if (!resultType) { - compiler.currentType = compiler.program.stringInstance.type; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "rotl", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.rotl, builtin_rotl); + +// rotr(value: T, shift: T) -> T +function builtin_rotr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.BOOL: { + return compiler.ensureSmallIntegerWrap( + module.binary(BinaryOp.RotrI32, arg0, arg1), + type + ); } - let value: string; - if (resultType.is(TypeFlags.REFERENCE)) { - let classReference = resultType.classReference; - if (classReference) { - value = classReference.name; - } else { - let signatureReference = resultType.signatureReference; - if (signatureReference) { - value = "Function"; - } else { - value = "Anyref"; - } - } - } else { - switch (resultType.kind) { - case TypeKind.BOOL: { value = "bool"; break; } - case TypeKind.I8: { value = "i8"; break; } - case TypeKind.U8: { value = "u8"; break; } - case TypeKind.I16: { value = "i16"; break; } - case TypeKind.U16: { value = "u16"; break; } - case TypeKind.I32: { value = "i32"; break; } - case TypeKind.U32: { value = "u32"; break; } - case TypeKind.F32: { value = "f32"; break; } - case TypeKind.I64: { value = "i64"; break; } - case TypeKind.U64: { value = "u64"; break; } - case TypeKind.F64: { value = "f64"; break; } - case TypeKind.ISIZE: { value = "isize"; break; } - case TypeKind.USIZE: { value = "usize"; break; } - case TypeKind.V128: { value = "v128"; break; } - case TypeKind.ANYREF: { value = "anyref"; break; } - default: assert(false); - case TypeKind.VOID: { value = "void"; break; } - } + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.RotrI32, arg0, arg1); + case TypeKind.USIZE: + case TypeKind.ISIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.RotrI64 + : BinaryOp.RotrI32, + arg0, arg1 + ); } - return compiler.ensureStaticString(value); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.RotrI64, arg0, arg1); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "rotr", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.rotr, builtin_rotr); - // === Math =================================================================================== - - case BuiltinNames.clz: { // clz(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.ClzI32, arg0); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.ClzI64 - : UnaryOp.ClzI32, - arg0 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.ClzI64, arg0); - } +// abs(value: T) -> T +function builtin_abs(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { + let flow = compiler.currentFlow; + + // possibly overflows, e.g. abs(-128) == 128 + let temp1 = flow.getTempLocal(Type.i32); + let temp2 = flow.getTempLocal(Type.i32); + // (x + (x >> 31)) ^ (x >> 31) + let ret = module.binary(BinaryOp.XorI32, + module.binary(BinaryOp.AddI32, + module.local_tee( + temp2.index, + module.binary(BinaryOp.ShrI32, + module.local_tee(temp1.index, arg0), + module.i32(31) + ) + ), + module.local_get(temp1.index, NativeType.I32) + ), + module.local_get(temp2.index, NativeType.I32) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "clz", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.ctz: { // ctz(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.CtzI32, arg0); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.CtzI64 - : UnaryOp.CtzI32, - arg0 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.CtzI64, arg0); - } + case TypeKind.ISIZE: { + let options = compiler.options; + let flow = compiler.currentFlow; + let isWasm64 = options.isWasm64; + + let temp1 = flow.getTempLocal(options.usizeType); + let temp2 = flow.getTempLocal(options.usizeType); + let ret = module.binary(isWasm64 ? BinaryOp.XorI64 : BinaryOp.XorI32, + module.binary(isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32, + module.local_tee( + temp2.index, + module.binary(isWasm64 ? BinaryOp.ShrI64 : BinaryOp.ShrI32, + module.local_tee(temp1.index, arg0), + isWasm64 ? module.i64(63) : module.i32(31) + ) + ), + module.local_get(temp1.index, options.nativeSizeType) + ), + module.local_get(temp2.index, options.nativeSizeType) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "ctz", type.toString() - ); - return module.unreachable(); + case TypeKind.I64: { + let flow = compiler.currentFlow; + + let temp1 = flow.getTempLocal(Type.i64); + let temp2 = flow.getTempLocal(Type.i64); + // (x + (x >> 63)) ^ (x >> 63) + let ret = module.binary(BinaryOp.XorI64, + module.binary(BinaryOp.AddI64, + module.local_tee( + temp2.index, + module.binary(BinaryOp.ShrI64, + module.local_tee(temp1.index, arg0), + module.i64(63) + ) + ), + module.local_get(temp1.index, NativeType.I64) + ), + module.local_get(temp2.index, NativeType.I64) + ); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; + } + case TypeKind.USIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.BOOL: return arg0; + case TypeKind.F32: return module.unary(UnaryOp.AbsF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.AbsF64, arg0); } - case BuiltinNames.popcnt: { // popcnt(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (compiler.currentType.kind) { - case TypeKind.BOOL: // not wrapped - case TypeKind.I8: - case TypeKind.U8: - case TypeKind.I16: - case TypeKind.U16: - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.PopcntI32, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.PopcntI64, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.PopcntI64 - : UnaryOp.PopcntI32, - arg0 - ); - } - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "abs", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.abs, builtin_abs); + +// max(left: T, right: T) -> T +function builtin_max(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1: ExpressionRef; + if (!typeArguments && isNumericLiteral(left)) { // prefer right type + arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "popcnt", type.toString() + } else { + arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { op = BinaryOp.GtI32; break; } + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { op = BinaryOp.GtU32; break; } + case TypeKind.I64: { op = BinaryOp.GtI64; break; } + case TypeKind.U64: { op = BinaryOp.GtU64; break; } + case TypeKind.ISIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.GtI64 + : BinaryOp.GtI32; + break; + } + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.GtU64 + : BinaryOp.GtU32; + break; + } + case TypeKind.F32: return module.binary(BinaryOp.MaxF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MaxF64, arg0, arg1); + } + if (op != -1) { + let flow = compiler.currentFlow; + let nativeType = type.toNativeType(); + let temp1 = flow.getTempLocal(type); + flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); + let temp2 = flow.getTempLocal(type); + flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); + let ret = module.select( + module.local_tee(temp1.index, arg0), + module.local_tee(temp2.index, arg1), + module.binary(op, + module.local_get(temp1.index, nativeType), + module.local_get(temp2.index, nativeType) + ) ); - return module.unreachable(); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - case BuiltinNames.rotl: { // rotl(value: T, shift: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.BOOL: { - return compiler.ensureSmallIntegerWrap( - module.binary(BinaryOp.RotlI32, arg0, arg1), - type - ); - } - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.RotlI32, arg0, arg1); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.RotlI64 - : BinaryOp.RotlI32, - arg0, arg1 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.RotlI64, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "max", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.max, builtin_max); + +// min(left: T, right: T) -> T +function builtin_min(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var left = operands[0]; + var arg0 = typeArguments + ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1: ExpressionRef; + if (!typeArguments && isNumericLiteral(left)) { // prefer right type + arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); + if (compiler.currentType != type) { + arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "rotl", type.toString() + } else { + arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); + } + let op: BinaryOp = -1; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: { op = BinaryOp.LtI32; break; } + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { op = BinaryOp.LtU32; break; } + case TypeKind.I64: { op = BinaryOp.LtI64; break; } + case TypeKind.U64: { op = BinaryOp.LtU64; break; } + case TypeKind.ISIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.LtI64 + : BinaryOp.LtI32; + break; + } + case TypeKind.USIZE: { + op = compiler.options.isWasm64 + ? BinaryOp.LtU64 + : BinaryOp.LtU32; + break; + } + case TypeKind.F32: return module.binary(BinaryOp.MinF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MinF64, arg0, arg1); + } + if (op != -1) { + let flow = compiler.currentFlow; + let nativeType = type.toNativeType(); + let temp1 = flow.getTempLocal(type); + flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); + let temp2 = flow.getTempLocal(type); + flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); + let ret = module.select( + module.local_tee(temp1.index, arg0), + module.local_tee(temp2.index, arg1), + module.binary(op, + module.local_get(temp1.index, nativeType), + module.local_get(temp2.index, nativeType) + ) ); - return module.unreachable(); + flow.freeTempLocal(temp2); + flow.freeTempLocal(temp1); + return ret; } - case BuiltinNames.rotr: { // rotr(value: T, shift: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.i32, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.BOOL: { - return compiler.ensureSmallIntegerWrap( - module.binary(BinaryOp.RotrI32, arg0, arg1), - type - ); - } - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.RotrI32, arg0, arg1); - case TypeKind.USIZE: - case TypeKind.ISIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.RotrI64 - : BinaryOp.RotrI32, - arg0, arg1 - ); - } - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.RotrI64, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "rotr", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "min", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.min, builtin_min); + +// ceil(value: T) -> T +function builtin_ceil(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered rounded + case TypeKind.F32: return module.unary(UnaryOp.CeilF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.CeilF64, arg0); } - case BuiltinNames.abs: { // abs(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { - let flow = compiler.currentFlow; - - // possibly overflows, e.g. abs(-128) == 128 - let temp1 = flow.getTempLocal(Type.i32); - let temp2 = flow.getTempLocal(Type.i32); - // (x + (x >> 31)) ^ (x >> 31) - let ret = module.binary(BinaryOp.XorI32, - module.binary(BinaryOp.AddI32, - module.local_tee( - temp2.index, - module.binary(BinaryOp.ShrI32, - module.local_tee(temp1.index, arg0), - module.i32(31) - ) - ), - module.local_get(temp1.index, NativeType.I32) - ), - module.local_get(temp2.index, NativeType.I32) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.ISIZE: { - let options = compiler.options; - let flow = compiler.currentFlow; - let isWasm64 = options.isWasm64; - - let temp1 = flow.getTempLocal(options.usizeType); - let temp2 = flow.getTempLocal(options.usizeType); - let ret = module.binary(isWasm64 ? BinaryOp.XorI64 : BinaryOp.XorI32, - module.binary(isWasm64 ? BinaryOp.AddI64 : BinaryOp.AddI32, - module.local_tee( - temp2.index, - module.binary(isWasm64 ? BinaryOp.ShrI64 : BinaryOp.ShrI32, - module.local_tee(temp1.index, arg0), - isWasm64 ? module.i64(63) : module.i32(31) - ) - ), - module.local_get(temp1.index, options.nativeSizeType) - ), - module.local_get(temp2.index, options.nativeSizeType) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.I64: { - let flow = compiler.currentFlow; - - let temp1 = flow.getTempLocal(Type.i64); - let temp2 = flow.getTempLocal(Type.i64); - // (x + (x >> 63)) ^ (x >> 63) - let ret = module.binary(BinaryOp.XorI64, - module.binary(BinaryOp.AddI64, - module.local_tee( - temp2.index, - module.binary(BinaryOp.ShrI64, - module.local_tee(temp1.index, arg0), - module.i64(63) - ) - ), - module.local_get(temp1.index, NativeType.I64) - ), - module.local_get(temp2.index, NativeType.I64) - ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; - } - case TypeKind.USIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.BOOL: return arg0; - case TypeKind.F32: return module.unary(UnaryOp.AbsF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.AbsF64, arg0); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "ceil", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.ceil, builtin_ceil); + +// floor(value: T) -> T +function builtin_floor(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered rounded + case TypeKind.F32: return module.unary(UnaryOp.FloorF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.FloorF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "floor", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.floor, builtin_floor); + +// copysign(left: T, right: T) -> T +function builtin_copysign(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + switch (type.kind) { + // TODO: does an integer version make sense? + case TypeKind.F32: return module.binary(BinaryOp.CopysignF32, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.CopysignF64, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "copysign", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.copysign, builtin_copysign); + +// nearest(value: T) -> T +function builtin_nearest(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; + case TypeKind.F32: return module.unary(UnaryOp.NearestF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.NearestF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "nearest", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.nearest, builtin_nearest); + +// reinterpret(value: *) -> T +function builtin_reinterpret(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var type = typeArguments![0]; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: + case TypeKind.U32: { + let arg0 = compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + return module.unary(UnaryOp.ReinterpretF32, arg0); + } + case TypeKind.I64: + case TypeKind.U64: { + let arg0 = compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + return module.unary(UnaryOp.ReinterpretF64, arg0); + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + let arg0 = compiler.compileExpression(operands[0], + compiler.options.isWasm64 + ? Type.f64 + : Type.f32, + Constraints.CONV_IMPLICIT + ); + compiler.currentType = type; + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.ReinterpretF64 + : UnaryOp.ReinterpretF32, + arg0 + ); + } + case TypeKind.F32: { + let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.f32; + return module.unary(UnaryOp.ReinterpretI32, arg0); + } + case TypeKind.F64: { + let arg0 = compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.f64; + return module.unary(UnaryOp.ReinterpretI64, arg0); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "abs", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.max: { // max(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let left = operands[0]; - let arg0 = typeArguments - ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type - arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); - if (compiler.currentType != type) { - arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - } else { - arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - let op: BinaryOp = -1; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { op = BinaryOp.GtI32; break; } - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { op = BinaryOp.GtU32; break; } - case TypeKind.I64: { op = BinaryOp.GtI64; break; } - case TypeKind.U64: { op = BinaryOp.GtU64; break; } - case TypeKind.ISIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.GtI64 - : BinaryOp.GtI32; - break; - } - case TypeKind.USIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.GtU64 - : BinaryOp.GtU32; - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MaxF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MaxF64, arg0, arg1); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "reinterpret", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.reinterpret, builtin_reinterpret); + +// sqrt(value: T) -> T +function builtin_sqrt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // TODO: integer versions (that return f64 or convert)? + case TypeKind.F32: return module.unary(UnaryOp.SqrtF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SqrtF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "sqrt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.sqrt, builtin_sqrt); + +// trunc(value: T) -> T +function builtin_trunc(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); + var type = compiler.currentType; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.BOOL: return arg0; // considered truncated + case TypeKind.F32: return module.unary(UnaryOp.TruncF32, arg0); + case TypeKind.F64: return module.unary(UnaryOp.TruncF64, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "trunc", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.trunc, builtin_trunc); + +// isNaN(value: T) -> bool +function builtin_isNaN(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // never NaN + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: { + return hasSideEffects(arg0) + ? module.block(null, [ + module.drop(arg0), + module.i32(0) + ], NativeType.I32) + : module.i32(0); + } + // (t = arg0) != t + case TypeKind.F32: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.NeF32, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F32) + ); } - if (op != -1) { - let flow = compiler.currentFlow; - let nativeType = type.toNativeType(); - let temp1 = flow.getTempLocal(type); - flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); - let temp2 = flow.getTempLocal(type); - flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); - let ret = module.select( - module.local_tee(temp1.index, arg0), - module.local_tee(temp2.index, arg1), - module.binary(op, - module.local_get(temp1.index, nativeType), - module.local_get(temp2.index, nativeType) - ) + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f32); + let ret = module.binary(BinaryOp.NeF32, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F32) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.NeF64, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F64) ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; } + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f64); + let ret = module.binary(BinaryOp.NeF64, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F64) + ); + flow.freeTempLocal(temp); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "max", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.min: { // min(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let left = operands[0]; - let arg0 = typeArguments - ? compiler.compileExpression(left, typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.auto, Constraints.MUST_WRAP); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1: ExpressionRef; - if (!typeArguments && isNumericLiteral(left)) { // prefer right type - arg1 = compiler.compileExpression(operands[1], type, Constraints.MUST_WRAP); - if (compiler.currentType != type) { - arg0 = compiler.compileExpression(left, type = compiler.currentType, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - } else { - arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP); - } - let op: BinaryOp = -1; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: { op = BinaryOp.LtI32; break; } - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { op = BinaryOp.LtU32; break; } - case TypeKind.I64: { op = BinaryOp.LtI64; break; } - case TypeKind.U64: { op = BinaryOp.LtU64; break; } - case TypeKind.ISIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.LtI64 - : BinaryOp.LtI32; - break; - } - case TypeKind.USIZE: { - op = compiler.options.isWasm64 - ? BinaryOp.LtU64 - : BinaryOp.LtU32; - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MinF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MinF64, arg0, arg1); - } - if (op != -1) { - let flow = compiler.currentFlow; - let nativeType = type.toNativeType(); - let temp1 = flow.getTempLocal(type); - flow.setLocalFlag(temp1.index, LocalFlags.WRAPPED); - let temp2 = flow.getTempLocal(type); - flow.setLocalFlag(temp2.index, LocalFlags.WRAPPED); - let ret = module.select( - module.local_tee(temp1.index, arg0), - module.local_tee(temp2.index, arg1), - module.binary(op, - module.local_get(temp1.index, nativeType), - module.local_get(temp2.index, nativeType) - ) + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "isNaN", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.isNaN, builtin_isNaN); + +// isFinite(value: T) -> bool +function builtin_isFinite(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + // always finite + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: { + return hasSideEffects(arg0) + ? module.block(null, [ + module.drop(arg0), + module.i32(1) + ], NativeType.I32) + : module.i32(1); + } + // (t = arg0) - t == 0 + case TypeKind.F32: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.EqF32, + module.binary(BinaryOp.SubF32, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F32) + ), + module.f32(0) ); - flow.freeTempLocal(temp2); - flow.freeTempLocal(temp1); - return ret; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "min", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.ceil: { // ceil(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered rounded - case TypeKind.F32: return module.unary(UnaryOp.CeilF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.CeilF64, arg0); + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f32); + let ret = module.binary(BinaryOp.EqF32, + module.binary(BinaryOp.SubF32, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F32) + ), + module.f32(0) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + if (getExpressionId(arg0) == ExpressionId.LocalGet) { + return module.binary(BinaryOp.EqF64, + module.binary(BinaryOp.SubF64, + arg0, + module.local_get(getLocalGetIndex(arg0), NativeType.F64) + ), + module.f64(0) + ); } + let flow = compiler.currentFlow; + let temp = flow.getTempLocal(Type.f64); + let ret = module.binary(BinaryOp.EqF64, + module.binary(BinaryOp.SubF64, + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.F64) + ), + module.f64(0) + ); + flow.freeTempLocal(temp); + return ret; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "ceil", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.floor: { // floor(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered rounded - case TypeKind.F32: return module.unary(UnaryOp.FloorF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.FloorF64, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "floor", type.toString() - ); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "isFinite", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.isFinite, builtin_isFinite); + +// === Memory access ========================================================================== + +// load(offset: usize, immOffset?: usize, immAlign?: usize) -> T* +function builtin_load(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var outType = ( + contextualType != Type.auto && + type.is(TypeFlags.INTEGER) && + contextualType.is(TypeFlags.INTEGER) && + contextualType.size > type.size + ) ? contextualType : type; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = outType; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { + compiler.currentType = outType; return module.unreachable(); } - case BuiltinNames.copysign: { // copysign(left: T, right: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - switch (type.kind) { - // TODO: does an integer version make sense? - case TypeKind.F32: return module.binary(BinaryOp.CopysignF32, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.CopysignF64, arg0, arg1); - } - } + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "copysign", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() ); + compiler.currentType = outType; return module.unreachable(); } - case BuiltinNames.nearest: { // nearest(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; - case TypeKind.F32: return module.unary(UnaryOp.NearestF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.NearestF64, arg0); - } - } + if (!isPowerOf2(immAlign)) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "nearest", type.toString() + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" ); + compiler.currentType = outType; return module.unreachable(); } - case BuiltinNames.reinterpret: { // reinterpret(value: *) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: - case TypeKind.U32: { - let arg0 = compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - return module.unary(UnaryOp.ReinterpretF32, arg0); - } - case TypeKind.I64: - case TypeKind.U64: { - let arg0 = compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - return module.unary(UnaryOp.ReinterpretF64, arg0); - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - let arg0 = compiler.compileExpression(operands[0], - compiler.options.isWasm64 - ? Type.f64 - : Type.f32, - Constraints.CONV_IMPLICIT - ); - compiler.currentType = type; - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.ReinterpretF64 - : UnaryOp.ReinterpretF32, - arg0 - ); - } - case TypeKind.F32: { - let arg0 = compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.f32; - return module.unary(UnaryOp.ReinterpretI32, arg0); - } - case TypeKind.F64: { - let arg0 = compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.f64; - return module.unary(UnaryOp.ReinterpretI64, arg0); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "reinterpret", type.toString() + } else { + immAlign = naturalAlign; + } + compiler.currentType = outType; + return module.load( + type.byteSize, + type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), + arg0, + outType.toNativeType(), + immOffset, + immAlign + ); +} +builtins.set(BuiltinNames.load, builtin_load); + +// store(offset: usize, value: T*, offset?: usize, align?: usize) -> void +function builtin_store(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 2, 4) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = ctx.contextIsExact + ? compiler.compileExpression(operands[1], + contextualType, + Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT ); + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length >= 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (operands.length == 4) { + immAlign = evaluateImmediateOffset(operands[3], compiler); + if (immAlign < 0) { + compiler.currentType = Type.void; return module.unreachable(); } - case BuiltinNames.sqrt: { // sqrt(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.f64, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // TODO: integer versions (that return f64 or convert)? - case TypeKind.F32: return module.unary(UnaryOp.SqrtF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SqrtF64, arg0); - } - } + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "sqrt", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[3].range, "Alignment", "0", naturalAlign.toString() ); + compiler.currentType = Type.void; return module.unreachable(); } - case BuiltinNames.trunc: { // trunc(value: T) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto, Constraints.NONE); - let type = compiler.currentType; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.BOOL: return arg0; // considered truncated - case TypeKind.F32: return module.unary(UnaryOp.TruncF32, arg0); - case TypeKind.F64: return module.unary(UnaryOp.TruncF64, arg0); - } - } + if (!isPowerOf2(immAlign)) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "trunc", type.toString() + DiagnosticCode._0_must_be_a_power_of_two, + operands[3].range, "Alignment" ); + compiler.currentType = Type.void; return module.unreachable(); } + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.void; + return module.store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset, immAlign); +} +builtins.set(BuiltinNames.store, builtin_store); - // === Memory access ========================================================================== - - case BuiltinNames.load: { // load(offset: usize, immOffset?: usize, immAlign?: usize) -> T* - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let outType = ( - contextualType != Type.auto && - type.is(TypeFlags.INTEGER) && - contextualType.is(TypeFlags.INTEGER) && - contextualType.size > type.size - ) ? contextualType : type; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - compiler.currentType = outType; - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - compiler.currentType = outType; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; - } - compiler.currentType = outType; - return module.load( - type.byteSize, - type.is(TypeFlags.SIGNED | TypeFlags.INTEGER), - arg0, - outType.toNativeType(), - immOffset, - immAlign - ); - } - case BuiltinNames.store: { // store(offset: usize, value: T*, offset?: usize, align?: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 2, 4, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] - ); - inType = type; - } - let immOffset = operands.length >= 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.void; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (operands.length == 4) { - immAlign = evaluateImmediateOffset(operands[3], compiler); - if (immAlign < 0) { - compiler.currentType = Type.void; - return module.unreachable(); - } - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[3].range, "Alignment", "0", naturalAlign.toString() - ); - compiler.currentType = Type.void; - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[3].range, "Alignment" - ); - compiler.currentType = Type.void; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; - } - compiler.currentType = Type.void; - return module.store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset, immAlign); - } +// === Atomics ================================================================================ - // === Atomics ================================================================================ - - case BuiltinNames.atomic_load: { // load(offset: usize, immOffset?: usize) -> T* - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 2, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let outType = ( - type.is(TypeFlags.INTEGER) && - contextualType.is(TypeFlags.INTEGER) && - contextualType.size > type.size - ) ? contextualType : type; - if (!type.is(TypeFlags.INTEGER)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.load", type.toString() - ); - compiler.currentType = outType; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let immOffset = operands.length == 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = outType; - return module.unreachable(); - } - compiler.currentType = outType; - return module.atomic_load( - type.byteSize, - arg0, - outType.toNativeType(), - immOffset - ); - } - case BuiltinNames.atomic_store: { // store(offset: usize, value: T*, immOffset?: usize) -> void - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 2, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER)) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.store", type.toString() - ); - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = isAsm - ? compiler.compileExpression( - operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] - ); - inType = type; - } - let immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.void; - return module.unreachable(); - } - compiler.currentType = Type.void; - return module.atomic_store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset); - } - case BuiltinNames.atomic_add: // any_atomic_binary(ptr, value: T, immOffset?: usize) -> T - case BuiltinNames.atomic_sub: - case BuiltinNames.atomic_and: - case BuiltinNames.atomic_or: - case BuiltinNames.atomic_xor: - case BuiltinNames.atomic_xchg: { - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 2, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER) || type.size < 8) { - let opName: string; - switch (prototype.internalName) { - default: assert(false); - case BuiltinNames.atomic_add: { opName = "atomic.add"; break; } - case BuiltinNames.atomic_sub: { opName = "atomic.sub"; break; } - case BuiltinNames.atomic_and: { opName = "atomic.and"; break; } - case BuiltinNames.atomic_or: { opName = "atomic.or"; break; } - case BuiltinNames.atomic_xor: { opName = "atomic.xor"; break; } - case BuiltinNames.atomic_xchg: { opName = "atomic.xchg"; break; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, opName, type.toString() - ); - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], - compiler.options.usizeType, +// atomic.load(offset: usize, immOffset?: usize) -> T* +function builtin_atomic_load(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + var outType = ( + type.is(TypeFlags.INTEGER) && + contextualType.is(TypeFlags.INTEGER) && + contextualType.size > type.size + ) ? contextualType : type; + if (!type.is(TypeFlags.INTEGER)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.load", type.toString() + ); + compiler.currentType = outType; + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var immOffset = operands.length == 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = outType; + return module.unreachable(); + } + compiler.currentType = outType; + return module.atomic_load( + type.byteSize, + arg0, + outType.toNativeType(), + immOffset + ); +} +builtins.set(BuiltinNames.atomic_load, builtin_atomic_load); + +// atomic.store(offset: usize, value: T*, immOffset?: usize) -> void +function builtin_atomic_store(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.store", type.toString() + ); + compiler.currentType = Type.void; + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = ctx.contextIsExact + ? compiler.compileExpression( + operands[1], + contextualType, Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT ); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] - ); - inType = type; - } - let immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = inType; - return module.unreachable(); - } - let op: AtomicRMWOp; - switch (prototype.internalName) { - default: assert(false); - case BuiltinNames.atomic_add: { op = AtomicRMWOp.Add; break; } - case BuiltinNames.atomic_sub: { op = AtomicRMWOp.Sub; break; } - case BuiltinNames.atomic_and: { op = AtomicRMWOp.And; break; } - case BuiltinNames.atomic_or: { op = AtomicRMWOp.Or; break; } - case BuiltinNames.atomic_xor: { op = AtomicRMWOp.Xor; break; } - case BuiltinNames.atomic_xchg: { op = AtomicRMWOp.Xchg; break; } - } - compiler.currentType = inType; - return module.atomic_rmw(op, type.byteSize, immOffset, arg0, arg1, inType.toNativeType()); - } - case BuiltinNames.atomic_cmpxchg: { // cmpxchg(ptr: usize, expected: T, replacement: T, off?: usize) -> T - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 3, 4, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - if (!type.is(TypeFlags.INTEGER) || type.size < 8) { - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.cmpxchg", type.toString() - ); - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], - compiler.options.usizeType, + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.void; + return module.unreachable(); + } + compiler.currentType = Type.void; + return module.atomic_store(type.byteSize, arg0, arg1, inType.toNativeType(), immOffset); +} +builtins.set(BuiltinNames.atomic_store, builtin_atomic_store); + +// any_atomic_binary(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_binary(ctx: BuiltinContext, op: AtomicRMWOp, opName: string): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 2, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER) || type.size < 8) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, opName, type.toString() + ); + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], + compiler.options.usizeType, + Constraints.CONV_IMPLICIT + ); + var arg1 = ctx.contextIsExact + ? compiler.compileExpression(operands[1], + contextualType, Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT ); - let arg1 = isAsm - ? compiler.compileExpression(operands[1], - contextualType, - Constraints.CONV_IMPLICIT - ) - : compiler.compileExpression( - operands[1], - type, - type.is(TypeFlags.INTEGER) - ? Constraints.NONE // no need to convert to small int (but now might result in a float) - : Constraints.CONV_IMPLICIT - ); - let inType = compiler.currentType; - let arg2 = compiler.compileExpression(operands[2], - inType, + var inType = compiler.currentType; + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + inType = type; + } + var immOffset = operands.length == 3 ? evaluateImmediateOffset(operands[2], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = inType; + return module.unreachable(); + } + compiler.currentType = inType; + return module.atomic_rmw(op, type.byteSize, immOffset, arg0, arg1, inType.toNativeType()); +} + +// atomic.add(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_add(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Add, "atomic.add"); +} +builtins.set(BuiltinNames.atomic_add, builtin_atomic_add); + +// atomic.sub(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_sub(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Sub, "atomic.sub"); +} +builtins.set(BuiltinNames.atomic_sub, builtin_atomic_sub); + +// atomic.and(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_and(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.And, "atomic.and"); +} +builtins.set(BuiltinNames.atomic_and, builtin_atomic_and); + +// atomic.or(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_or(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Or, "atomic.or"); +} +builtins.set(BuiltinNames.atomic_or, builtin_atomic_or); + +// atomic.xor(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_xor(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Xor, "atomic.xor"); +} +builtins.set(BuiltinNames.atomic_xor, builtin_atomic_xor); + +// atomic.xchg(ptr, value: T, immOffset?: usize) -> T +function builtin_atomic_xchg(ctx: BuiltinContext): ExpressionRef { + return builtin_atomic_binary(ctx, AtomicRMWOp.Xchg, "atomic.xchg"); +} +builtins.set(BuiltinNames.atomic_xchg, builtin_atomic_xchg); + +// atomic.cmpxchg(ptr: usize, expected: T, replacement: T, off?: usize) -> T +function builtin_atomic_cmpxchg(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 3, 4) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var contextualType = ctx.contextualType; + var type = typeArguments![0]; + if (!type.is(TypeFlags.INTEGER) || type.size < 8) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.cmpxchg", type.toString() + ); + return module.unreachable(); + } + var arg0 = compiler.compileExpression(operands[0], + compiler.options.usizeType, + Constraints.CONV_IMPLICIT + ); + var arg1 = ctx.contextIsExact + ? compiler.compileExpression(operands[1], + contextualType, Constraints.CONV_IMPLICIT + ) + : compiler.compileExpression( + operands[1], + type, + type.is(TypeFlags.INTEGER) + ? Constraints.NONE // no need to convert to small int (but now might result in a float) + : Constraints.CONV_IMPLICIT ); - if ( - type.is(TypeFlags.INTEGER) && - ( - !inType.is(TypeFlags.INTEGER) || // float to int - inType.size < type.size // int to larger int (clear garbage bits) - ) - ) { - arg1 = compiler.convertExpression(arg1, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[1] - ); - arg2 = compiler.convertExpression(arg2, - inType, type, - false, false, // still clears garbage bits when not wrapping - operands[2] - ); - inType = type; + var inType = compiler.currentType; + var arg2 = compiler.compileExpression(operands[2], + inType, + Constraints.CONV_IMPLICIT + ); + if ( + type.is(TypeFlags.INTEGER) && + ( + !inType.is(TypeFlags.INTEGER) || // float to int + inType.size < type.size // int to larger int (clear garbage bits) + ) + ) { + arg1 = compiler.convertExpression(arg1, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[1] + ); + arg2 = compiler.convertExpression(arg2, + inType, type, + false, false, // still clears garbage bits when not wrapping + operands[2] + ); + inType = type; + } + var immOffset = operands.length == 4 ? evaluateImmediateOffset(operands[3], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = inType; + return module.unreachable(); + } + compiler.currentType = inType; + return module.atomic_cmpxchg(type.byteSize, immOffset, arg0, arg1, arg2, inType.toNativeType()); +} +builtins.set(BuiltinNames.atomic_cmpxchg, builtin_atomic_cmpxchg); + +// atomic.wait(ptr: usize, expected: T, timeout: i64) -> i32 +function builtin_atomic_wait(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.i32; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var type = typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.i64, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.i32; + switch (type.kind) { + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: return module.atomic_wait(arg0, arg1, arg2, type.toNativeType()); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "atomic.wait", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.atomic_wait, builtin_atomic_wait); + +// atomic.notify(ptr: usize, count: i32) -> i32 +function builtin_atomic_notify(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.i32; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.i32; + return module.atomic_notify(arg0, arg1); +} +builtins.set(BuiltinNames.atomic_notify, builtin_atomic_notify); + +// atomic.fence() -> void +function builtin_atomic_fence(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkFeatureEnabled(ctx, Feature.THREADS) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + return module.atomic_fence(); +} +builtins.set(BuiltinNames.atomic_fence, builtin_atomic_fence); + +// === Control flow =========================================================================== + +// select(ifTrue: T, ifFalse: T, condition: bool) -> T +function builtin_select(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeOptional(ctx, true) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) + : compiler.compileExpression(operands[0], Type.auto); + var type = compiler.currentType; + if (!type.isAny(TypeFlags.VALUE | TypeFlags.REFERENCE)) { + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "select", type.toString() + ); + return module.unreachable(); + } + var arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); + var arg2 = compiler.makeIsTrueish( + compiler.compileExpression(operands[2], Type.bool), + compiler.currentType // ^ + ); + compiler.currentType = type; + return module.select(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.select, builtin_select); + +// unreachable() -> * +function builtin_unreachable(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + checkArgsRequired(ctx, 0); + return ctx.compiler.module.unreachable(); +} +builtins.set(BuiltinNames.unreachable, builtin_unreachable); + +// === Memory ================================================================================= + +// memory.size() -> i32 +function builtin_memory_size(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.i32; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 0) + ) return module.unreachable(); + return module.host(HostOp.MemorySize); +} +builtins.set(BuiltinNames.memory_size, builtin_memory_size); + +// memory.grow(pages: i32) -> i32 +function builtin_memory_grow(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.i32; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + return module.host(HostOp.MemoryGrow, null, [ + compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT) + ]); +} +builtins.set(BuiltinNames.memory_grow, builtin_memory_grow); + +// memory.copy(dest: usize, src: usize: n: usize) -> void +function builtin_memory_copy(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { + // use stdlib alternative if not supported + let instance = compiler.resolver.resolveFunction(ctx.prototype, null); // reports + compiler.currentType = Type.void; + if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); + return compiler.compileCallDirect(instance, operands, ctx.reportNode); + } + var usizeType = compiler.options.usizeType; + var arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], usizeType, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.void; + return module.memory_copy(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.memory_copy, builtin_memory_copy); + +// memory.fill(dest: usize, value: u8, n: usize) -> void +function builtin_memory_fill(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + compiler.currentType = Type.void; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) return module.unreachable(); + var operands = ctx.operands; + if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { + // use stdlib alternative if not supported + let instance = compiler.resolver.resolveFunction(ctx.prototype, null); // reports + compiler.currentType = Type.void; + if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); + return compiler.compileCallDirect(instance, operands, ctx.reportNode); + } + var usizeType = compiler.options.usizeType; + var arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.void; + return module.memory_fill(arg0, arg1, arg2); +} +builtins.set(BuiltinNames.memory_fill, builtin_memory_fill); + +// === Helpers ================================================================================ + +// changetype(value: *) -> T +function builtin_changetype(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var toType = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.auto); + var fromType = compiler.currentType; + compiler.currentType = toType; + if (!fromType.isChangeableTo(toType)) { + compiler.error( + DiagnosticCode.Type_0_cannot_be_changed_to_type_1, + ctx.reportNode.range, fromType.toString(), toType.toString() + ); + return module.unreachable(); + } + return arg0; +} +builtins.set(BuiltinNames.changetype, builtin_changetype); + +// assert(isTrueish: T, message?: string) -> T{!= null} +function builtin_assert(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + var typeArguments = ctx.typeArguments; + if ( + checkTypeOptional(ctx, true) | + checkArgsOptional(ctx, 1, 2) + ) { + if (typeArguments) { + assert(typeArguments.length); // otherwise invalid, should not been set at all + compiler.currentType = typeArguments[0].nonNullableType; + } + return module.unreachable(); + } + var operands = ctx.operands; + var contextualType = ctx.contextualType; + var arg0 = typeArguments + ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) + : compiler.compileExpression(operands[0], Type.bool, Constraints.MUST_WRAP); + var type = compiler.currentType; + compiler.currentType = type.nonNullableType; + + // if the assertion can be proven statically, omit it + if (getExpressionId(arg0 = module.precomputeExpression(arg0)) == ExpressionId.Const) { + switch (getExpressionType(arg0)) { + case NativeType.I32: { + if (getConstValueI32(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; + } + break; } - let immOffset = operands.length == 4 ? evaluateImmediateOffset(operands[3], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = inType; - return module.unreachable(); + case NativeType.I64: { + if (getConstValueI64Low(arg0) != 0 || getConstValueI64High(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; + } + break; } - compiler.currentType = inType; - return module.atomic_cmpxchg(type.byteSize, immOffset, arg0, arg1, arg2, inType.toNativeType()); - } - case BuiltinNames.atomic_wait: { // wait(ptr: usize, expected: T, timeout: i64) -> i32 - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); + case NativeType.F32: { + if (getConstValueF32(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.i64, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.i32; - switch (type.kind) { - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: return module.atomic_wait(arg0, arg1, arg2, type.toNativeType()); + case NativeType.F64: { + if (getConstValueF64(arg0) != 0) { + if (contextualType == Type.void) { + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; + } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "atomic.wait", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.atomic_notify: { // notify(ptr: usize, count: i32) -> i32 - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); + } + + // return ifTrueish if assertions are disabled + if (compiler.options.noAssert) { + if (contextualType == Type.void) { // simplify if dropped anyway + compiler.currentType = Type.void; + return module.nop(); + } + return arg0; + } + + // otherwise call abort if the assertion is false-ish + var abort = compiler.makeAbort(operands.length == 2 ? operands[1] : null, ctx.reportNode); + compiler.currentType = type.nonNullableType; + if (contextualType == Type.void) { // simplify if dropped anyway + compiler.currentType = Type.void; + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: return module.if(module.unary(UnaryOp.EqzI32, arg0), abort); + case TypeKind.I64: + case TypeKind.U64: return module.if(module.unary(UnaryOp.EqzI64, arg0), abort); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.if( + module.unary( + compiler.options.isWasm64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + arg0 + ), + abort + ); } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.i32; - return module.atomic_notify(arg0, arg1); + // TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`? + case TypeKind.F32: return module.if(module.binary(BinaryOp.EqF32, arg0, module.f32(0)), abort); + case TypeKind.F64: return module.if(module.binary(BinaryOp.EqF64, arg0, module.f64(0)), abort); } - case BuiltinNames.atomic_fence: { // fence() -> void - compiler.currentType = Type.void; - if ( - checkFeatureEnabled(Feature.THREADS, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - return module.atomic_fence(); + } else { + compiler.currentType = type.nonNullableType; + let flow = compiler.currentFlow; + switch (compiler.currentType.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.BOOL: { + let temp = flow.getTempLocal(type); + flow.setLocalFlag(temp.index, LocalFlags.WRAPPED); // arg0 is wrapped + let ret = module.if( + module.local_tee(temp.index, arg0), + module.local_get(temp.index, NativeType.I32), + abort + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.I64: + case TypeKind.U64: { + let temp = flow.getTempLocal(Type.i64); + let ret = module.if( + module.unary(UnaryOp.EqzI64, + module.local_tee(temp.index, arg0) + ), + abort, + module.local_get(temp.index, NativeType.I64) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.ISIZE: + case TypeKind.USIZE: { + let temp = flow.getTempLocal(compiler.options.usizeType); + let ret = module.if( + module.unary( + compiler.options.isWasm64 + ? UnaryOp.EqzI64 + : UnaryOp.EqzI32, + module.local_tee(temp.index, arg0) + ), + abort, + module.local_get(temp.index, compiler.options.nativeSizeType) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F32: { + let temp = flow.getTempLocal(Type.f32); + let ret = module.if( + module.binary(BinaryOp.EqF32, + module.local_tee(temp.index, arg0), + module.f32(0) + ), + abort, + module.local_get(temp.index, NativeType.F32) + ); + flow.freeTempLocal(temp); + return ret; + } + case TypeKind.F64: { + let temp = flow.getTempLocal(Type.f64); + let ret = module.if( + module.binary(BinaryOp.EqF64, + module.local_tee(temp.index, arg0), + module.f64(0) + ), + abort, + module.local_get(temp.index, NativeType.F64) + ); + flow.freeTempLocal(temp); + return ret; + } } + } + compiler.error( + DiagnosticCode.Not_implemented, + ctx.reportNode.typeArgumentsRange + ); + return abort; +} +builtins.set(BuiltinNames.assert, builtin_assert); + +// unchecked(expr: *) -> * +function builtin_unchecked(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) return module.unreachable(); + var flow = compiler.currentFlow; + var alreadyUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); + flow.set(FlowFlags.UNCHECKED_CONTEXT); + // eliminate unnecessary tees by preferring contextualType(=void) + var expr = compiler.compileExpression(ctx.operands[0], ctx.contextualType); + if (!alreadyUnchecked) flow.unset(FlowFlags.UNCHECKED_CONTEXT); + return expr; +} +builtins.set(BuiltinNames.unchecked, builtin_unchecked); + +// instantiate(...args: *[]) -> T +function builtin_instantiate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeRequired(ctx, true) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var typeArgument = typeArguments[0]; + var classInstance = typeArgument.classReference; + if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { + compiler.error( + DiagnosticCode.This_expression_is_not_constructable, + ctx.reportNode.expression.range + ); + return module.unreachable(); + } + compiler.currentType = classInstance.type; + return compiler.compileInstantiate(classInstance, operands, Constraints.NONE, ctx.reportNode); +} +builtins.set(BuiltinNames.instantiate, builtin_instantiate); + +// === User-defined diagnostics =============================================================== + +function builtin_diagnostic(ctx: BuiltinContext, category: DiagnosticCategory): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + checkTypeAbsent(ctx); + var operands = ctx.operands; + var reportNode = ctx.reportNode; + compiler.emitDiagnostic( + DiagnosticCode.User_defined_0, + category, + reportNode.range, + null, + operands.length + ? operands[0].range.toString() + : reportNode.range.toString() + ); + return category == DiagnosticCategory.ERROR + ? module.unreachable() + : module.nop(); +} + +// ERROR(message?) +function builtin_error(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.ERROR); +} +builtins.set(BuiltinNames.ERROR, builtin_error); + +// WARNING(message?) +function builtin_warning(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.WARNING); +} +builtins.set(BuiltinNames.WARNING, builtin_warning); + +// INFO(message?) +function builtin_info(ctx: BuiltinContext): ExpressionRef { + return builtin_diagnostic(ctx, DiagnosticCategory.INFO); +} +builtins.set(BuiltinNames.INFO, builtin_info); + +// === Portable type conversions ============================================================== + +function builtin_conversion(ctx: BuiltinContext, toType: Type): ExpressionRef { + var compiler = ctx.compiler; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = toType; + return compiler.module.unreachable(); + } + return compiler.compileExpression(ctx.operands[0], toType, Constraints.CONV_EXPLICIT); +} + +// i8(*) -> i8 +function builtin_i8(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i8); +} +builtins.set(BuiltinNames.i8, builtin_i8); + +// i16(*) -> i16 +function builtin_i16(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i16); +} +builtins.set(BuiltinNames.i16, builtin_i16); + +// i32(*) -> i32 +function builtin_i32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i32); +} +builtins.set(BuiltinNames.i32, builtin_i32); + +// i64(*) -> i64 +function builtin_i64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.i64); +} +builtins.set(BuiltinNames.i64, builtin_i64); + +// isize(*) -> isize +function builtin_isize(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, ctx.compiler.options.isizeType); +} +builtins.set(BuiltinNames.isize, builtin_isize); + +// u8(*) -> u8 +function builtin_u8(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u8); +} +builtins.set(BuiltinNames.u8, builtin_u8); + +// u16(*) -> u16 +function builtin_u16(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u16); +} +builtins.set(BuiltinNames.u16, builtin_u16); + +// u32(*) -> u32 +function builtin_u32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u32); +} +builtins.set(BuiltinNames.u32, builtin_u32); + +// u64(*) -> u64 +function builtin_u64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.u64); +} +builtins.set(BuiltinNames.u64, builtin_u64); + +// usize(*) -> usize +function builtin_usize(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, ctx.compiler.options.usizeType); +} +builtins.set(BuiltinNames.usize, builtin_usize); + +// bool(*) -> bool +function builtin_bool(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.bool); +} +builtins.set(BuiltinNames.bool, builtin_bool); + +// f32(*) -> f32 +function builtin_f32(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.f32); +} +builtins.set(BuiltinNames.f32, builtin_f32); + +// f64(*) -> f64 +function builtin_f64(ctx: BuiltinContext): ExpressionRef { + return builtin_conversion(ctx, Type.f64); +} +builtins.set(BuiltinNames.f64, builtin_f64); + +// TODO: alias for now, splat input integer perhaps? +function builtin_v128(ctx: BuiltinContext): ExpressionRef { + return builtin_i8x16(ctx); +} +builtins.set(BuiltinNames.v128, builtin_v128); + +// === SIMD =================================================================================== - // === Control flow =========================================================================== - - case BuiltinNames.select: { // select(ifTrue: T, ifFalse: T, condition: bool) -> T - if ( - checkTypeOptional(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - if (!type.isAny(TypeFlags.VALUE | TypeFlags.REFERENCE)) { +// i8x16(...values: i8[16]) -> v128 +function builtin_i8x16(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 16) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 16; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i8, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "select", type.toString() + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range ); + compiler.currentType = Type.v128; return module.unreachable(); } - let arg1 = compiler.compileExpression(operands[1], type, Constraints.CONV_IMPLICIT); - let arg2 = compiler.makeIsTrueish( - compiler.compileExpression(operands[2], Type.bool), - compiler.currentType // ^ - ); - compiler.currentType = type; - return module.select(arg0, arg1, arg2); + assert(getExpressionType(expr) == NativeType.I32); + writeI8(getConstValueI32(expr), bytes, i); } - case BuiltinNames.unreachable: { // unreachable() -> * - if (typeArguments) { + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i8x16, builtin_i8x16); + +// i16x8(...values: i16[8]) -> v128 +function builtin_i16x8(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 8) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 8; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i16, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { compiler.error( - DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range ); + compiler.currentType = Type.v128; + return module.unreachable(); } - checkArgsRequired(operands, 0, reportNode, compiler); - return module.unreachable(); + assert(getExpressionType(expr) == NativeType.I32); + writeI16(getConstValueI32(expr), bytes, i << 1); } + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i16x8, builtin_i16x8); - // === Memory ================================================================================= - - case BuiltinNames.memory_size: { // memory.size() -> i32 - compiler.currentType = Type.i32; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 0, reportNode, compiler) - ) return module.unreachable(); - return module.host(HostOp.MemorySize); - } - case BuiltinNames.memory_grow: { // memory.grow(pages: i32) -> i32 - compiler.currentType = Type.i32; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - return module.host(HostOp.MemoryGrow, null, [ - compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_IMPLICIT) - ]); - } - case BuiltinNames.memory_copy: { // memory.copy(dest: usize, src: usize: n: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { - // use stdlib alternative if not supported - let instance = compiler.resolver.resolveFunction(prototype, null); // reports - compiler.currentType = Type.void; - if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); - return compiler.compileCallDirect(instance, operands, reportNode); +// i32x4(...values: i32[4]) -> v128 +function builtin_i32x4(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 4) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i32, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.unreachable(); } - let usizeType = compiler.options.usizeType; - let arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], usizeType, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.void; - return module.memory_copy(arg0, arg1, arg2); + assert(getExpressionType(expr) == NativeType.I32); + writeI32(getConstValueI32(expr), bytes, i << 2); } - case BuiltinNames.memory_fill: { // memory.fill(dest: usize, value: u8, n: usize) -> void - compiler.currentType = Type.void; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) return module.unreachable(); - if (!compiler.options.hasFeature(Feature.BULK_MEMORY)) { - // use stdlib alternative if not supported - let instance = compiler.resolver.resolveFunction(prototype, null); // reports - compiler.currentType = Type.void; - if (!instance || !compiler.compileFunction(instance, true)) return module.unreachable(); - return compiler.compileCallDirect(instance, operands, reportNode); + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i32x4, builtin_i32x4); + +// i64x2(...values: i64[2]) -> v128 +function builtin_i64x2(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.i64, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; + return module.unreachable(); } - let usizeType = compiler.options.usizeType; - let arg0 = compiler.compileExpression(operands[0], usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], usizeType, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.void; - return module.memory_fill(arg0, arg1, arg2); + assert(getExpressionType(expr) == NativeType.I64); + let off = i << 3; + writeI32(getConstValueI64Low(expr), bytes, off); + writeI32(getConstValueI64High(expr), bytes, off + 4); } + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.i64x2, builtin_i64x2); - // === Helpers ================================================================================ - - case BuiltinNames.changetype: { // changetype(value: *) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let toType = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.auto); - let fromType = compiler.currentType; - compiler.currentType = toType; - if (!fromType.isChangeableTo(toType)) { +// f32x4(...values: f32[4]) -> v128 +function builtin_f32x4(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 4) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 4; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.f32, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { compiler.error( - DiagnosticCode.Type_0_cannot_be_changed_to_type_1, - reportNode.range, fromType.toString(), toType.toString() + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range ); + compiler.currentType = Type.v128; return module.unreachable(); } - return arg0; + assert(getExpressionType(expr) == NativeType.F32); + writeF32(getConstValueF32(expr), bytes, i << 2); } - case BuiltinNames.assert: { // assert(isTrueish: T, message?: string) -> T{!= null} - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsOptional(operands, 1, 2, reportNode, compiler) - ) { - if (typeArguments) { - assert(typeArguments.length); // otherwise invalid, should not been set at all - compiler.currentType = typeArguments[0].nonNullableType; - } + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.f32x4, builtin_f32x4); + +// f64x2(...values: f64[2]) -> v128 +function builtin_f64x2(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var bytes = new Uint8Array(16); + for (let i = 0; i < 2; ++i) { + let value = operands[i]; + if (value) { + let expr = compiler.precomputeExpression(value, Type.f64, Constraints.CONV_IMPLICIT); + if (getExpressionId(expr) != ExpressionId.Const) { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + value.range + ); + compiler.currentType = Type.v128; return module.unreachable(); } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT | Constraints.MUST_WRAP) - : compiler.compileExpression(operands[0], Type.bool, Constraints.MUST_WRAP); - let type = compiler.currentType; - compiler.currentType = type.nonNullableType; - - // if the assertion can be proven statically, omit it - if (getExpressionId(arg0 = module.precomputeExpression(arg0)) == ExpressionId.Const) { - switch (getExpressionType(arg0)) { - case NativeType.I32: { - if (getConstValueI32(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.I64: { - if (getConstValueI64Low(arg0) != 0 || getConstValueI64High(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.F32: { - if (getConstValueF32(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - case NativeType.F64: { - if (getConstValueF64(arg0) != 0) { - if (contextualType == Type.void) { - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; - } - break; - } - } - } + assert(getExpressionType(expr) == NativeType.F64); + writeF64(getConstValueF64(expr), bytes, i << 3); + } + } + compiler.currentType = Type.v128; + return module.v128(bytes); +} +builtins.set(BuiltinNames.f64x2, builtin_f64x2); - // return ifTrueish if assertions are disabled - if (compiler.options.noAssert) { - if (contextualType == Type.void) { // simplify if dropped anyway - compiler.currentType = Type.void; - return module.nop(); - } - return arg0; +// v128.splat(x: T) -> v128 +function builtin_v128_splat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], type, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.SplatI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.SplatI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.SplatI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.SplatI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.SplatI64x2 + : UnaryOp.SplatI32x4, + arg0 + ); } + case TypeKind.F32: return module.unary(UnaryOp.SplatF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SplatF64x2, arg0); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.splat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_splat, builtin_v128_splat); - // otherwise call abort if the assertion is false-ish - let abort = compiler.makeAbort(operands.length == 2 ? operands[1] : null, reportNode); - compiler.currentType = type.nonNullableType; - if (contextualType == Type.void) { // simplify if dropped anyway - compiler.currentType = Type.void; - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: return module.if(module.unary(UnaryOp.EqzI32, arg0), abort); - case TypeKind.I64: - case TypeKind.U64: return module.if(module.unary(UnaryOp.EqzI64, arg0), abort); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.if( - module.unary( - compiler.options.isWasm64 - ? UnaryOp.EqzI64 - : UnaryOp.EqzI32, - arg0 - ), - abort - ); - } - // TODO: also check for NaN in float assertions, as in `Boolean(NaN) -> false`? - case TypeKind.F32: return module.if(module.binary(BinaryOp.EqF32, arg0, module.f32(0)), abort); - case TypeKind.F64: return module.if(module.binary(BinaryOp.EqF64, arg0, module.f64(0)), abort); - } - } else { - compiler.currentType = type.nonNullableType; - let flow = compiler.currentFlow; - switch (compiler.currentType.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.BOOL: { - let temp = flow.getTempLocal(type); - flow.setLocalFlag(temp.index, LocalFlags.WRAPPED); // arg0 is wrapped - let ret = module.if( - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.I32), - abort - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.I64: - case TypeKind.U64: { - let temp = flow.getTempLocal(Type.i64); - let ret = module.if( - module.unary(UnaryOp.EqzI64, - module.local_tee(temp.index, arg0) - ), - abort, - module.local_get(temp.index, NativeType.I64) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - let temp = flow.getTempLocal(compiler.options.usizeType); - let ret = module.if( - module.unary( - compiler.options.isWasm64 - ? UnaryOp.EqzI64 - : UnaryOp.EqzI32, - module.local_tee(temp.index, arg0) - ), - abort, - module.local_get(temp.index, compiler.options.nativeSizeType) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F32: { - let temp = flow.getTempLocal(Type.f32); - let ret = module.if( - module.binary(BinaryOp.EqF32, - module.local_tee(temp.index, arg0), - module.f32(0) - ), - abort, - module.local_get(temp.index, NativeType.F32) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - let temp = flow.getTempLocal(Type.f64); - let ret = module.if( - module.binary(BinaryOp.EqF64, - module.local_tee(temp.index, arg0), - module.f64(0) - ), - abort, - module.local_get(temp.index, NativeType.F64) - ); - flow.freeTempLocal(temp); - return ret; - } - } - } +// v128.extract_lane(x: v128, idx: u8) -> T +function builtin_v128_extract_lane(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsRequired(ctx, 2) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + compiler.currentType = type; + var idx = 0; + if (getExpressionId(arg1) == ExpressionId.Const) { + assert(getExpressionType(arg1) == NativeType.I32); + idx = getConstValueI32(arg1); + } else { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + } + if (!type.is(TypeFlags.REFERENCE)) { + let maxIdx = (16 / assert(type.byteSize)) - 1; + if (idx < 0 || idx > maxIdx) { compiler.error( - DiagnosticCode.Not_implemented, - reportNode.typeArgumentsRange + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() ); - return abort; - } - case BuiltinNames.unchecked: { // unchecked(expr: *) -> * - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) return module.unreachable(); - let flow = compiler.currentFlow; - let alreadyUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT); - flow.set(FlowFlags.UNCHECKED_CONTEXT); - // eliminate unnecessary tees by preferring contextualType(=void) - let expr = compiler.compileExpression(operands[0], contextualType); - if (!alreadyUnchecked) flow.unset(FlowFlags.UNCHECKED_CONTEXT); - return expr; - } - case BuiltinNames.instantiate: { // instantiate(...args: *[]) -> T - if ( - checkTypeRequired(typeArguments, reportNode, compiler, true) - ) return module.unreachable(); - let typeArgument = typeArguments![0]; - let classInstance = typeArgument.classReference; - if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) { - compiler.error( - DiagnosticCode.This_expression_is_not_constructable, - reportNode.expression.range + idx = 0; + } + switch (type.kind) { + case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); + case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); + case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); + case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); + case TypeKind.I32: + case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); + case TypeKind.I64: + case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_extract( + compiler.options.isWasm64 + ? SIMDExtractOp.ExtractLaneI64x2 + : SIMDExtractOp.ExtractLaneI32x4, + arg0, idx ); - return module.unreachable(); } - compiler.currentType = classInstance.type; - return compiler.compileInstantiate(classInstance, operands, Constraints.NONE, reportNode); + case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); + case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.extract_lane", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_extract_lane, builtin_v128_extract_lane); - // === User-defined diagnostics =============================================================== - - case BuiltinNames.ERROR: { - checkTypeAbsent(typeArguments, reportNode, prototype); +// v128.replace_lane(x: v128, idx: u8, value: T) -> v128 +function builtin_v128_replace_lane(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], type, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + var idx = 0; + if (getExpressionId(arg1) == ExpressionId.Const) { + assert(getExpressionType(arg1) == NativeType.I32); + idx = getConstValueI32(arg1); + } else { + compiler.error( + DiagnosticCode.Expression_must_be_a_compile_time_constant, + operands[1].range + ); + } + if (!type.is(TypeFlags.REFERENCE)) { + let maxIdx = (16 / assert(type.byteSize)) - 1; + if (idx < 0 || idx > maxIdx) { compiler.error( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() - ); - return module.unreachable(); - } - case BuiltinNames.WARNING: { - checkTypeAbsent(typeArguments, reportNode, prototype); - compiler.warning( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() - ); - return module.nop(); - } - case BuiltinNames.INFO: { - checkTypeAbsent(typeArguments, reportNode, prototype); - compiler.info( - DiagnosticCode.User_defined_0, - reportNode.range, (operands.length ? operands[0] : reportNode).range.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[1].range, "Lane index", "0", maxIdx.toString() ); - return module.nop(); - } - - // === Portable type conversions ============================================================== - - case BuiltinNames.i8: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i8; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i8, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i16: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i16; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i16, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i32; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.i64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.i64; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.i64, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.isize: { - let isizeType = compiler.options.isizeType; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = isizeType; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], isizeType, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u8: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u8; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u8, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u16: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u16; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u16, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u32; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.u64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.u64; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.u64, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.usize: { - let usizeType = compiler.options.usizeType; - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = usizeType; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], usizeType, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.bool: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.bool, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.f32: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.f32; - return module.unreachable(); - } - return compiler.compileExpression(operands[0], Type.f32, Constraints.CONV_EXPLICIT); - } - case BuiltinNames.f64: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.f64; - return module.unreachable(); + idx = 0; + } + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); + case TypeKind.I16: + case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); + case TypeKind.I32: + case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); + case TypeKind.I64: + case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_replace( + compiler.options.isWasm64 + ? SIMDReplaceOp.ReplaceLaneI64x2 + : SIMDReplaceOp.ReplaceLaneI32x4, + arg0, idx, arg2 + ); } - return compiler.compileExpression(operands[0], Type.f64, Constraints.CONV_EXPLICIT); + case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); + case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.replace_lane", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_replace_lane, builtin_v128_replace_lane); - // === SIMD =================================================================================== - - case BuiltinNames.v128: // alias for now - case BuiltinNames.i8x16: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 16, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let bytes = new Uint8Array(16); - for (let i = 0; i < 16; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i8, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.I32); - writeI8(getConstValueI32(expr), bytes, i); - } - } +// v128.shuffle(a: v128, b: v128, ...lanes: u8[]) -> v128 +function builtin_v128_shuffle(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + if (!type.is(TypeFlags.REFERENCE)) { + let laneWidth = type.byteSize; + let laneCount = 16 / laneWidth; + assert(isInteger(laneCount) && isPowerOf2(laneCount)); + if ( + checkArgsRequired(ctx, 2 + laneCount) + ) { compiler.currentType = Type.v128; - return module.v128(bytes); + return module.unreachable(); } - case BuiltinNames.i16x8: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 8, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let bytes = new Uint8Array(16); - for (let i = 0; i < 8; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i16, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { + let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + switch (type.kind) { + case TypeKind.I8: + case TypeKind.I16: + case TypeKind.I32: + case TypeKind.I64: + case TypeKind.ISIZE: + case TypeKind.U8: + case TypeKind.U16: + case TypeKind.U32: + case TypeKind.U64: + case TypeKind.USIZE: + case TypeKind.F32: + case TypeKind.F64: { + let mask = new Uint8Array(16); + let maxIdx = (laneCount << 1) - 1; + for (let i = 0; i < laneCount; ++i) { + let operand = operands[2 + i]; + let argN = compiler.precomputeExpression(operand, Type.u8, Constraints.CONV_IMPLICIT); + if (getExpressionId(argN) != ExpressionId.Const) { compiler.error( DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range + operand.range ); compiler.currentType = Type.v128; return module.unreachable(); } - assert(getExpressionType(expr) == NativeType.I32); - writeI16(getConstValueI32(expr), bytes, i << 1); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); - } - case BuiltinNames.i32x4: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 4, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let bytes = new Uint8Array(16); - for (let i = 0; i < 4; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i32, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { + assert(getExpressionType(argN) == NativeType.I32); + let idx = getConstValueI32(argN); + if (idx < 0 || idx > maxIdx) { compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operand.range, "Lane index", "0", maxIdx.toString() ); compiler.currentType = Type.v128; return module.unreachable(); } - assert(getExpressionType(expr) == NativeType.I32); - writeI32(getConstValueI32(expr), bytes, i << 2); - } - } - compiler.currentType = Type.v128; - return module.v128(bytes); - } - case BuiltinNames.i64x2: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let bytes = new Uint8Array(16); - for (let i = 0; i < 2; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.i64, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); + switch (laneWidth) { + case 1: { + writeI8(idx, mask, i); + break; + } + case 2: { + let off8 = i << 1; + let idx8 = idx << 1; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + break; + } + case 4: { + let off8 = i << 2; + let idx8 = idx << 2; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + break; + } + case 8: { + let off8 = i << 3; + let idx8 = idx << 3; + writeI8(idx8 , mask, off8); + writeI8(idx8 + 1, mask, off8 + 1); + writeI8(idx8 + 2, mask, off8 + 2); + writeI8(idx8 + 3, mask, off8 + 3); + writeI8(idx8 + 4, mask, off8 + 4); + writeI8(idx8 + 5, mask, off8 + 5); + writeI8(idx8 + 6, mask, off8 + 6); + writeI8(idx8 + 7, mask, off8 + 7); + break; + } + default: assert(false); } - assert(getExpressionType(expr) == NativeType.I64); - let off = i << 3; - writeI32(getConstValueI64Low(expr), bytes, off); - writeI32(getConstValueI64High(expr), bytes, off + 4); } + compiler.currentType = Type.v128; + return module.simd_shuffle(arg0, arg1, mask); } + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shuffle", type.toString() + ); + compiler.currentType = Type.v128; + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_shuffle, builtin_v128_shuffle); + +// v128.swizzle(a: v128, b: v128) -> v128 +function builtin_v128_swizzle(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + return module.binary(BinaryOp.SwizzleV8x16, arg0, arg1); +} +builtins.set(BuiltinNames.v128_swizzle, builtin_v128_swizzle); + +// v128.load_splat(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 +function builtin_v128_load_splat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { compiler.currentType = Type.v128; - return module.v128(bytes); + return module.unreachable(); } - case BuiltinNames.f32x4: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 4, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + if (immAlign > naturalAlign) { + compiler.error( + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() + ); + return module.unreachable(); + } + if (!isPowerOf2(immAlign)) { + compiler.error( + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" + ); + return module.unreachable(); + } + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: { + return module.simd_load(SIMDLoadOp.LoadSplatV8x16, arg0, immOffset, immAlign); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 4; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.f32, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.F32); - writeF32(getConstValueF32(expr), bytes, i << 2); - } + case TypeKind.I16: + case TypeKind.U16: { + return module.simd_load(SIMDLoadOp.LoadSplatV16x8, arg0, immOffset, immAlign); } - compiler.currentType = Type.v128; - return module.v128(bytes); - } - case BuiltinNames.f64x2: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + case TypeKind.I32: + case TypeKind.U32: + case TypeKind.F32: { + return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); } - let bytes = new Uint8Array(16); - for (let i = 0; i < 2; ++i) { - let value = operands[i]; - if (value) { - let expr = compiler.precomputeExpression(value, Type.f64, Constraints.CONV_IMPLICIT); - if (getExpressionId(expr) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - value.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(expr) == NativeType.F64); - writeF64(getConstValueF64(expr), bytes, i << 3); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); } + // fall-through } - compiler.currentType = Type.v128; - return module.v128(bytes); - } - case BuiltinNames.v128_splat: { // splat(x: T) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + case TypeKind.I64: + case TypeKind.U64: + case TypeKind.F64: { + return module.simd_load(SIMDLoadOp.LoadSplatV64x2, arg0, immOffset, immAlign); } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], type, Constraints.CONV_IMPLICIT); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.load_splat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_load_splat, builtin_v128_load_splat); + +// v128.load_ext(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 +function builtin_v128_load_ext(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx, true) | + checkArgsOptional(ctx, 1, 3) + ) return module.unreachable(); + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var numOperands = operands.length; + var immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports + if (immOffset < 0) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var immAlign: i32; + var naturalAlign = type.byteSize; + if (numOperands == 3) { + immAlign = evaluateImmediateOffset(operands[2], compiler); + if (immAlign < 0) { compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.SplatI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.SplatI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.SplatI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.SplatI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.SplatI64x2 - : UnaryOp.SplatI32x4, - arg0 - ); - } - case TypeKind.F32: return module.unary(UnaryOp.SplatF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SplatF64x2, arg0); - } - } + return module.unreachable(); + } + } else { + immAlign = naturalAlign; + } + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + if (immAlign > naturalAlign) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.splat", type.toString() + DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, + operands[2].range, "Alignment", "0", naturalAlign.toString() ); return module.unreachable(); } - case BuiltinNames.v128_extract_lane: { // extract_lane(x: v128, idx: u8) -> T - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - compiler.currentType = type; - let idx = 0; - if (getExpressionId(arg1) == ExpressionId.Const) { - assert(getExpressionType(arg1) == NativeType.I32); - idx = getConstValueI32(arg1); - } else { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operands[1].range - ); - } - if (!type.is(TypeFlags.REFERENCE)) { - let maxIdx = (16 / assert(type.byteSize)) - 1; - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[1].range, "Lane index", "0", maxIdx.toString() - ); - idx = 0; - } - switch (type.kind) { - case TypeKind.I8: return module.simd_extract(SIMDExtractOp.ExtractLaneI8x16, arg0, idx); - case TypeKind.U8: return module.simd_extract(SIMDExtractOp.ExtractLaneU8x16, arg0, idx); - case TypeKind.I16: return module.simd_extract(SIMDExtractOp.ExtractLaneI16x8, arg0, idx); - case TypeKind.U16: return module.simd_extract(SIMDExtractOp.ExtractLaneU16x8, arg0, idx); - case TypeKind.I32: - case TypeKind.U32: return module.simd_extract(SIMDExtractOp.ExtractLaneI32x4, arg0, idx); - case TypeKind.I64: - case TypeKind.U64: return module.simd_extract(SIMDExtractOp.ExtractLaneI64x2, arg0, idx); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_extract( - compiler.options.isWasm64 - ? SIMDExtractOp.ExtractLaneI64x2 - : SIMDExtractOp.ExtractLaneI32x4, - arg0, idx - ); - } - case TypeKind.F32: return module.simd_extract(SIMDExtractOp.ExtractLaneF32x4, arg0, idx); - case TypeKind.F64: return module.simd_extract(SIMDExtractOp.ExtractLaneF64x2, arg0, idx); - } - } + if (!isPowerOf2(immAlign)) { compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.extract_lane", type.toString() + DiagnosticCode._0_must_be_a_power_of_two, + operands[2].range, "Alignment" ); return module.unreachable(); } - case BuiltinNames.v128_replace_lane: { // replace_lane(x: v128, idx: u8, value: T) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + switch (type.kind) { + case TypeKind.I8: return module.simd_load(SIMDLoadOp.LoadI8ToI16x8, arg0, immOffset, immAlign); + case TypeKind.U8: return module.simd_load(SIMDLoadOp.LoadU8ToU16x8, arg0, immOffset, immAlign); + case TypeKind.I16: return module.simd_load(SIMDLoadOp.LoadI16ToI32x4, arg0, immOffset, immAlign); + case TypeKind.U16: return module.simd_load(SIMDLoadOp.LoadU16ToU32x4, arg0, immOffset, immAlign); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.precomputeExpression(operands[1], Type.u8, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], type, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - let idx = 0; - if (getExpressionId(arg1) == ExpressionId.Const) { - assert(getExpressionType(arg1) == NativeType.I32); - idx = getConstValueI32(arg1); - } else { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operands[1].range - ); - } - if (!type.is(TypeFlags.REFERENCE)) { - let maxIdx = (16 / assert(type.byteSize)) - 1; - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[1].range, "Lane index", "0", maxIdx.toString() - ); - idx = 0; - } - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI8x16, arg0, idx, arg2); - case TypeKind.I16: - case TypeKind.U16: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI16x8, arg0, idx, arg2); - case TypeKind.I32: - case TypeKind.U32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI32x4, arg0, idx, arg2); - case TypeKind.I64: - case TypeKind.U64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneI64x2, arg0, idx, arg2); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_replace( - compiler.options.isWasm64 - ? SIMDReplaceOp.ReplaceLaneI64x2 - : SIMDReplaceOp.ReplaceLaneI32x4, - arg0, idx, arg2 - ); - } - case TypeKind.F32: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF32x4, arg0, idx, arg2); - case TypeKind.F64: return module.simd_replace(SIMDReplaceOp.ReplaceLaneF64x2, arg0, idx, arg2); - } + case TypeKind.I32: return module.simd_load(SIMDLoadOp.LoadI32ToI64x2, arg0, immOffset, immAlign); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.replace_lane", type.toString() - ); - return module.unreachable(); + case TypeKind.U32: return module.simd_load(SIMDLoadOp.LoadU32ToU64x2, arg0, immOffset, immAlign); } - case BuiltinNames.v128_shuffle: { // shuffle(a: v128, b: v128, ...lanes: u8[]) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - if (!type.is(TypeFlags.REFERENCE)) { - let laneWidth = type.byteSize; - let laneCount = 16 / laneWidth; - assert(isInteger(laneCount) && isPowerOf2(laneCount)); - if ( - checkArgsRequired(operands, 2 + laneCount, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - switch (type.kind) { - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: - case TypeKind.F32: - case TypeKind.F64: { - let mask = new Uint8Array(16); - let maxIdx = (laneCount << 1) - 1; - for (let i = 0; i < laneCount; ++i) { - let operand = operands[2 + i]; - let argN = compiler.precomputeExpression(operand, Type.u8, Constraints.CONV_IMPLICIT); - if (getExpressionId(argN) != ExpressionId.Const) { - compiler.error( - DiagnosticCode.Expression_must_be_a_compile_time_constant, - operand.range - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - assert(getExpressionType(argN) == NativeType.I32); - let idx = getConstValueI32(argN); - if (idx < 0 || idx > maxIdx) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operand.range, "Lane index", "0", maxIdx.toString() - ); - compiler.currentType = Type.v128; - return module.unreachable(); - } - switch (laneWidth) { - case 1: { - writeI8(idx, mask, i); - break; - } - case 2: { - let off8 = i << 1; - let idx8 = idx << 1; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - break; - } - case 4: { - let off8 = i << 2; - let idx8 = idx << 2; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - writeI8(idx8 + 2, mask, off8 + 2); - writeI8(idx8 + 3, mask, off8 + 3); - break; - } - case 8: { - let off8 = i << 3; - let idx8 = idx << 3; - writeI8(idx8 , mask, off8); - writeI8(idx8 + 1, mask, off8 + 1); - writeI8(idx8 + 2, mask, off8 + 2); - writeI8(idx8 + 3, mask, off8 + 3); - writeI8(idx8 + 4, mask, off8 + 4); - writeI8(idx8 + 5, mask, off8 + 5); - writeI8(idx8 + 6, mask, off8 + 6); - writeI8(idx8 + 7, mask, off8 + 7); - break; - } - default: assert(false); - } - } - compiler.currentType = Type.v128; - return module.simd_shuffle(arg0, arg1, mask); - } - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.load_ext", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_load_ext, builtin_v128_load_ext); + +// v128.add(a: v128, b: v128) -> v128 +function builtin_v128_add(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.AddI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.AddI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.AddI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.AddI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.AddI64x2 + : BinaryOp.AddI32x4, + arg0, arg1 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shuffle", type.toString() - ); - compiler.currentType = Type.v128; - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.AddF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.AddF64x2, arg0, arg1); } - case BuiltinNames.v128_swizzle: { // swizzle(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.add", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_add, builtin_v128_add); + +// v128.sub(a: v128, b: v128) -> v128 +function builtin_v128_sub(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.SubI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.SubI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.SubI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.binary(BinaryOp.SubI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.binary( + compiler.options.isWasm64 + ? BinaryOp.SubI64x2 + : BinaryOp.SubI32x4, + arg0, arg1 + ); } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.SwizzleV8x16, arg0, arg1); + case TypeKind.F32: return module.binary(BinaryOp.SubF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.SubF64x2, arg0, arg1); } - case BuiltinNames.v128_load_splat: { // load_splat(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; - } - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - return module.unreachable(); - } - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: { - return module.simd_load(SIMDLoadOp.LoadSplatV8x16, arg0, immOffset, immAlign); - } - case TypeKind.I16: - case TypeKind.U16: { - return module.simd_load(SIMDLoadOp.LoadSplatV16x8, arg0, immOffset, immAlign); - } - case TypeKind.I32: - case TypeKind.U32: - case TypeKind.F32: { - return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); - } - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.simd_load(SIMDLoadOp.LoadSplatV32x4, arg0, immOffset, immAlign); - } - // fall-through - } - case TypeKind.I64: - case TypeKind.U64: - case TypeKind.F64: { - return module.simd_load(SIMDLoadOp.LoadSplatV64x2, arg0, immOffset, immAlign); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sub", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sub, builtin_v128_sub); + +// v128.mul(a: v128, b: v128) -> v128 +function builtin_v128_mul(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.MulI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.MulI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.MulI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.MulI32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.load_splat", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.MulF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MulF64x2, arg0, arg1); } - case BuiltinNames.v128_load_ext: { // load_ext(ptr: usize, immOffset?: usize, immAlign?: usize) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler, true) | - checkArgsOptional(operands, 1, 3, reportNode, compiler) - ) return module.unreachable(); - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let numOperands = operands.length; - let immOffset = numOperands >= 2 ? evaluateImmediateOffset(operands[1], compiler) : 0; // reports - if (immOffset < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let immAlign: i32; - let naturalAlign = type.byteSize; - if (numOperands == 3) { - immAlign = evaluateImmediateOffset(operands[2], compiler); - if (immAlign < 0) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - } else { - immAlign = naturalAlign; - } - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - if (immAlign > naturalAlign) { - compiler.error( - DiagnosticCode._0_must_be_a_value_between_1_and_2_inclusive, - operands[2].range, "Alignment", "0", naturalAlign.toString() - ); - return module.unreachable(); - } - if (!isPowerOf2(immAlign)) { - compiler.error( - DiagnosticCode._0_must_be_a_power_of_two, - operands[2].range, "Alignment" - ); - return module.unreachable(); - } - switch (type.kind) { - case TypeKind.I8: return module.simd_load(SIMDLoadOp.LoadI8ToI16x8, arg0, immOffset, immAlign); - case TypeKind.U8: return module.simd_load(SIMDLoadOp.LoadU8ToU16x8, arg0, immOffset, immAlign); - case TypeKind.I16: return module.simd_load(SIMDLoadOp.LoadI16ToI32x4, arg0, immOffset, immAlign); - case TypeKind.U16: return module.simd_load(SIMDLoadOp.LoadU16ToU32x4, arg0, immOffset, immAlign); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.simd_load(SIMDLoadOp.LoadI32ToI64x2, arg0, immOffset, immAlign); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.simd_load(SIMDLoadOp.LoadU32ToU64x2, arg0, immOffset, immAlign); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.load_ext", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.mul", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_mul, builtin_v128_mul); + +// v128.div(a: v128, b: v128) -> v128 +function builtin_v128_div(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.binary(BinaryOp.DivF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.DivF64x2, arg0, arg1); } - case BuiltinNames.v128_add: { // add(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.AddI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.AddI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.AddI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.AddI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.AddI64x2 - : BinaryOp.AddI32x4, - arg0, arg1 - ); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.div", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_div, builtin_v128_div); + +// v128.add_saturate(a: v128, b: v128) -> v128 +function builtin_v128_add_saturate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.AddSatI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.AddSatU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.AddSatI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.AddSatU16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.add_saturate", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_add_saturate, builtin_v128_add_saturate); + +// v128.sub_saturate(a: v128, b: v128) -> v128 +function builtin_v128_sub_saturate(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.SubSatI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.SubSatU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.SubSatI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.SubSatU16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sub_saturate", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sub_saturate, builtin_v128_sub_saturate); + +// v128.min(a: v128, b: v128) -> v128 +function builtin_v128_min(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.MinI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.MinU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.MinI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.MinU16x8, arg0, arg1); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through + } + case TypeKind.I32: return module.binary(BinaryOp.MinI32x4, arg0, arg1); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through + } + case TypeKind.U32: return module.binary(BinaryOp.MinU32x4, arg0, arg1); + case TypeKind.F32: return module.binary(BinaryOp.MinF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MinF64x2, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.min", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_min, builtin_v128_min); + +// v128.max(a: v128, b: v128) -> v128 +function builtin_v128_max(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.MaxI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.MaxU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.MaxI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.MaxU16x8, arg0, arg1); + case TypeKind.ISIZE: { + if (compiler.options.isWasm64) break; + // fall-through + } + case TypeKind.I32: return module.binary(BinaryOp.MaxI32x4, arg0, arg1); + case TypeKind.USIZE: { + if (compiler.options.isWasm64) break; + // fall-through + } + case TypeKind.U32: return module.binary(BinaryOp.MaxU32x4, arg0, arg1); + case TypeKind.F32: return module.binary(BinaryOp.MaxF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.MaxF64x2, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.max", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_max, builtin_v128_max); + +// v128.dot(a: v128, b: v128) -> v128 +function builtin_v128_dot(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I16: return module.binary(BinaryOp.DotI16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.dot", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_dot, builtin_v128_dot); + +// v128.avgr(a: v128, b: v128) -> v128 +function builtin_v128_avgr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.U8: return module.binary(BinaryOp.AvgrU8x16, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.AvgrU16x8, arg0, arg1); + } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.avgr", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_avgr, builtin_v128_avgr); + +// v128.eq(a: v128, b: v128) -> v128 +function builtin_v128_eq(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.EqI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.EqI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.EqI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.EqI32x4, arg0, arg1); } - case TypeKind.F32: return module.binary(BinaryOp.AddF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.AddF64x2, arg0, arg1); + break; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.add", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.EqF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.EqF64x2, arg0, arg1); } - case BuiltinNames.v128_sub: { // sub(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.SubI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.SubI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.SubI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.binary(BinaryOp.SubI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.binary( - compiler.options.isWasm64 - ? BinaryOp.SubI64x2 - : BinaryOp.SubI32x4, - arg0, arg1 - ); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.eq", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_eq, builtin_v128_eq); + +// v128.ne(a: v128, b: v128) -> v128 +function builtin_v128_ne(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.binary(BinaryOp.NeI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.binary(BinaryOp.NeI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.binary(BinaryOp.NeI32x4, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.NeI32x4, arg0, arg1); } - case TypeKind.F32: return module.binary(BinaryOp.SubF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.SubF64x2, arg0, arg1); + break; } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sub", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.NeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.NeF64x2, arg0, arg1); } - case BuiltinNames.v128_mul: { // mul(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.ne", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_ne, builtin_v128_ne); + +// v128.lt(a: v128, b: v128) -> v128 +function builtin_v128_lt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.LtI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.LtU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.LtI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.LtU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.LtI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.LtU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LtI32x4, arg0, arg1); + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.MulI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.MulI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.MulI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.MulI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.MulF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MulF64x2, arg0, arg1); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LtU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.mul", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.LtF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.LtF64x2, arg0, arg1); } - case BuiltinNames.v128_div: { // div(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.lt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_lt, builtin_v128_lt); + +// v128.le(a: v128, b: v128) -> v128 +function builtin_v128_le(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.LeI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.LeU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.LeI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.LeU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.LeI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.LeU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LeI32x4, arg0, arg1); + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.binary(BinaryOp.DivF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.DivF64x2, arg0, arg1); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.LeU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.div", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.LeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.LeF64x2, arg0, arg1); } - case BuiltinNames.v128_add_saturate: { // add_saturate(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.le", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_le, builtin_v128_le); + +// v128.gt(a: v128, b: v128) -> v128 +function builtin_v128_gt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.GtI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.GtU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.GtI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.GtU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.GtI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.GtU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GtI32x4, arg0, arg1); + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.AddSatI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.AddSatU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.AddSatI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.AddSatU16x8, arg0, arg1); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GtU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.add_saturate", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.GtF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.GtF64x2, arg0, arg1); } - case BuiltinNames.v128_sub_saturate: { // sub_saturate(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.gt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_gt, builtin_v128_gt); + +// v128.ge(a: v128, b: v128) -> v128 +function builtin_v128_ge(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.binary(BinaryOp.GeI8x16, arg0, arg1); + case TypeKind.U8: return module.binary(BinaryOp.GeU8x16, arg0, arg1); + case TypeKind.I16: return module.binary(BinaryOp.GeI16x8, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.GeU16x8, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.GeI32x4, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.GeU32x4, arg0, arg1); + case TypeKind.ISIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GeI32x4, arg0, arg1); + } + break; } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.SubSatI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.SubSatU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.SubSatI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.SubSatU16x8, arg0, arg1); + case TypeKind.USIZE: { + if (!compiler.options.isWasm64) { + return module.binary(BinaryOp.GeU32x4, arg0, arg1); } + break; } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sub_saturate", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.binary(BinaryOp.GeF32x4, arg0, arg1); + case TypeKind.F64: return module.binary(BinaryOp.GeF64x2, arg0, arg1); } - case BuiltinNames.v128_min: { // min(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.MinI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.MinU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.MinI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.MinU16x8, arg0, arg1); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.binary(BinaryOp.MinI32x4, arg0, arg1); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.binary(BinaryOp.MinU32x4, arg0, arg1); - case TypeKind.F32: return module.binary(BinaryOp.MinF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MinF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.min", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_max: { // max(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.MaxI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.MaxU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.MaxI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.MaxU16x8, arg0, arg1); - case TypeKind.ISIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.I32: return module.binary(BinaryOp.MaxI32x4, arg0, arg1); - case TypeKind.USIZE: { - if (compiler.options.isWasm64) break; - // fall-through - } - case TypeKind.U32: return module.binary(BinaryOp.MaxU32x4, arg0, arg1); - case TypeKind.F32: return module.binary(BinaryOp.MaxF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.MaxF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.max", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.ge", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_ge, builtin_v128_ge); + +// v128.narrow(a: v128, b: v128) -> v128 +function builtin_v128_narrow(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I16: return module.binary(BinaryOp.NarrowI16x8ToI8x16, arg0, arg1); + case TypeKind.U16: return module.binary(BinaryOp.NarrowU16x8ToU8x16, arg0, arg1); + case TypeKind.I32: return module.binary(BinaryOp.NarrowI32x4ToI16x8, arg0, arg1); + case TypeKind.U32: return module.binary(BinaryOp.NarrowU32x4ToU16x8, arg0, arg1); } - case BuiltinNames.v128_dot: { // dot(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I16: return module.binary(BinaryOp.DotI16x8, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.narrow", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_narrow, builtin_v128_narrow); + +// v128.neg(a: v128) -> v128 +function builtin_v128_neg(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.NegI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.NegI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.NegI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.NegI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.NegI64x2 + : UnaryOp.NegI32x4, + arg0 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.dot", type.toString() - ); - return module.unreachable(); + case TypeKind.F32: return module.unary(UnaryOp.NegF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.NegF64x2, arg0); } - case BuiltinNames.v128_avgr: { // avgr(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.U8: return module.binary(BinaryOp.AvgrU8x16, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.AvgrU16x8, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.avgr", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.neg", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_neg, builtin_v128_neg); + +// v128.abs(a: v128) -> v128 +function builtin_v128_abs(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.unary(UnaryOp.AbsF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.AbsF64x2, arg0); } - case BuiltinNames.v128_eq: { // eq(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.EqI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.EqI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.EqI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.EqI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.EqF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.EqF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.eq", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.abs", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_abs, builtin_v128_abs); + +// v128.sqrt(a: v128) -> v128 +function builtin_v128_sqrt(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.unary(UnaryOp.SqrtF32x4, arg0); + case TypeKind.F64: return module.unary(UnaryOp.SqrtF64x2, arg0); } - case BuiltinNames.v128_ne: { // ne(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.binary(BinaryOp.NeI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.binary(BinaryOp.NeI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.binary(BinaryOp.NeI32x4, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.NeI32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.NeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.NeF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.ne", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.sqrt", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_sqrt, builtin_v128_sqrt); + +// v128.convert(a: v128) -> v128 +function builtin_v128_convert(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: return module.unary(UnaryOp.ConvertI32x4ToF32x4, arg0); + case TypeKind.U32: return module.unary(UnaryOp.ConvertU32x4ToF32x4, arg0); + case TypeKind.I64: return module.unary(UnaryOp.ConvertI64x2ToF64x2, arg0); + case TypeKind.U64: return module.unary(UnaryOp.ConvertU64x2ToF64x2, arg0); } - case BuiltinNames.v128_lt: { // lt(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.LtI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.LtU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.LtI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.LtU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.LtI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.LtU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LtI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LtU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.LtF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.LtF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.lt", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.convert", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_convert, builtin_v128_convert); + +// v128.trunc_sat(a: v128) -> v128 +function builtin_v128_trunc_sat(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I32: return module.unary(UnaryOp.TruncSatF32x4ToI32x4, arg0); + case TypeKind.U32: return module.unary(UnaryOp.TruncSatF32x4ToU32x4, arg0); + case TypeKind.I64: return module.unary(UnaryOp.TruncSatF64x2ToI64x2, arg0); + case TypeKind.U64: return module.unary(UnaryOp.TruncSatF64x2ToU64x2, arg0); } - case BuiltinNames.v128_le: { // le(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.LeI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.LeU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.LeI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.LeU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.LeI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.LeU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LeI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.LeU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.LeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.LeF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.le", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.trunc_sat", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_trunc_sat, builtin_v128_trunc_sat); + +// v128.widen_low(a: v128) -> v128 +function builtin_v128_widen_low(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.unary(UnaryOp.WidenLowI8x16ToI16x8, arg0); + case TypeKind.U8: return module.unary(UnaryOp.WidenLowU8x16ToU16x8, arg0); + case TypeKind.I16: return module.unary(UnaryOp.WidenLowI16x8ToI32x4, arg0); + case TypeKind.U16: return module.unary(UnaryOp.WidenLowU16x8ToU32x4, arg0); } - case BuiltinNames.v128_gt: { // gt(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.GtI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.GtU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.GtI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.GtU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.GtI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.GtU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GtI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GtU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.GtF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.GtF64x2, arg0, arg1); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.gt", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.widen_low", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_widen_low, builtin_v128_widen_low); + +// v128.widen_high(a: v128) -> v128 +function builtin_v128_widen_high(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var typeArguments = ctx.typeArguments!; + var type = typeArguments[0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.unary(UnaryOp.WidenHighI8x16ToI16x8, arg0); + case TypeKind.U8: return module.unary(UnaryOp.WidenHighU8x16ToU16x8, arg0); + case TypeKind.I16: return module.unary(UnaryOp.WidenHighI16x8ToI32x4, arg0); + case TypeKind.U16: return module.unary(UnaryOp.WidenHighU16x8ToU32x4, arg0); } - case BuiltinNames.v128_ge: { // ge(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.binary(BinaryOp.GeI8x16, arg0, arg1); - case TypeKind.U8: return module.binary(BinaryOp.GeU8x16, arg0, arg1); - case TypeKind.I16: return module.binary(BinaryOp.GeI16x8, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.GeU16x8, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.GeI32x4, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.GeU32x4, arg0, arg1); - case TypeKind.ISIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GeI32x4, arg0, arg1); - } - break; - } - case TypeKind.USIZE: { - if (!compiler.options.isWasm64) { - return module.binary(BinaryOp.GeU32x4, arg0, arg1); - } - break; - } - case TypeKind.F32: return module.binary(BinaryOp.GeF32x4, arg0, arg1); - case TypeKind.F64: return module.binary(BinaryOp.GeF64x2, arg0, arg1); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.widen_high", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_widen_high, builtin_v128_widen_high); + +// v128.shl(a: v128, b: i32) -> v128 +function builtin_v128_shl(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShlI8x16, arg0, arg1); + case TypeKind.I16: + case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShlI16x8, arg0, arg1); + case TypeKind.I32: + case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShlI32x4, arg0, arg1); + case TypeKind.I64: + case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShlI64x2, arg0, arg1); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShlI64x2 + : SIMDShiftOp.ShlI32x4, + arg0, arg1 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.ge", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.v128_narrow: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shl", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_shl, builtin_v128_shl); + +// v128.shr(a: v128, b: i32) -> v128 +function builtin_v128_shr(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.v128; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: return module.simd_shift(SIMDShiftOp.ShrI8x16, arg0, arg1); + case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShrU8x16, arg0, arg1); + case TypeKind.I16: return module.simd_shift(SIMDShiftOp.ShrI16x8, arg0, arg1); + case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShrU16x8, arg0, arg1); + case TypeKind.I32: return module.simd_shift(SIMDShiftOp.ShrI32x4, arg0, arg1); + case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShrU32x4, arg0, arg1); + case TypeKind.I64: return module.simd_shift(SIMDShiftOp.ShrI64x2, arg0, arg1); + case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShrU64x2, arg0, arg1); + case TypeKind.ISIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShrI64x2 + : SIMDShiftOp.ShrI32x4, + arg0, arg1 + ); } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I16: return module.binary(BinaryOp.NarrowI16x8ToI8x16, arg0, arg1); - case TypeKind.U16: return module.binary(BinaryOp.NarrowU16x8ToU8x16, arg0, arg1); - case TypeKind.I32: return module.binary(BinaryOp.NarrowI32x4ToI16x8, arg0, arg1); - case TypeKind.U32: return module.binary(BinaryOp.NarrowU32x4ToU16x8, arg0, arg1); - } + case TypeKind.USIZE: { + return module.simd_shift( + compiler.options.isWasm64 + ? SIMDShiftOp.ShrU64x2 + : SIMDShiftOp.ShrU32x4, + arg0, arg1 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.narrow", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.v128_neg: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.NegI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.NegI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.NegI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.NegI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.NegI64x2 - : UnaryOp.NegI32x4, - arg0 - ); - } - case TypeKind.F32: return module.unary(UnaryOp.NegF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.NegF64x2, arg0); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.shr", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_shr, builtin_v128_shr); + +function builtin_v128_bitwise_binary(ctx: BuiltinContext, op: BinaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + return module.binary(op, arg0, arg1); +} + +// v128.and(a: v128, b: v128) -> v128 +function builtin_v128_and(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.AndV128); +} +builtins.set(BuiltinNames.v128_and, builtin_v128_and); + +// v128.or(a: v128, b: v128) -> v128 +function builtin_v128_or(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.OrV128); +} +builtins.set(BuiltinNames.v128_or, builtin_v128_or); + +// v128.xor(a: v128, b: v128) -> v128 +function builtin_v128_xor(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.XorV128); +} +builtins.set(BuiltinNames.v128_xor, builtin_v128_xor); + +// v128.andnot(a: v128, b: v128) -> v128 +function builtin_v128_andnot(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_binary(ctx, BinaryOp.AndNotV128); +} +builtins.set(BuiltinNames.v128_andnot, builtin_v128_andnot); + +function builtin_v128_bitwise_unary(ctx: BuiltinContext, op: UnaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + return module.unary(op, arg0); +} + +// v128.not(a: v128) -> v128 +function builtin_v128_not(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_unary(ctx, UnaryOp.NotV128); +} +builtins.set(BuiltinNames.v128_not, builtin_v128_not); + +function builtin_v128_bitwise_ternary(ctx: BuiltinContext, op: SIMDTernaryOp): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + return module.simd_ternary(op, arg0, arg1, arg2); +} + +// v128.bitselect(v1: v128, v2: v128, c: v128) -> v128 +function builtin_v128_bitselect(ctx: BuiltinContext): ExpressionRef { + return builtin_v128_bitwise_ternary(ctx, SIMDTernaryOp.Bitselect); +} +builtins.set(BuiltinNames.v128_bitselect, builtin_v128_bitselect); + +// v128.any_true(a: v128) -> bool +function builtin_v128_any_true(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.AnyTrueI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.AnyTrueI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.AnyTrueI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.AnyTrueI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.AnyTrueI64x2 + : UnaryOp.AnyTrueI32x4, + arg0 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.neg", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.v128_abs: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.unary(UnaryOp.AbsF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.AbsF64x2, arg0); - } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.any_true", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_any_true, builtin_v128_any_true); + +// v128.all_true(a: v128) -> bool +function builtin_v128_all_true(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 1) + ) { + compiler.currentType = Type.bool; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + compiler.currentType = Type.bool; + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.I8: + case TypeKind.U8: return module.unary(UnaryOp.AllTrueI8x16, arg0); + case TypeKind.I16: + case TypeKind.U16: return module.unary(UnaryOp.AllTrueI16x8, arg0); + case TypeKind.I32: + case TypeKind.U32: return module.unary(UnaryOp.AllTrueI32x4, arg0); + case TypeKind.I64: + case TypeKind.U64: return module.unary(UnaryOp.AllTrueI64x2, arg0); + case TypeKind.ISIZE: + case TypeKind.USIZE: { + return module.unary( + compiler.options.isWasm64 + ? UnaryOp.AllTrueI64x2 + : UnaryOp.AllTrueI32x4, + arg0 + ); } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.abs", type.toString() - ); - return module.unreachable(); } - case BuiltinNames.v128_sqrt: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.unary(UnaryOp.SqrtF32x4, arg0); - case TypeKind.F64: return module.unary(UnaryOp.SqrtF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.sqrt", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_convert: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: return module.unary(UnaryOp.ConvertI32x4ToF32x4, arg0); - case TypeKind.U32: return module.unary(UnaryOp.ConvertU32x4ToF32x4, arg0); - case TypeKind.I64: return module.unary(UnaryOp.ConvertI64x2ToF64x2, arg0); - case TypeKind.U64: return module.unary(UnaryOp.ConvertU64x2ToF64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.convert", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_trunc_sat: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I32: return module.unary(UnaryOp.TruncSatF32x4ToI32x4, arg0); - case TypeKind.U32: return module.unary(UnaryOp.TruncSatF32x4ToU32x4, arg0); - case TypeKind.I64: return module.unary(UnaryOp.TruncSatF64x2ToI64x2, arg0); - case TypeKind.U64: return module.unary(UnaryOp.TruncSatF64x2ToU64x2, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.trunc_sat", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_widen_low: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.unary(UnaryOp.WidenLowI8x16ToI16x8, arg0); - case TypeKind.U8: return module.unary(UnaryOp.WidenLowU8x16ToU16x8, arg0); - case TypeKind.I16: return module.unary(UnaryOp.WidenLowI16x8ToI32x4, arg0); - case TypeKind.U16: return module.unary(UnaryOp.WidenLowU16x8ToU32x4, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.widen_low", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_widen_high: { - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.unary(UnaryOp.WidenHighI8x16ToI16x8, arg0); - case TypeKind.U8: return module.unary(UnaryOp.WidenHighU8x16ToU16x8, arg0); - case TypeKind.I16: return module.unary(UnaryOp.WidenHighI16x8ToI32x4, arg0); - case TypeKind.U16: return module.unary(UnaryOp.WidenHighU16x8ToU32x4, arg0); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.widen_high", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_shl: { // shl(a: v128, b: i32) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShlI8x16, arg0, arg1); - case TypeKind.I16: - case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShlI16x8, arg0, arg1); - case TypeKind.I32: - case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShlI32x4, arg0, arg1); - case TypeKind.I64: - case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShlI64x2, arg0, arg1); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShlI64x2 - : SIMDShiftOp.ShlI32x4, - arg0, arg1 - ); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shl", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_shr: { // shr(a: v128, b: i32) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.i32, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.v128; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: return module.simd_shift(SIMDShiftOp.ShrI8x16, arg0, arg1); - case TypeKind.U8: return module.simd_shift(SIMDShiftOp.ShrU8x16, arg0, arg1); - case TypeKind.I16: return module.simd_shift(SIMDShiftOp.ShrI16x8, arg0, arg1); - case TypeKind.U16: return module.simd_shift(SIMDShiftOp.ShrU16x8, arg0, arg1); - case TypeKind.I32: return module.simd_shift(SIMDShiftOp.ShrI32x4, arg0, arg1); - case TypeKind.U32: return module.simd_shift(SIMDShiftOp.ShrU32x4, arg0, arg1); - case TypeKind.I64: return module.simd_shift(SIMDShiftOp.ShrI64x2, arg0, arg1); - case TypeKind.U64: return module.simd_shift(SIMDShiftOp.ShrU64x2, arg0, arg1); - case TypeKind.ISIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShrI64x2 - : SIMDShiftOp.ShrI32x4, - arg0, arg1 - ); - } - case TypeKind.USIZE: { - return module.simd_shift( - compiler.options.isWasm64 - ? SIMDShiftOp.ShrU64x2 - : SIMDShiftOp.ShrU32x4, - arg0, arg1 - ); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.shr", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_and: { // and(a: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.AndV128, arg0, arg1); - } - case BuiltinNames.v128_or: { // or(a: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.OrV128, arg0, arg1); - } - case BuiltinNames.v128_xor: { // xor(a: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.XorV128, arg0, arg1); - } - case BuiltinNames.v128_andnot: { // andnot(a: v128, b: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - return module.binary(BinaryOp.AndNotV128, arg0, arg1); - } - case BuiltinNames.v128_not: { // not(a: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - return module.unary(UnaryOp.NotV128, arg0); - } - case BuiltinNames.v128_bitselect: { // bitselect(v1: v128, v2: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - return module.simd_ternary(SIMDTernaryOp.Bitselect, arg0, arg1, arg2); - } - case BuiltinNames.v128_any_true: { // any_true(a: v128) -> bool - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.AnyTrueI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.AnyTrueI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.AnyTrueI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.AnyTrueI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.AnyTrueI64x2 - : UnaryOp.AnyTrueI32x4, - arg0 - ); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.any_true", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_all_true: { // all_true(a: v128) -> bool - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.I8: - case TypeKind.U8: return module.unary(UnaryOp.AllTrueI8x16, arg0); - case TypeKind.I16: - case TypeKind.U16: return module.unary(UnaryOp.AllTrueI16x8, arg0); - case TypeKind.I32: - case TypeKind.U32: return module.unary(UnaryOp.AllTrueI32x4, arg0); - case TypeKind.I64: - case TypeKind.U64: return module.unary(UnaryOp.AllTrueI64x2, arg0); - case TypeKind.ISIZE: - case TypeKind.USIZE: { - return module.unary( - compiler.options.isWasm64 - ? UnaryOp.AllTrueI64x2 - : UnaryOp.AllTrueI32x4, - arg0 - ); - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.all_true", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.v128_qfma: { // qfma(a: v128, b: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMAF32x4, arg0, arg1, arg2); - case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMAF64x2, arg0, arg1, arg2); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.qfma", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.all_true", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_all_true, builtin_v128_all_true); + +// v128.qfma(a: v128, b: v128, c: v128) -> v128 +function builtin_v128_qfma(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMAF32x4, arg0, arg1, arg2); + case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMAF64x2, arg0, arg1, arg2); } - case BuiltinNames.v128_qfms: { // qfms(a: v128, b: v128, c: v128) -> v128 - if ( - checkFeatureEnabled(Feature.SIMD, reportNode, compiler) | - checkTypeRequired(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 3, reportNode, compiler) - ) { - compiler.currentType = Type.v128; - return module.unreachable(); - } - let type = typeArguments![0]; - let arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); - let arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMSF32x4, arg0, arg1, arg2); - case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMSF64x2, arg0, arg1, arg2); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "v128.qfms", type.toString() - ); - return module.unreachable(); + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.qfma", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_qfma, builtin_v128_qfma); + +// v128.qfms(a: v128, b: v128, c: v128) -> v128 +function builtin_v128_qfms(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkFeatureEnabled(ctx, Feature.SIMD) | + checkTypeRequired(ctx) | + checkArgsRequired(ctx, 3) + ) { + compiler.currentType = Type.v128; + return module.unreachable(); + } + var operands = ctx.operands; + var type = ctx.typeArguments![0]; + var arg0 = compiler.compileExpression(operands[0], Type.v128, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.v128, Constraints.CONV_IMPLICIT); + var arg2 = compiler.compileExpression(operands[2], Type.v128, Constraints.CONV_IMPLICIT); + if (!type.is(TypeFlags.REFERENCE)) { + switch (type.kind) { + case TypeKind.F32: return module.simd_ternary(SIMDTernaryOp.QFMSF32x4, arg0, arg1, arg2); + case TypeKind.F64: return module.simd_ternary(SIMDTernaryOp.QFMSF64x2, arg0, arg1, arg2); } + } + compiler.error( + DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, + ctx.reportNode.typeArgumentsRange, "v128.qfms", type.toString() + ); + return module.unreachable(); +} +builtins.set(BuiltinNames.v128_qfms, builtin_v128_qfms); + +// === Internal runtime ======================================================================= + +// __visit_globals(cookie: u32) -> void +function builtin_visit_globals(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 1) // cookie + ) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_IMPLICIT); + compiler.runtimeFeatures |= RuntimeFeatures.visitGlobals; + compiler.currentType = Type.void; + return module.call(BuiltinNames.visit_globals, [ arg0 ], NativeType.None); +} +builtins.set(BuiltinNames.visit_globals, builtin_visit_globals); + +// __visit_members(ref: usize, cookie: u32) -> void +function builtin_visit_members(ctx: BuiltinContext): ExpressionRef { + var compiler = ctx.compiler; + var module = compiler.module; + if ( + checkTypeAbsent(ctx) | + checkArgsRequired(ctx, 2) // ref, cookie + ) { + compiler.currentType = Type.void; + return module.unreachable(); + } + var operands = ctx.operands; + var arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); + var arg1 = compiler.compileExpression(operands[1], Type.u32, Constraints.CONV_IMPLICIT); + compiler.runtimeFeatures |= RuntimeFeatures.visitMembers; + compiler.currentType = Type.void; + return module.call(BuiltinNames.visit_members, [ arg0, arg1 ], NativeType.None); +} +builtins.set(BuiltinNames.visit_members, builtin_visit_members); + +// === Inline assembler ======================================================================= + +// TODO: Operators can't be just deferred (don't have a corresponding generic built-in) +// add, sub, mul, div_s, div_u, rem_s, rem_u +// and, or, xor, shl, shr_u, shr_s +// eq, eqz, ne, lt_s, lt_u, le_s, le_u, gt_s, gt_u, ge_s, ge_u + +// i32.clz -> clz +function builtin_i32_clz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_clz(ctx); +} +builtins.set(BuiltinNames.i32_clz, builtin_i32_clz); + +// i64.clz -> clz +function builtin_i64_clz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_clz(ctx); +} +builtins.set(BuiltinNames.i64_clz, builtin_i64_clz); + +// i32.ctz -> ctz +function builtin_i32_ctz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_ctz(ctx); +} +builtins.set(BuiltinNames.i32_ctz, builtin_i32_ctz); + +// i64.ctz -> ctz +function builtin_i64_ctz(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_ctz(ctx); +} +builtins.set(BuiltinNames.i64_ctz, builtin_i64_ctz); + +// i32.popcnt -> popcnt +function builtin_i32_popcnt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_popcnt(ctx); +} +builtins.set(BuiltinNames.i32_popcnt, builtin_i32_popcnt); + +// i64.popcnt -> popcnt +function builtin_i64_popcnt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_popcnt(ctx); +} +builtins.set(BuiltinNames.i64_popcnt, builtin_i64_popcnt); + +// i32.rotl -> rotl +function builtin_i32_rotl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_rotl(ctx); +} +builtins.set(BuiltinNames.i32_rotl, builtin_i32_rotl); + +// i64.rotl -> rotl +function builtin_i64_rotl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_rotl(ctx); +} +builtins.set(BuiltinNames.i64_rotl, builtin_i64_rotl); + +// i32.rotr -> rotr +function builtin_i32_rotr(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_rotr(ctx); +} +builtins.set(BuiltinNames.i32_rotr, builtin_i32_rotr); + +// i64.rotr -> rotr +function builtin_i64_rotr(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_rotr(ctx); +} +builtins.set(BuiltinNames.i64_rotr, builtin_i64_rotr); + +// f32.abs -> abs +function builtin_f32_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_abs(ctx); +} +builtins.set(BuiltinNames.f32_abs, builtin_f32_abs); + +// f64.abs -> abs +function builtin_f64_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_abs(ctx); +} +builtins.set(BuiltinNames.f64_abs, builtin_f64_abs); + +// f32.max -> max +function builtin_f32_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_max(ctx); +} +builtins.set(BuiltinNames.f32_max, builtin_f32_max); + +// f64.max -> max +function builtin_f64_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_max(ctx); +} +builtins.set(BuiltinNames.f64_max, builtin_f64_max); + +// f32.min -> min +function builtin_f32_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_min(ctx); +} +builtins.set(BuiltinNames.f32_min, builtin_f32_min); + +// f64.min -> min +function builtin_f64_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_min(ctx); +} +builtins.set(BuiltinNames.f64_min, builtin_f64_min); + +// f32.ceil -> ceil +function builtin_f32_ceil(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_ceil(ctx); +} +builtins.set(BuiltinNames.f32_ceil, builtin_f32_ceil); + +// f64.ceil -> ceil +function builtin_f64_ceil(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_ceil(ctx); +} +builtins.set(BuiltinNames.f64_ceil, builtin_f64_ceil); + +// f32.floor -> floor +function builtin_f32_floor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_floor(ctx); +} +builtins.set(BuiltinNames.f32_floor, builtin_f32_floor); + +// f64.floor -> floor +function builtin_f64_floor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_floor(ctx); +} +builtins.set(BuiltinNames.f64_floor, builtin_f64_floor); + +// f32.copysign -> copysign +function builtin_f32_copysign(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_copysign(ctx); +} +builtins.set(BuiltinNames.f32_copysign, builtin_f32_copysign); + +// f64.copysign -> copysign +function builtin_f64_copysign(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_copysign(ctx); +} +builtins.set(BuiltinNames.f64_copysign, builtin_f64_copysign); + +// f32.nearest -> nearest +function builtin_f32_nearest(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_nearest(ctx); +} +builtins.set(BuiltinNames.f32_nearest, builtin_f32_nearest); + +// f64.nearest -> nearest +function builtin_f64_nearest(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_nearest(ctx); +} +builtins.set(BuiltinNames.f64_nearest, builtin_f64_nearest); + +// i32.reinterpret_f32 -> reinterpret +function builtin_i32_reinterpret_f32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.f32; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.i32_reinterpret_f32, builtin_i32_reinterpret_f32); + +// i64.reinterpret_f64 -> reinterpret +function builtin_i64_reinterpret_f64(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.f64; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.i64_reinterpret_f64, builtin_i64_reinterpret_f64); + +// f32.reinterpret_i32 -> reinterpret +function builtin_f32_reinterpret_i32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.i32; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.f32_reinterpret_i32, builtin_f32_reinterpret_i32); + +// f64.reinterpret_i64 -> reinterpret +function builtin_f64_reinterpret_i64(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.i64; + return builtin_reinterpret(ctx); +} +builtins.set(BuiltinNames.f64_reinterpret_i64, builtin_f64_reinterpret_i64); + +// f32.sqrt -> sqrt +function builtin_f32_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_sqrt(ctx); +} +builtins.set(BuiltinNames.f32_sqrt, builtin_f32_sqrt); + +// f64.sqrt -> sqrt +function builtin_f64_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_sqrt(ctx); +} +builtins.set(BuiltinNames.f64_sqrt, builtin_f64_sqrt); + +// f32.trunc -> trunc +function builtin_f32_trunc(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_trunc(ctx); +} +builtins.set(BuiltinNames.f32_trunc, builtin_f32_trunc); + +// f64.trunc -> trunc +function builtin_f64_trunc(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_trunc(ctx); +} +builtins.set(BuiltinNames.f64_trunc, builtin_f64_trunc); + +// i32.load8_s -> load +function builtin_i32_load8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load8_s, builtin_i32_load8_s); + +// i32.load8_u -> load +function builtin_i32_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load8_u, builtin_i32_load8_u); + +// i32.load16_s -> load +function builtin_i32_load16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load16_s, builtin_i32_load16_s); + +// i32.load16_u -> load +function builtin_i32_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load16_u, builtin_i32_load16_u); + +// i32.load -> load +function builtin_i32_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i32_load, builtin_i32_load); + +// i64.load8_s -> load +function builtin_i64_load8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load8_s, builtin_i64_load8_s); + +// i64.load8_u -> load +function builtin_i64_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load8_u, builtin_i64_load8_u); + +// i64.load16_s -> load +function builtin_i64_load16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load16_s, builtin_i64_load16_s); + +// i64.load16_u -> load +function builtin_i64_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load16_u, builtin_i64_load16_u); + +// i64.load32_s -> load +function builtin_i64_load32_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load32_s, builtin_i64_load32_s); + +// i64.load32_u -> load +function builtin_i64_load32_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load32_u, builtin_i64_load32_u); + +// i64.load -> load +function builtin_i64_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.i64_load, builtin_i64_load); + +// f32.load -> load +function builtin_f32_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.f32_load, builtin_f32_load); + +// f64.load -> load +function builtin_f64_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.f64_load, builtin_f64_load); + +// i32.store8 -> store +function builtin_i32_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store8, builtin_i32_store8); + +// i32.store16 -> store +function builtin_i32_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store16, builtin_i32_store16); + +// i32.store -> store +function builtin_i32_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i32_store, builtin_i32_store); + +// i64.store8 -> store +function builtin_i64_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store8, builtin_i64_store8); + +// i64.store16 -> store +function builtin_i64_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store16, builtin_i64_store16); + +// i64.store32 -> store +function builtin_i64_store32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store32, builtin_i64_store32); + +// i64.store -> store +function builtin_i64_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.i64_store, builtin_i64_store); + +// f32.store -> store +function builtin_f32_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.f32_store, builtin_f32_store); + +// f64.store -> store +function builtin_f64_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.f64_store, builtin_f64_store); + +// i32.atomic.load8_u -> atomic.load +function builtin_i32_atomic_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load8_u, builtin_i32_atomic_load8_u); + +// i32.atomic.load16_u -> atomic.load +function builtin_i32_atomic_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load16_u, builtin_i32_atomic_load16_u); + +// i32.atomic.load -> atomic.load +function builtin_i32_atomic_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i32_atomic_load, builtin_i32_atomic_load); + +// i64.atomic.load8_u -> atomic.load +function builtin_i64_atomic_load8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load8_u, builtin_i64_atomic_load8_u); + +// i64.atomic.load16_u -> atomic.load +function builtin_i64_atomic_load16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load16_u, builtin_i64_atomic_load16_u); + +// i64.atomic.load32_u -> atomic.load +function builtin_i64_atomic_load32_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load32_u, builtin_i64_atomic_load32_u); + +// i64.atomic.load -> atomic.load +function builtin_i64_atomic_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_atomic_load(ctx); +} +builtins.set(BuiltinNames.i64_atomic_load, builtin_i64_atomic_load); + +// i32.atomic.store8 -> atomic.store +function builtin_i32_atomic_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store8, builtin_i32_atomic_store8); + +// i32.atomic.store16 -> atomic.store +function builtin_i32_atomic_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store16, builtin_i32_atomic_store16); + +// i32.atomic.store -> atomic.store +function builtin_i32_atomic_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i32_atomic_store, builtin_i32_atomic_store); + +// i64.atomic.store8 -> atomic.store +function builtin_i64_atomic_store8(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store8, builtin_i64_atomic_store8); + +// i64.atomic.store16 -> atomic.store +function builtin_i64_atomic_store16(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store16, builtin_i64_atomic_store16); + +// i64.atomic.store32 -> atomic.store +function builtin_i64_atomic_store32(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store32, builtin_i64_atomic_store32); + +// i64.atomic.store -> atomic.store +function builtin_i64_atomic_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_store(ctx); +} +builtins.set(BuiltinNames.i64_atomic_store, builtin_i64_atomic_store); + +// i32.atomic.rmw8.add_u -> atomic.add +function builtin_i32_atomic_rmw8_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_add_u, builtin_i32_atomic_rmw8_add_u); + +// i32.atomic.rmw16.add_u -> atomic.add +function builtin_i32_atomic_rmw16_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_add_u, builtin_i32_atomic_rmw16_add_u); + +// i32.atomic.rmw.add -> atomic.add +function builtin_i32_atomic_rmw_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_add, builtin_i32_atomic_rmw_add); + +// i64.atomic.rmw8.add_u -> atomic.add +function builtin_i64_atomic_rmw8_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_add_u, builtin_i64_atomic_rmw8_add_u); + +// i64.atomic.rmw16.add_u -> atomic.add +function builtin_i64_atomic_rmw16_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_add_u, builtin_i64_atomic_rmw16_add_u); + +// i64.atomic.rmw32.add_u -> atomic.add +function builtin_i64_atomic_rmw32_add_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_add_u, builtin_i64_atomic_rmw32_add_u); + +// i64.atomic.rmw.add -> atomic.add +function builtin_i64_atomic_rmw_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_add(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_add, builtin_i64_atomic_rmw_add); + +// i32.atomic.rmw8.sub_u -> atomic.sub +function builtin_i32_atomic_rmw8_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_sub_u, builtin_i32_atomic_rmw8_sub_u); + +// i32.atomic.rmw16.sub_u -> atomic.sub +function builtin_i32_atomic_rmw16_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_sub_u, builtin_i32_atomic_rmw16_sub_u); + +// i32.atomic.rmw.sub -> atomic.sub +function builtin_i32_atomic_rmw_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_sub, builtin_i32_atomic_rmw_sub); + +// i64.atomic.rmw8.sub_u -> atomic.sub +function builtin_i64_atomic_rmw8_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_sub_u, builtin_i64_atomic_rmw8_sub_u); + +// i64.atomic.rmw16.sub_u -> atomic.sub +function builtin_i64_atomic_rmw16_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_sub_u, builtin_i64_atomic_rmw16_sub_u); + +// i64.atomic.rmw32.sub_u -> atomic.sub +function builtin_i64_atomic_rmw32_sub_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_sub_u, builtin_i64_atomic_rmw32_sub_u); + +// i64.atomic.rmw.sub -> atomic.sub +function builtin_i64_atomic_rmw_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_sub(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_sub, builtin_i64_atomic_rmw_sub); + +// i32.atomic.rmw8.and_u -> atomic.and +function builtin_i32_atomic_rmw8_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_and_u, builtin_i32_atomic_rmw8_and_u); + +// i32.atomic.rmw16.and_u -> atomic.and +function builtin_i32_atomic_rmw16_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_and_u, builtin_i32_atomic_rmw16_and_u); + +// i32.atomic.rmw.and -> atomic.and +function builtin_i32_atomic_rmw_and(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_and, builtin_i32_atomic_rmw_and); + +// i64.atomic.rmw8.and_u -> atomic.and +function builtin_i64_atomic_rmw8_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_and_u, builtin_i64_atomic_rmw8_and_u); + +// i64.atomic.rmw16.and_u -> atomic.and +function builtin_i64_atomic_rmw16_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_and_u, builtin_i64_atomic_rmw16_and_u); + +// i64.atomic.rmw32.and_u -> atomic.and +function builtin_i64_atomic_rmw32_and_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_and_u, builtin_i64_atomic_rmw32_and_u); + +// i64.atomic.rmw.and -> atomic.and +function builtin_i64_atomic_rmw_and(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_and(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_and, builtin_i64_atomic_rmw_and); + +// i32.atomic.rmw8.or_u -> atomic.or +function builtin_i32_atomic_rmw8_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_or_u, builtin_i32_atomic_rmw8_or_u); + +// i32.atomic.rmw16.or_u -> +function builtin_i32_atomic_rmw16_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_or_u, builtin_i32_atomic_rmw16_or_u); + +// i32.atomic.rmw.or -> atomic.or +function builtin_i32_atomic_rmw_or(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_or, builtin_i32_atomic_rmw_or); + +// i64.atomic.rmw8.or_u -> atomic.or +function builtin_i64_atomic_rmw8_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_or_u, builtin_i64_atomic_rmw8_or_u); + +// i64.atomic.rmw16.or_u -> atomic.or +function builtin_i64_atomic_rmw16_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_or_u, builtin_i64_atomic_rmw16_or_u); + +// i64.atomic.rmw32.or_u -> atomic.or +function builtin_i64_atomic_rmw32_or_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_or_u, builtin_i64_atomic_rmw32_or_u); + +// i64.atomic.rmw.or -> atomic.or +function builtin_i64_atomic_rmw_or(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_or(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_or, builtin_i64_atomic_rmw_or); + +// i32.atomic.rmw8.xor_u -> atomic.xor +function builtin_i32_atomic_rmw8_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_xor_u, builtin_i32_atomic_rmw8_xor_u); + +// i32.atomic.rmw16.xor_u -> atomic.xor +function builtin_i32_atomic_rmw16_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_xor_u, builtin_i32_atomic_rmw16_xor_u); + +// i32.atomic.rmw.xor -> atomic.xor +function builtin_i32_atomic_rmw_xor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_xor, builtin_i32_atomic_rmw_xor); + +// i64.atomic.rmw8.xor_u -> atomic.xor +function builtin_i64_atomic_rmw8_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_xor_u, builtin_i64_atomic_rmw8_xor_u); + +// i64.atomic.rmw16.xor_u -> atomic.xor +function builtin_i64_atomic_rmw16_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_xor_u, builtin_i64_atomic_rmw16_xor_u); + +// i64.atomic.rmw32.xor_u -> atomic.xor +function builtin_i64_atomic_rmw32_xor_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_xor_u, builtin_i64_atomic_rmw32_xor_u); + +// i64.atomic.rmw.xor -> atomic.xor +function builtin_i64_atomic_rmw_xor(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xor(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_xor, builtin_i64_atomic_rmw_xor); + +// i32.atomic.rmw8.xchg_u -> atomic.xchg +function builtin_i32_atomic_rmw8_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_xchg_u, builtin_i32_atomic_rmw8_xchg_u); + +// i32.atomic.rmw16.xchg_u -> atomic.xchg +function builtin_i32_atomic_rmw16_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_xchg_u, builtin_i32_atomic_rmw16_xchg_u); + +// i32.atomic.rmw.xchg -> atomic.xchg +function builtin_i32_atomic_rmw_xchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_xchg, builtin_i32_atomic_rmw_xchg); + +// i64.atomic.rmw8.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw8_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_xchg_u, builtin_i64_atomic_rmw8_xchg_u); + +// i64.atomic.rmw16.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw16_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_xchg_u, builtin_i64_atomic_rmw16_xchg_u); + +// i64.atomic.rmw32.xchg_u -> atomic.xchg +function builtin_i64_atomic_rmw32_xchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_xchg_u, builtin_i64_atomic_rmw32_xchg_u); + +// i64.atomic.rmw.xchg -> atomic.xchg +function builtin_i64_atomic_rmw_xchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_xchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_xchg, builtin_i64_atomic_rmw_xchg); + +// i32.atomic.rmw8.cmpxchg_u -> atomic.cmpxchg +function builtin_i32_atomic_rmw8_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw8_cmpxchg_u, builtin_i32_atomic_rmw8_cmpxchg_u); + +// i32.atomic.rmw16.cmpxchg_u -> atomic.cmpxchg +function builtin_i32_atomic_rmw16_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw16_cmpxchg_u, builtin_i32_atomic_rmw16_cmpxchg_u); + +// i32.atomic.rmw.cmpxchg -> atomic.cmpxchg +function builtin_i32_atomic_rmw_cmpxchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i32_atomic_rmw_cmpxchg, builtin_i32_atomic_rmw_cmpxchg); + +// i64.atomic.rmw8.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw8_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw8_cmpxchg_u, builtin_i64_atomic_rmw8_cmpxchg_u); + +// i64.atomic.rmw16.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw16_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw16_cmpxchg_u, builtin_i64_atomic_rmw16_cmpxchg_u); + +// i64.atomic.rmw32.cmpxchg_u -> atomic.cmpxchg +function builtin_i64_atomic_rmw32_cmpxchg_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw32_cmpxchg_u, builtin_i64_atomic_rmw32_cmpxchg_u); + +// i64.atomic.rmw.cmpxchg -> atomic.cmpxchg +function builtin_i64_atomic_rmw_cmpxchg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + ctx.contextIsExact = true; + return builtin_atomic_cmpxchg(ctx); +} +builtins.set(BuiltinNames.i64_atomic_rmw_cmpxchg, builtin_i64_atomic_rmw_cmpxchg); + +// i32.wait -> atomic.wait +function builtin_i32_wait(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + return builtin_atomic_wait(ctx); +} +builtins.set(BuiltinNames.i32_wait, builtin_i32_wait); + +// i64.wait -> atomic.wait +function builtin_i64_wait(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_atomic_wait(ctx); +} +builtins.set(BuiltinNames.i64_wait, builtin_i64_wait); + +// v128.load -> load +function builtin_v128_load(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.v128 ]; + ctx.contextualType = Type.v128; + return builtin_load(ctx); +} +builtins.set(BuiltinNames.v128_load, builtin_v128_load); + +// v128.store -> store +function builtin_v128_store(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.v128 ]; + ctx.contextualType = Type.v128; + ctx.contextIsExact = true; + return builtin_store(ctx); +} +builtins.set(BuiltinNames.v128_store, builtin_v128_store); + +// i8x16_splat -> v128.splat +function builtin_i8x16_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i8x16_splat, builtin_i8x16_splat); + +// i8x16.extract_lane_s -> v128.extract_lane +function builtin_i8x16_extract_lane_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_extract_lane_s, builtin_i8x16_extract_lane_s); + +// i8x16.extract_lane_u -> v128.extract_lane +function builtin_i8x16_extract_lane_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_extract_lane_u, builtin_i8x16_extract_lane_u); + +// i8x16.replace_lane -> v128.replace_lane +function builtin_i8x16_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i8x16_replace_lane, builtin_i8x16_replace_lane); + +// i8x16.add -> v128.add +function builtin_i8x16_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i8x16_add, builtin_i8x16_add); + +// i8x16.sub -> v128.sub +function builtin_i8x16_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i8x16_sub, builtin_i8x16_sub); + +// i8x16.mul -> v128.mul +function builtin_i8x16_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i8x16_mul, builtin_i8x16_mul); + +// i8x16.min_s -> v128.min +function builtin_i8x16_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i8x16_min_s, builtin_i8x16_min_s); + +// i8x16.min_u -> v128.min +function builtin_i8x16_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i8x16_min_u, builtin_i8x16_min_u); + +// i8x16.max_s -> v128.max +function builtin_i8x16_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i8x16_max_s, builtin_i8x16_max_s); + +// i8x16.max_u -> v128.max +function builtin_i8x16_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i8x16_max_u, builtin_i8x16_max_u); + +// i8x16.avgr_u -> v128.avgr +function builtin_i8x16_avgr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_avgr(ctx); +} +builtins.set(BuiltinNames.i8x16_avgr_u, builtin_i8x16_avgr_u); + +// i8x16.neg -> v128.neg +function builtin_i8x16_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i8x16_neg, builtin_i8x16_neg); + +// i8x16.add_saturate_s -> v128.add_saturate +function builtin_i8x16_add_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_add_saturate_s, builtin_i8x16_add_saturate_s); + +// i8x16.add_saturate_u -> v128.add_saturate +function builtin_i8x16_add_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_add_saturate_u, builtin_i8x16_add_saturate_u); + +// i8x16.sub_saturate_s -> v128.sub_saturate +function builtin_i8x16_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_sub_saturate_s, builtin_i8x16_sub_saturate_s); + +// i8x16.sub_saturate_u -> v128.sub_saturate +function builtin_i8x16_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i8x16_sub_saturate_u, builtin_i8x16_sub_saturate_u); + +// i8x16.shl -> v128.shl +function builtin_i8x16_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i8x16_shl, builtin_i8x16_shl); + +// i8x16.shr_s -> v128.shr +function builtin_i8x16_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i8x16_shr_s, builtin_i8x16_shr_s); + +// i8x16.shr_u -> v128.shr +function builtin_i8x16_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i8x16_shr_u, builtin_i8x16_shr_u); + +// i8x16.any_true -> v128.any_true +function builtin_i8x16_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i8x16_any_true, builtin_i8x16_any_true); + +// i8x16.all_true -> v128.all_true +function builtin_i8x16_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i8x16_all_true, builtin_i8x16_all_true); + +// i8x16.eq -> v128.eq +function builtin_i8x16_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i8x16_eq, builtin_i8x16_eq); + +// i8x16.ne -> v128.ne +function builtin_i8x16_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i8x16_ne, builtin_i8x16_ne); + +// i8x16.lt_s -> v128.lt +function builtin_i8x16_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i8x16_lt_s, builtin_i8x16_lt_s); + +// i8x16.lt_u -> v128.lt +function builtin_i8x16_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i8x16_lt_u, builtin_i8x16_lt_u); + +// i8x16.le_s -> v128.le +function builtin_i8x16_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i8x16_le_s, builtin_i8x16_le_s); + +// i8x16.le_u -> v128.le +function builtin_i8x16_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i8x16_le_u, builtin_i8x16_le_u); + +// i8x16.gt_s -> v128.gt +function builtin_i8x16_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i8x16_gt_s, builtin_i8x16_gt_s); + +// i8x16.gt_u -> v128.gt +function builtin_i8x16_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i8x16_gt_u, builtin_i8x16_gt_u); + +// i8x16.ge_s -> v128.ge +function builtin_i8x16_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i8x16_ge_s, builtin_i8x16_ge_s); + +// i8x16.ge_u -> v128.ge +function builtin_i8x16_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i8x16_ge_u, builtin_i8x16_ge_u); + +// i8x16.narrow_i16x8_s -> v128.narrow +function builtin_i8x16_narrow_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i8x16_narrow_i16x8_s, builtin_i8x16_narrow_i16x8_s); + +// i8x16.narrow_i16x8_u -> v128.narrow +function builtin_i8x16_narrow_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i8x16_narrow_i16x8_u, builtin_i8x16_narrow_i16x8_u); + +// i16x8.splat -> v128.splat +function builtin_i16x8_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i16x8_splat, builtin_i16x8_splat); + +// i16x8.extract_lane_s -> v128.extract_lane +function builtin_i16x8_extract_lane_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_extract_lane_s, builtin_i16x8_extract_lane_s); + +// i16x8..extract_lane_u -> v128.extract_lane +function builtin_i16x8_extract_lane_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_extract_lane_u, builtin_i16x8_extract_lane_u); + +// i16x8.replace_lane -> v128.replace_lane +function builtin_i16x8_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i16x8_replace_lane, builtin_i16x8_replace_lane); + +// i16x8.add -> v128.add +function builtin_i16x8_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i16x8_add, builtin_i16x8_add); + +// i16x8.sub -> v128.sub +function builtin_i16x8_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i16x8_sub, builtin_i16x8_sub); + +// i16x8.mul -> v128.mul +function builtin_i16x8_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i16x8_mul, builtin_i16x8_mul); + +// i16x8.min_s -> v128.min +function builtin_i16x8_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i16x8_min_s, builtin_i16x8_min_s); + +// i16x8.min_u -> v128.min +function builtin_i16x8_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i16x8_min_u, builtin_i16x8_min_u); + +// i16x8.max_s -> v128.max +function builtin_i16x8_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i16x8_max_s, builtin_i16x8_max_s); + +// i16x8.max_u -> v128.max +function builtin_i16x8_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.i16x8_max_u, builtin_i16x8_max_u); + +// i16x8.avgr_u -> v128.avgr +function builtin_i16x8_avgr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_avgr(ctx); +} +builtins.set(BuiltinNames.i16x8_avgr_u, builtin_i16x8_avgr_u); + +// i16x8.neg -> v128.neg +function builtin_i16x8_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i16x8_neg, builtin_i16x8_neg); + +// i16x8.add_saturate_s -> v128.add_saturate +function builtin_i16x8_add_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_add_saturate_s, builtin_i16x8_add_saturate_s); + +// i16x8.add_saturate_u -> v128.add_saturate +function builtin_i16x8_add_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_add_saturate_u, builtin_i16x8_add_saturate_u); + +// i16x8.sub_saturate_s -> v128.sub_saturate +function builtin_i16x8_sub_saturate_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_sub_saturate_s, builtin_i16x8_sub_saturate_s); + +// i16x8.sub_saturate_u -> v128.sub_saturate +function builtin_i16x8_sub_saturate_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub_saturate(ctx); +} +builtins.set(BuiltinNames.i16x8_sub_saturate_u, builtin_i16x8_sub_saturate_u); + +// i16x8.shl -> v128.shl +function builtin_i16x8_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i16x8_shl, builtin_i16x8_shl); + +// i16x8.shr_s -> v128.shr +function builtin_i16x8_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i16x8_shr_s, builtin_i16x8_shr_s); + +// i16x8.shr_u -> v128.shr +function builtin_i16x8_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i16x8_shr_u, builtin_i16x8_shr_u); + +// i16x8.any_true -> v128.any_true +function builtin_i16x8_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i16x8_any_true, builtin_i16x8_any_true); + +// i16x8.all_true -> v128.all_true +function builtin_i16x8_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i16x8_all_true, builtin_i16x8_all_true); + +// i16x8.eq -> v128.eq +function builtin_i16x8_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i16x8_eq, builtin_i16x8_eq); + +// i16x8.ne -> v128.ne +function builtin_i16x8_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i16x8_ne, builtin_i16x8_ne); + +// i16x8.lt_s -> v128.lt +function builtin_i16x8_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i16x8_lt_s, builtin_i16x8_lt_s); + +// i16x8.lt_u -> v128.lt +function builtin_i16x8_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i16x8_lt_u, builtin_i16x8_lt_u); + +// i16x8.le_s -> v128.le +function builtin_i16x8_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i16x8_le_s, builtin_i16x8_le_s); + +// i16x8.le_u -> v128.le +function builtin_i16x8_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i16x8_le_u, builtin_i16x8_le_u); + +// i16x8.gt_s -> v128.gt +function builtin_i16x8_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i16x8_gt_s, builtin_i16x8_gt_s); + +// i16x8.gt_u -> v128.gt +function builtin_i16x8_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i16x8_gt_u, builtin_i16x8_gt_u); + +// i16x8.ge_s -> v128.ge +function builtin_i16x8_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i16x8_ge_s, builtin_i16x8_ge_s); + +// i16x8.ge_u -> v128.ge +function builtin_i16x8_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i16x8_ge_u, builtin_i16x8_ge_u); + +// i16x8.narrow_i32x4_s -> v128.narrow +function builtin_i16x8_narrow_i32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i16x8_narrow_i32x4_s, builtin_i16x8_narrow_i32x4_s); + +// i16x8.narrow_i32x4_u -> v128.narrow +function builtin_i16x8_narrow_i32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_narrow(ctx); +} +builtins.set(BuiltinNames.i16x8_narrow_i32x4_u, builtin_i16x8_narrow_i32x4_u); + +// i16x8.widen_low_i8x16_s -> v128.widen_low +function builtin_i16x8_widen_low_i8x16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_low_i8x16_s, builtin_i16x8_widen_low_i8x16_s); + +// i16x8.widen_low_i8x16_u -> v128.widen_low +function builtin_i16x8_widen_low_i8x16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_low_i8x16_u, builtin_i16x8_widen_low_i8x16_u); + +// i16x8.widen_high_i8x16_s -> v128.widen_high +function builtin_i16x8_widen_high_i8x16_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_high_i8x16_s, builtin_i16x8_widen_high_i8x16_s); + +// i16x8.widen_high_i8x16_u -> v128.widen_high +function builtin_i16x8_widen_high_i8x16_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i16x8_widen_high_i8x16_u, builtin_i16x8_widen_high_i8x16_u); + +// i16x8.load8x8_s -> v128.load_ext +function builtin_i16x8_load8x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i16x8_load8x8_s, builtin_i16x8_load8x8_s); + +// i16x8.load8x8_u -> v128.load_ext +function builtin_i16x8_load8x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i16x8_load8x8_u, builtin_i16x8_load8x8_u); + +// i32x4.splat -> v128.splat +function builtin_i32x4_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i32x4_splat, builtin_i32x4_splat); + +// i32x4.extract_lane -> v128.extract_lane +function builtin_i32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i32x4_extract_lane, builtin_i32x4_extract_lane); + +// i32x4.replace_lane -> v128.replace_lane +function builtin_i32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i32x4_replace_lane, builtin_i32x4_replace_lane); + +// i32x4.add -> v128.add +function builtin_i32x4_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i32x4_add, builtin_i32x4_add); + +// i32x4.sub -> v128.sub +function builtin_i32x4_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i32x4_sub, builtin_i32x4_sub); + +// i32x4.mul -> v128.mul +function builtin_i32x4_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.i32x4_mul, builtin_i32x4_mul); - // === Internal runtime ======================================================================= +// i32x4.min_s -> v128.min +function builtin_i32x4_min_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i32x4_min_s, builtin_i32x4_min_s); - case BuiltinNames.idof: { - let type = evaluateConstantType(compiler, typeArguments, operands, reportNode); - compiler.currentType = Type.u32; - if (!type) return module.unreachable(); - if (type.is(TypeFlags.REFERENCE)) { - let signatureReference = type.signatureReference; - if (signatureReference) { - return module.i32(signatureReference.id); - } - let classReference = type.classReference; - if (classReference !== null && !classReference.hasDecorator(DecoratorFlags.UNMANAGED)) { - return module.i32(classReference.id); - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "idof", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.visit_globals: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 1, reportNode, compiler) // cookie - ) { - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], Type.u32, Constraints.CONV_IMPLICIT); - compiler.runtimeFeatures |= RuntimeFeatures.visitGlobals; - compiler.currentType = Type.void; - return module.call(BuiltinNames.visit_globals, [ arg0 ], NativeType.None); - } - case BuiltinNames.visit_members: { - if ( - checkTypeAbsent(typeArguments, reportNode, prototype) | - checkArgsRequired(operands, 2, reportNode, compiler) // ref, cookie - ) { - compiler.currentType = Type.void; - return module.unreachable(); - } - let arg0 = compiler.compileExpression(operands[0], compiler.options.usizeType, Constraints.CONV_IMPLICIT); - let arg1 = compiler.compileExpression(operands[1], Type.u32, Constraints.CONV_IMPLICIT); - compiler.runtimeFeatures |= RuntimeFeatures.visitMembers; - compiler.currentType = Type.void; - return module.call(BuiltinNames.visit_members, [ arg0, arg1 ], NativeType.None); - } - case BuiltinNames.isNaN: { - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // never NaN - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: { - return hasSideEffects(arg0) - ? module.block(null, [ - module.drop(arg0), - module.i32(0) - ], NativeType.I32) - : module.i32(0); - } - // (t = arg0) != t - case TypeKind.F32: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.NeF32, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F32) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f32); - let ret = module.binary(BinaryOp.NeF32, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F32) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.NeF64, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F64) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f64); - let ret = module.binary(BinaryOp.NeF64, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F64) - ); - flow.freeTempLocal(temp); - return ret; - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "isNaN", type.toString() - ); - return module.unreachable(); - } - case BuiltinNames.isFinite: { - if ( - checkTypeOptional(typeArguments, reportNode, compiler) | - checkArgsRequired(operands, 1, reportNode, compiler) - ) { - compiler.currentType = Type.bool; - return module.unreachable(); - } - let arg0 = typeArguments - ? compiler.compileExpression(operands[0], typeArguments[0], Constraints.CONV_IMPLICIT) - : compiler.compileExpression(operands[0], Type.auto); - let type = compiler.currentType; - compiler.currentType = Type.bool; - if (!type.is(TypeFlags.REFERENCE)) { - switch (type.kind) { - // always finite - case TypeKind.I8: - case TypeKind.I16: - case TypeKind.I32: - case TypeKind.I64: - case TypeKind.ISIZE: - case TypeKind.U8: - case TypeKind.U16: - case TypeKind.U32: - case TypeKind.U64: - case TypeKind.USIZE: { - return hasSideEffects(arg0) - ? module.block(null, [ - module.drop(arg0), - module.i32(1) - ], NativeType.I32) - : module.i32(1); - } - // (t = arg0) - t == 0 - case TypeKind.F32: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.EqF32, - module.binary(BinaryOp.SubF32, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F32) - ), - module.f32(0) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f32); - let ret = module.binary(BinaryOp.EqF32, - module.binary(BinaryOp.SubF32, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F32) - ), - module.f32(0) - ); - flow.freeTempLocal(temp); - return ret; - } - case TypeKind.F64: { - if (getExpressionId(arg0) == ExpressionId.LocalGet) { - return module.binary(BinaryOp.EqF64, - module.binary(BinaryOp.SubF64, - arg0, - module.local_get(getLocalGetIndex(arg0), NativeType.F64) - ), - module.f64(0) - ); - } - let flow = compiler.currentFlow; - let temp = flow.getTempLocal(Type.f64); - let ret = module.binary(BinaryOp.EqF64, - module.binary(BinaryOp.SubF64, - module.local_tee(temp.index, arg0), - module.local_get(temp.index, NativeType.F64) - ), - module.f64(0) - ); - flow.freeTempLocal(temp); - return ret; - } - } - } - compiler.error( - DiagnosticCode.Operation_0_cannot_be_applied_to_type_1, - reportNode.typeArgumentsRange, "isFinite", type.toString() - ); - return module.unreachable(); - } - } +// i32x4.min_u -> v128.min +function builtin_i32x4_min_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.i32x4_min_u, builtin_i32x4_min_u); - // try to defer inline asm to a concrete built-in - { - let expr = tryDeferASM(compiler, prototype, operands, reportNode); - if (expr) { - if (typeArguments) { - compiler.error( - DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName - ); - } - return expr; - } - } - compiler.error( - DiagnosticCode.Not_implemented, - reportNode.expression.range - ); - return module.unreachable(); +// i32x4.max_s -> v128.max +function builtin_i32x4_max_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); } +builtins.set(BuiltinNames.i32x4_max_s, builtin_i32x4_max_s); -/** Tries to defer an inline-assembler-like call to a built-in function. */ -function tryDeferASM( - compiler: Compiler, - prototype: FunctionPrototype, - operands: Expression[], - reportNode: CallExpression -): ExpressionRef { - /* tslint:disable:max-line-length */ - switch (prototype.internalName) { - - // TODO: Operators can't be just deferred (don't have a corresponding generic built-in) - // add, sub, mul, div_s, div_u, rem_s, rem_u - // and, or, xor, shl, shr_u, shr_s - // eq, eqz, ne, lt_s, lt_u, le_s, le_u, gt_s, gt_u, ge_s, ge_u - - case BuiltinNames.i32_clz: return deferASM(BuiltinNames.clz, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_clz: return deferASM(BuiltinNames.clz, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_ctz: return deferASM(BuiltinNames.ctz, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_ctz: return deferASM(BuiltinNames.ctz, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_popcnt: return deferASM(BuiltinNames.popcnt, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_popcnt: return deferASM(BuiltinNames.popcnt, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_rotl: return deferASM(BuiltinNames.rotl, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_rotl: return deferASM(BuiltinNames.rotl, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i32_rotr: return deferASM(BuiltinNames.rotr, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_rotr: return deferASM(BuiltinNames.rotr, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_abs: return deferASM(BuiltinNames.abs, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_abs: return deferASM(BuiltinNames.abs, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_max: return deferASM(BuiltinNames.max, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_max: return deferASM(BuiltinNames.max, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_min: return deferASM(BuiltinNames.min, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_min: return deferASM(BuiltinNames.min, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_ceil: return deferASM(BuiltinNames.ceil, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_ceil: return deferASM(BuiltinNames.ceil, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_floor: return deferASM(BuiltinNames.floor, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_floor: return deferASM(BuiltinNames.floor, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_copysign: return deferASM(BuiltinNames.copysign, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_copysign: return deferASM(BuiltinNames.copysign, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_nearest: return deferASM(BuiltinNames.nearest, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_nearest: return deferASM(BuiltinNames.nearest, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_reinterpret_f32: return deferASM(BuiltinNames.reinterpret, compiler, Type.i32, operands, Type.f32, reportNode); - case BuiltinNames.i64_reinterpret_f64: return deferASM(BuiltinNames.reinterpret, compiler, Type.i64, operands, Type.f64, reportNode); - case BuiltinNames.f32_reinterpret_i32: return deferASM(BuiltinNames.reinterpret, compiler, Type.f32, operands, Type.i32, reportNode); - case BuiltinNames.f64_reinterpret_i64: return deferASM(BuiltinNames.reinterpret, compiler, Type.f64, operands, Type.i64, reportNode); - case BuiltinNames.f32_sqrt: return deferASM(BuiltinNames.sqrt, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_sqrt: return deferASM(BuiltinNames.sqrt, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f32_trunc: return deferASM(BuiltinNames.trunc, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_trunc: return deferASM(BuiltinNames.trunc, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_load8_s: return deferASM(BuiltinNames.load, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i32_load8_u: return deferASM(BuiltinNames.load, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_load16_s: return deferASM(BuiltinNames.load, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i32_load16_u: return deferASM(BuiltinNames.load, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_load: return deferASM(BuiltinNames.load, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_load8_s: return deferASM(BuiltinNames.load, compiler, Type.i8, operands, Type.i64, reportNode); - case BuiltinNames.i64_load8_u: return deferASM(BuiltinNames.load, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_load16_s: return deferASM(BuiltinNames.load, compiler, Type.i16, operands, Type.i64, reportNode); - case BuiltinNames.i64_load16_u: return deferASM(BuiltinNames.load, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_load32_s: return deferASM(BuiltinNames.load, compiler, Type.i32, operands, Type.i64, reportNode); - case BuiltinNames.i64_load32_u: return deferASM(BuiltinNames.load, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_load: return deferASM(BuiltinNames.load, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_load: return deferASM(BuiltinNames.load, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_load: return deferASM(BuiltinNames.load, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.i32_store8: return deferASM(BuiltinNames.store, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i32_store16: return deferASM(BuiltinNames.store, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i32_store: return deferASM(BuiltinNames.store, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_store8: return deferASM(BuiltinNames.store, compiler, Type.i8, operands, Type.i64, reportNode); - case BuiltinNames.i64_store16: return deferASM(BuiltinNames.store, compiler, Type.i16, operands, Type.i64, reportNode); - case BuiltinNames.i64_store32: return deferASM(BuiltinNames.store, compiler, Type.i32, operands, Type.i64, reportNode); - case BuiltinNames.i64_store: return deferASM(BuiltinNames.store, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.f32_store: return deferASM(BuiltinNames.store, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f64_store: return deferASM(BuiltinNames.store, compiler, Type.f64, operands, Type.f64, reportNode); - - case BuiltinNames.i32_atomic_load8_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_load16_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_load: return deferASM(BuiltinNames.atomic_load, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_load8_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load16_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load32_u: return deferASM(BuiltinNames.atomic_load, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_load: return deferASM(BuiltinNames.atomic_load, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_store8: return deferASM(BuiltinNames.atomic_store, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_store16: return deferASM(BuiltinNames.atomic_store, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_store: return deferASM(BuiltinNames.atomic_store, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_store8: return deferASM(BuiltinNames.atomic_store, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store16: return deferASM(BuiltinNames.atomic_store, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store32: return deferASM(BuiltinNames.atomic_store, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_store: return deferASM(BuiltinNames.atomic_store, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_add: return deferASM(BuiltinNames.atomic_add, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_add_u: return deferASM(BuiltinNames.atomic_add, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_add: return deferASM(BuiltinNames.atomic_add, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_sub: return deferASM(BuiltinNames.atomic_sub, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_sub_u: return deferASM(BuiltinNames.atomic_sub, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_sub: return deferASM(BuiltinNames.atomic_sub, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_and: return deferASM(BuiltinNames.atomic_and, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_and_u: return deferASM(BuiltinNames.atomic_and, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_and: return deferASM(BuiltinNames.atomic_and, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_or: return deferASM(BuiltinNames.atomic_or, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_or_u: return deferASM(BuiltinNames.atomic_or, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_or: return deferASM(BuiltinNames.atomic_or, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_xor: return deferASM(BuiltinNames.atomic_xor, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_xor_u: return deferASM(BuiltinNames.atomic_xor, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_xor: return deferASM(BuiltinNames.atomic_xor, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_xchg: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_xchg_u: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_xchg: return deferASM(BuiltinNames.atomic_xchg, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_atomic_rmw8_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u8, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw16_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u16, operands, Type.i32, reportNode); - case BuiltinNames.i32_atomic_rmw_cmpxchg: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_atomic_rmw8_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u8, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw16_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u16, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw32_cmpxchg_u: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.u32, operands, Type.i64, reportNode); - case BuiltinNames.i64_atomic_rmw_cmpxchg: return deferASM(BuiltinNames.atomic_cmpxchg, compiler, Type.i64, operands, Type.i64, reportNode); - - case BuiltinNames.i32_wait: return deferASM(BuiltinNames.atomic_wait, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i64_wait: return deferASM(BuiltinNames.atomic_wait, compiler, Type.i64, operands, Type.i32, reportNode); - - case BuiltinNames.v128_load: return deferASM(BuiltinNames.load, compiler, Type.v128, operands, Type.v128, reportNode); - case BuiltinNames.v128_store: return deferASM(BuiltinNames.store, compiler, Type.v128, operands, Type.v128, reportNode); - - case BuiltinNames.i8x16_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_extract_lane_s: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i8, operands, Type.i8, reportNode); - case BuiltinNames.i8x16_extract_lane_u: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.u8, operands, Type.u8, reportNode); - case BuiltinNames.i8x16_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_avgr_u: return deferASM(BuiltinNames.v128_avgr, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add_saturate_s: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_add_saturate_u: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub_saturate_s: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_sub_saturate_u: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i8x16_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i8, operands, Type.i32, reportNode); - case BuiltinNames.i8x16_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_narrow_i16x8_s: return deferASM(BuiltinNames.v128_narrow, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i8x16_narrow_i16x8_u: return deferASM(BuiltinNames.v128_narrow, compiler, Type.u16, operands, Type.v128, reportNode); - - case BuiltinNames.i16x8_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_extract_lane_s: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i16, operands, Type.i16, reportNode); - case BuiltinNames.i16x8_extract_lane_u: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.u16, operands, Type.u16, reportNode); - case BuiltinNames.i16x8_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_avgr_u: return deferASM(BuiltinNames.v128_avgr, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add_saturate_s: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_add_saturate_u: return deferASM(BuiltinNames.v128_add_saturate, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub_saturate_s: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_sub_saturate_u: return deferASM(BuiltinNames.v128_sub_saturate, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i16x8_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i16, operands, Type.i32, reportNode); - case BuiltinNames.i16x8_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_narrow_i32x4_s: return deferASM(BuiltinNames.v128_narrow, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_narrow_i32x4_u: return deferASM(BuiltinNames.v128_narrow, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_low_i8x16_s: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_low_i8x16_u: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_high_i8x16_s: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_widen_high_i8x16_u: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_load8x8_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.i16x8_load8x8_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u8, operands, Type.v128, reportNode); - - case BuiltinNames.i32x4_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_min_s: return deferASM(BuiltinNames.v128_min, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_min_u: return deferASM(BuiltinNames.v128_min, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_max_s: return deferASM(BuiltinNames.v128_max, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_max_u: return deferASM(BuiltinNames.v128_max, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_dot_i16x8_s: return deferASM(BuiltinNames.v128_dot, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i32, operands, Type.i32, reportNode); - case BuiltinNames.i32x4_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_lt_s: return deferASM(BuiltinNames.v128_lt, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_lt_u: return deferASM(BuiltinNames.v128_lt, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_le_s: return deferASM(BuiltinNames.v128_le, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_le_u: return deferASM(BuiltinNames.v128_le, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_gt_s: return deferASM(BuiltinNames.v128_gt, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_gt_u: return deferASM(BuiltinNames.v128_gt, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ge_s: return deferASM(BuiltinNames.v128_ge, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_ge_u: return deferASM(BuiltinNames.v128_ge, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_trunc_sat_f32x4_s: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_trunc_sat_f32x4_u: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_low_i16x8_s: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_low_i16x8_u: return deferASM(BuiltinNames.v128_widen_low, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_high_i16x8_s: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_widen_high_i16x8_u: return deferASM(BuiltinNames.v128_widen_high, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_load16x4_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i16, operands, Type.v128, reportNode); - case BuiltinNames.i32x4_load16x4_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u16, operands, Type.v128, reportNode); - - case BuiltinNames.i64x2_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.i64, operands, Type.i64, reportNode); - case BuiltinNames.i64x2_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_add: return deferASM(BuiltinNames.v128_add, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shl: return deferASM(BuiltinNames.v128_shl, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shr_s: return deferASM(BuiltinNames.v128_shr, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_shr_u: return deferASM(BuiltinNames.v128_shr, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_any_true: return deferASM(BuiltinNames.v128_any_true, compiler, Type.i64, operands, Type.i32, reportNode); - case BuiltinNames.i64x2_all_true: return deferASM(BuiltinNames.v128_all_true, compiler, Type.i64, operands, Type.i32, reportNode); - case BuiltinNames.i64x2_trunc_sat_f64x2_s: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_trunc_sat_f64x2_u: return deferASM(BuiltinNames.v128_trunc_sat, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_load32x2_s: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.i64x2_load32x2_u: return deferASM(BuiltinNames.v128_load_ext, compiler, Type.u32, operands, Type.v128, reportNode); - - case BuiltinNames.f32x4_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.f32, operands, Type.f32, reportNode); - case BuiltinNames.f32x4_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_add: return deferASM(BuiltinNames.v128_add, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_div: return deferASM(BuiltinNames.v128_div, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_min: return deferASM(BuiltinNames.v128_min, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_max: return deferASM(BuiltinNames.v128_max, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_abs: return deferASM(BuiltinNames.v128_abs, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_sqrt: return deferASM(BuiltinNames.v128_sqrt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_lt: return deferASM(BuiltinNames.v128_lt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_le: return deferASM(BuiltinNames.v128_le, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_gt: return deferASM(BuiltinNames.v128_gt, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_ge: return deferASM(BuiltinNames.v128_ge, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_convert_i32x4_s: return deferASM(BuiltinNames.v128_convert, compiler, Type.i32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_convert_i32x4_u: return deferASM(BuiltinNames.v128_convert, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_qfma: return deferASM(BuiltinNames.v128_qfma, compiler, Type.f32, operands, Type.v128, reportNode); - case BuiltinNames.f32x4_qfms: return deferASM(BuiltinNames.v128_qfms, compiler, Type.f32, operands, Type.v128, reportNode); - - case BuiltinNames.f64x2_splat: return deferASM(BuiltinNames.v128_splat, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_extract_lane: return deferASM(BuiltinNames.v128_extract_lane, compiler, Type.f64, operands, Type.f64, reportNode); - case BuiltinNames.f64x2_replace_lane: return deferASM(BuiltinNames.v128_replace_lane, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_add: return deferASM(BuiltinNames.v128_add, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_sub: return deferASM(BuiltinNames.v128_sub, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_mul: return deferASM(BuiltinNames.v128_mul, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_div: return deferASM(BuiltinNames.v128_div, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_neg: return deferASM(BuiltinNames.v128_neg, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_min: return deferASM(BuiltinNames.v128_min, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_max: return deferASM(BuiltinNames.v128_max, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_abs: return deferASM(BuiltinNames.v128_abs, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_sqrt: return deferASM(BuiltinNames.v128_sqrt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_eq: return deferASM(BuiltinNames.v128_eq, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_ne: return deferASM(BuiltinNames.v128_ne, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_lt: return deferASM(BuiltinNames.v128_lt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_le: return deferASM(BuiltinNames.v128_le, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_gt: return deferASM(BuiltinNames.v128_gt, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_ge: return deferASM(BuiltinNames.v128_ge, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_convert_i64x2_s: return deferASM(BuiltinNames.v128_convert, compiler, Type.i64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_convert_i64x2_u: return deferASM(BuiltinNames.v128_convert, compiler, Type.u64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_qfma: return deferASM(BuiltinNames.v128_qfma, compiler, Type.f64, operands, Type.v128, reportNode); - case BuiltinNames.f64x2_qfms: return deferASM(BuiltinNames.v128_qfms, compiler, Type.f64, operands, Type.v128, reportNode); - - case BuiltinNames.v8x16_shuffle: return deferASM(BuiltinNames.v128_shuffle, compiler, Type.i8, operands, Type.v128, reportNode); - case BuiltinNames.v8x16_swizzle: return deferASM(BuiltinNames.v128_swizzle, compiler, null, operands, Type.v128, reportNode); - case BuiltinNames.v8x16_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u8, operands, Type.v128, reportNode); - case BuiltinNames.v16x8_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u16, operands, Type.v128, reportNode); - case BuiltinNames.v32x4_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u32, operands, Type.v128, reportNode); - case BuiltinNames.v64x2_load_splat: return deferASM(BuiltinNames.v128_load_splat, compiler, Type.u64, operands, Type.v128, reportNode); - } - /* tslint:enable:max-line-length */ - return 0; +// i32x4.max_u -> v128.max +function builtin_i32x4_max_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); } +builtins.set(BuiltinNames.i32x4_max_u, builtin_i32x4_max_u); -/** A helper for deferring inline-assembler-like calls to built-in functions. */ -function deferASM( - name: string, - compiler: Compiler, - typeArgument: Type | null, - operands: Expression[], - contextualType: Type, - reportNode: CallExpression -): ExpressionRef { - assert(compiler.program.elementsByName.has(name)); - var prototype = compiler.program.elementsByName.get(name)!; - assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); - return compileCall( - compiler, - prototype, - typeArgument ? [ typeArgument ] : null, - operands, - contextualType, - reportNode, - /* isAsm */ true - ); +// i32x4.dot_i16x8_s -> v128.dot +function builtin_i32x4_dot_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_dot(ctx); +} +builtins.set(BuiltinNames.i32x4_dot_i16x8_s, builtin_i32x4_dot_i16x8_s); + +// i32x4.neg -> v128.neg +function builtin_i32x4_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i32x4_neg, builtin_i32x4_neg); + +// i32x4.shl -> v128.shl +function builtin_i32x4_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i32x4_shl, builtin_i32x4_shl); + +// i32x4.shr_s -> v128.shr +function builtin_i32x4_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i32x4_shr_s, builtin_i32x4_shr_s); + +// i32x4.shr_u -> v128.shr +function builtin_i32x4_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i32x4_shr_u, builtin_i32x4_shr_u); + +// i32x4.any_true -> v128.any_true +function builtin_i32x4_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i32x4_any_true, builtin_i32x4_any_true); + +// i32x4.all_true -> v128.all_true +function builtin_i32x4_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i32x4_all_true, builtin_i32x4_all_true); + +// i32x4.eq -> v128.eq +function builtin_i32x4_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.i32x4_eq, builtin_i32x4_eq); + +// i32x4.ne -> v128.ne +function builtin_i32x4_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.i32x4_ne, builtin_i32x4_ne); + +// i32x4.lt_s -> v128.lt +function builtin_i32x4_lt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i32x4_lt_s, builtin_i32x4_lt_s); + +// i32x4.lt_u -> v128.lt +function builtin_i32x4_lt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.i32x4_lt_u, builtin_i32x4_lt_u); + +// i32x4.le_s -> v128.le +function builtin_i32x4_le_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i32x4_le_s, builtin_i32x4_le_s); + +// i32x4.le_u -> v128.le +function builtin_i32x4_le_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.i32x4_le_u, builtin_i32x4_le_u); + +// i32x4.gt_s -> v128.gt +function builtin_i32x4_gt_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i32x4_gt_s, builtin_i32x4_gt_s); + +// i32x4.gt_u -> v128.gt +function builtin_i32x4_gt_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.i32x4_gt_u, builtin_i32x4_gt_u); + +// i32x4.ge_s -> v128.ge +function builtin_i32x4_ge_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i32x4_ge_s, builtin_i32x4_ge_s); + +// i32x4.ge_u -> v128.ge +function builtin_i32x4_ge_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.i32x4_ge_u, builtin_i32x4_ge_u); + +// i32x4.trunc_sat_f32x4_s -> v128.trunc_sat +function builtin_i32x4_trunc_sat_f32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_s, builtin_i32x4_trunc_sat_f32x4_s); + +// i32x4.trunc_sat_f32x4_u -> v128.trunc_sat +function builtin_i32x4_trunc_sat_f32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i32x4_trunc_sat_f32x4_u, builtin_i32x4_trunc_sat_f32x4_u); + +// i32x4.widen_low_i16x8_s -> // v128.widen_low +function builtin_i32x4_widen_low_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_low_i16x8_s, builtin_i32x4_widen_low_i16x8_s); + +// i32x4.widen_low_i16x8_u -> v128.widen_low +function builtin_i32x4_widen_low_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_low(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_low_i16x8_u, builtin_i32x4_widen_low_i16x8_u); + +// i32x4.widen_high_i16x8_s -> v128.widen_high +function builtin_i32x4_widen_high_i16x8_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_high_i16x8_s, builtin_i32x4_widen_high_i16x8_s); + +// i32x4.widen_high_i16x8_u -> v128.widen_high +function builtin_i32x4_widen_high_i16x8_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_widen_high(ctx); +} +builtins.set(BuiltinNames.i32x4_widen_high_i16x8_u, builtin_i32x4_widen_high_i16x8_u); + +// i32x4.load16x4_s -> v128.load_ext +function builtin_i32x4_load16x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i32x4_load16x4_s, builtin_i32x4_load16x4_s); + +// i32x4.load16x4_u -> v128.load_ext +function builtin_i32x4_load16x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i32x4_load16x4_u, builtin_i32x4_load16x4_u); + +// i64x2.splat -> v128.splat +function builtin_i64x2_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.i64x2_splat, builtin_i64x2_splat); + +// i64x2.extract_lane -> v128.extract_lane +function builtin_i64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i64; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.i64x2_extract_lane, builtin_i64x2_extract_lane); + +// i64x2.replace_lane -> v128.replace_lane +function builtin_i64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.i64x2_replace_lane, builtin_i64x2_replace_lane); + +// i64x2.add -> v128.add +function builtin_i64x2_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.i64x2_add, builtin_i64x2_add); + +// i64x2.sub -> v128.sub +function builtin_i64x2_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.i64x2_sub, builtin_i64x2_sub); + +// i64x2.neg -> v128.neg +function builtin_i64x2_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.i64x2_neg, builtin_i64x2_neg); + +// i64x2.shl -> v128.shl +function builtin_i64x2_shl(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shl(ctx); +} +builtins.set(BuiltinNames.i64x2_shl, builtin_i64x2_shl); + +// i64x2.shr_s -> v128.shr +function builtin_i64x2_shr_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i64x2_shr_s, builtin_i64x2_shr_s); + +// i64x2.shr_u -> v128.shr +function builtin_i64x2_shr_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shr(ctx); +} +builtins.set(BuiltinNames.i64x2_shr_u, builtin_i64x2_shr_u); + +// i64x2.any_true -> v128.any_true +function builtin_i64x2_any_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_v128_any_true(ctx); +} +builtins.set(BuiltinNames.i64x2_any_true, builtin_i64x2_any_true); + +// i64x2.all_true -> v128.all_true +function builtin_i64x2_all_true(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.i32; + return builtin_v128_all_true(ctx); +} +builtins.set(BuiltinNames.i64x2_all_true, builtin_i64x2_all_true); + +// i64x2.trunc_sat_f64x2_s -> v128.trunc_sat +function builtin_i64x2_trunc_sat_f64x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_s, builtin_i64x2_trunc_sat_f64x2_s); + +// i64x2.trunc_sat_f64x2_u -> v128.trunc_sat +function builtin_i64x2_trunc_sat_f64x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_trunc_sat(ctx); +} +builtins.set(BuiltinNames.i64x2_trunc_sat_f64x2_u, builtin_i64x2_trunc_sat_f64x2_u); + +// i64x2.load32x2_s -> v128.load_ext +function builtin_i64x2_load32x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i64x2_load32x2_s, builtin_i64x2_load32x2_s); + +// i64x2.load32x2_u -> v128.load_ext +function builtin_i64x2_load32x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_ext(ctx); +} +builtins.set(BuiltinNames.i64x2_load32x2_u, builtin_i64x2_load32x2_u); + +// f32x4.splat -> v128.splat +function builtin_f32x4_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.f32x4_splat, builtin_f32x4_splat); + +// f32x4.extract_lane -> v128.extract_lane +function builtin_f32x4_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.f32; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.f32x4_extract_lane, builtin_f32x4_extract_lane); + +// f32x4.replace_lane -> v128.replace_lane +function builtin_f32x4_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.f32x4_replace_lane, builtin_f32x4_replace_lane); + +// f32x4.add -> v128.add +function builtin_f32x4_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.f32x4_add, builtin_f32x4_add); + +// f32x4.sub -> v128.sub +function builtin_f32x4_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.f32x4_sub, builtin_f32x4_sub); + +// f32x4.mul -> v128.mul +function builtin_f32x4_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.f32x4_mul, builtin_f32x4_mul); + +// f32x4.div -> v128.div +function builtin_f32x4_div(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_div(ctx); +} +builtins.set(BuiltinNames.f32x4_div, builtin_f32x4_div); + +// f32x4.neg -> v128.neg +function builtin_f32x4_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.f32x4_neg, builtin_f32x4_neg); + +// f32x4.min -> v128.min +function builtin_f32x4_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.f32x4_min, builtin_f32x4_min); + +// f32x4.max -> v128.max +function builtin_f32x4_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.f32x4_max, builtin_f32x4_max); + +// f32x4.abs -> v128.abs +function builtin_f32x4_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_abs(ctx); +} +builtins.set(BuiltinNames.f32x4_abs, builtin_f32x4_abs); + +// f32x4.sqrt -> v128.sqrt +function builtin_f32x4_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sqrt(ctx); +} +builtins.set(BuiltinNames.f32x4_sqrt, builtin_f32x4_sqrt); + +// f32x4.eq -> v128.eq +function builtin_f32x4_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.f32x4_eq, builtin_f32x4_eq); + +// f32x4.ne -> v128.ne +function builtin_f32x4_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.f32x4_ne, builtin_f32x4_ne); + +// f32x4.lt -> v128.lt +function builtin_f32x4_lt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.f32x4_lt, builtin_f32x4_lt); + +// f32x4.le -> v128.le +function builtin_f32x4_le(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.f32x4_le, builtin_f32x4_le); + +// f32x4.gt -> v128.gt +function builtin_f32x4_gt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.f32x4_gt, builtin_f32x4_gt); + +// f32x4.ge -> v128.ge +function builtin_f32x4_ge(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.f32x4_ge, builtin_f32x4_ge); + +// f32x4.convert_i32x4_s -> v128.convert +function builtin_f32x4_convert_i32x4_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f32x4_convert_i32x4_s, builtin_f32x4_convert_i32x4_s); + +// f32x4.convert_i32x4_u -> v128.convert +function builtin_f32x4_convert_i32x4_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f32x4_convert_i32x4_u, builtin_f32x4_convert_i32x4_u); + +// f32x4.qfma -> v128.qfma +function builtin_f32x4_qfma(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfma(ctx); +} +builtins.set(BuiltinNames.f32x4_qfma, builtin_f32x4_qfma); + +// f32x4.qfms -> v128.qfms +function builtin_f32x4_qfms(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfms(ctx); +} +builtins.set(BuiltinNames.f32x4_qfms, builtin_f32x4_qfms); + +// f64x2.splat -> v128.splat +function builtin_f64x2_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_splat(ctx); +} +builtins.set(BuiltinNames.f64x2_splat, builtin_f64x2_splat); + +// f64x2.extract_lane -> v128.extract_lane +function builtin_f64x2_extract_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.f64; + return builtin_v128_extract_lane(ctx); +} +builtins.set(BuiltinNames.f64x2_extract_lane, builtin_f64x2_extract_lane); + +// f64x2.replace_lane -> v128.replace_lane +function builtin_f64x2_replace_lane(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_replace_lane(ctx); +} +builtins.set(BuiltinNames.f64x2_replace_lane, builtin_f64x2_replace_lane); + +// f64x2.add -> v128.add +function builtin_f64x2_add(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_add(ctx); +} +builtins.set(BuiltinNames.f64x2_add, builtin_f64x2_add); + +// f64x2.sub -> v128.sub +function builtin_f64x2_sub(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sub(ctx); +} +builtins.set(BuiltinNames.f64x2_sub, builtin_f64x2_sub); + +// f64x2.mul -> v128.mul +function builtin_f64x2_mul(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_mul(ctx); +} +builtins.set(BuiltinNames.f64x2_mul, builtin_f64x2_mul); + +// f64x2.div -> v128.div +function builtin_f64x2_div(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_div(ctx); +} +builtins.set(BuiltinNames.f64x2_div, builtin_f64x2_div); + +// f64x2.neg -> v128.neg +function builtin_f64x2_neg(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_neg(ctx); +} +builtins.set(BuiltinNames.f64x2_neg, builtin_f64x2_neg); + +// f64x2.min -> v128.min +function builtin_f64x2_min(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_min(ctx); +} +builtins.set(BuiltinNames.f64x2_min, builtin_f64x2_min); + +// f64x2.max -> v128.max +function builtin_f64x2_max(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_max(ctx); +} +builtins.set(BuiltinNames.f64x2_max, builtin_f64x2_max); + +// f64x2.abs -> v128.abs +function builtin_f64x2_abs(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_abs(ctx); +} +builtins.set(BuiltinNames.f64x2_abs, builtin_f64x2_abs); + +// f64x2.sqrt -> v128.sqrt +function builtin_f64x2_sqrt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_sqrt(ctx); +} +builtins.set(BuiltinNames.f64x2_sqrt, builtin_f64x2_sqrt); + +// f64x2.eq -> v128.eq +function builtin_f64x2_eq(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_eq(ctx); +} +builtins.set(BuiltinNames.f64x2_eq, builtin_f64x2_eq); + +// f64x2.ne -> v128.ne +function builtin_f64x2_ne(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ne(ctx); +} +builtins.set(BuiltinNames.f64x2_ne, builtin_f64x2_ne); + +// f64x2.lt -> v128.lt +function builtin_f64x2_lt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_lt(ctx); +} +builtins.set(BuiltinNames.f64x2_lt, builtin_f64x2_lt); + +// f64x2.le -> v128.le +function builtin_f64x2_le(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_le(ctx); +} +builtins.set(BuiltinNames.f64x2_le, builtin_f64x2_le); + +// f64x2.gt -> v128.gt +function builtin_f64x2_gt(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_gt(ctx); +} +builtins.set(BuiltinNames.f64x2_gt, builtin_f64x2_gt); + +// f64x2.ge -> v128.ge +function builtin_f64x2_ge(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_ge(ctx); +} +builtins.set(BuiltinNames.f64x2_ge, builtin_f64x2_ge); + +// f64x2.convert_i64x2_s -> v128.convert +function builtin_f64x2_convert_i64x2_s(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f64x2_convert_i64x2_s, builtin_f64x2_convert_i64x2_s); + +// f64x2.convert_i64x2_u -> v128.convert +function builtin_f64x2_convert_i64x2_u(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_convert(ctx); +} +builtins.set(BuiltinNames.f64x2_convert_i64x2_u, builtin_f64x2_convert_i64x2_u); + +// f64x2.qfma -> v128.qfma +function builtin_f64x2_qfma(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfma(ctx); +} +builtins.set(BuiltinNames.f64x2_qfma, builtin_f64x2_qfma); + +// f64x2.qfms -> v128.qfms +function builtin_f64x2_qfms(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.f64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_qfms(ctx); +} +builtins.set(BuiltinNames.f64x2_qfms, builtin_f64x2_qfms); + +// v8x16.shuffle -> v128.shuffle +function builtin_v8x16_shuffle(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.i8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_shuffle(ctx); +} +builtins.set(BuiltinNames.v8x16_shuffle, builtin_v8x16_shuffle); + +// v8x16.swizzle -> v128.swizzle +function builtin_v8x16_swizzle(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = null; + ctx.contextualType = Type.v128; + return builtin_v128_swizzle(ctx); +} +builtins.set(BuiltinNames.v8x16_swizzle, builtin_v8x16_swizzle); + +// v8x16.load_splat -> v128.load_splat +function builtin_v8x16_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u8 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v8x16_load_splat, builtin_v8x16_load_splat); + +// v16x8.load_splat -> v128.load_splat +function builtin_v16x8_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u16 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v16x8_load_splat, builtin_v16x8_load_splat); + +// v32x4.load_splat -> v128.load_splat +function builtin_v32x4_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u32 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); +} +builtins.set(BuiltinNames.v32x4_load_splat, builtin_v32x4_load_splat); + +// v64x2.load_splat -> v128.load_splat +function builtin_v64x2_load_splat(ctx: BuiltinContext): ExpressionRef { + checkTypeAbsent(ctx); + ctx.typeArguments = [ Type.u64 ]; + ctx.contextualType = Type.v128; + return builtin_v128_load_splat(ctx); } +builtins.set(BuiltinNames.v64x2_load_splat, builtin_v64x2_load_splat); + +// === Internal helpers ======================================================================= /** Compiles the `visit_globals` function. */ export function compileVisitGlobals(compiler: Compiler): void { @@ -4738,7 +7671,9 @@ export function compileVisitGlobals(compiler: Compiler): void { // this function is @lazy: make sure it exists compiler.compileFunction(visitInstance, true); - for (let element of compiler.program.elementsByName.values()) { + // TODO: for (let element of compiler.program.elementsByName.values()) { + for (let _values = Map_values(compiler.program.elementsByName), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); if (element.kind != ElementKind.GLOBAL) continue; let global = element; let globalType = global.type; @@ -4818,15 +7753,18 @@ export function compileVisitMembers(compiler: Compiler): void { ); var lastId = 0; - for (let [id, instance] of managedClasses) { + // TODO: for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = _keys[i]; + let instance = assert(managedClasses.get(instanceId)); assert(instance.type.isManaged); - assert(id == lastId++); + assert(instanceId == lastId++); let visitImpl: Element | null; let code = new Array(); // if a library element, check if it implements a custom traversal function - if (instance.isDeclaredInLibrary && (visitImpl = instance.lookupInSelf("__visit_impl"))) { + if (instance.isDeclaredInLibrary && (visitImpl = instance.lookupInSelf("__visit_impl")) !== null) { assert(visitImpl.kind == ElementKind.FUNCTION_PROTOTYPE); let visitFunc = program.resolver.resolveFunction(visitImpl, null); if (!visitFunc || !compiler.compileFunction(visitFunc)) { @@ -4854,7 +7792,9 @@ export function compileVisitMembers(compiler: Compiler): void { } else { let members = instance.members; if (members) { - for (let member of members.values()) { + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), j = 0, l = _values.length; j < l; ++j) { + let member = unchecked(_values[j]); if (member.kind == ElementKind.FIELD) { if ((member).parent === instance) { let fieldType = (member).type; @@ -4886,14 +7826,15 @@ export function compileVisitMembers(compiler: Compiler): void { let block = relooper.addBlock( module.flatten(code) ); - relooper.addBranchForSwitch(outer, block, [ id ]); + relooper.addBranchForSwitch(outer, block, [ instanceId ]); blocks.push(block); } - for (let [id, instance] of managedClasses) { + // TODO: for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = unchecked(_keys[i]); + let instance = assert(managedClasses.get(instanceId)); let base = instance.base; - if (base) { - relooper.addBranch(blocks[id], blocks[base.id]); - } + if (base) relooper.addBranch(blocks[instanceId], blocks[base.id]); } blocks.push( relooper.addBlock( @@ -4935,8 +7876,11 @@ export function compileRTTI(compiler: Compiler): void { var setPrototype = program.setPrototype; var mapPrototype = program.mapPrototype; var lastId = 0; - for (let [id, instance] of managedClasses) { - assert(id == lastId++); + // TODO: for (let [instanceId, instance] of managedClasses) { + for (let _keys = Map_keys(managedClasses), i = 0, k = _keys.length; i < k; ++i) { + let instanceId = unchecked(_keys[i]); + let instance = assert(managedClasses.get(instanceId)); + assert(instanceId == lastId++); let flags: TypeinfoFlags = 0; if (instance.isAcyclic) flags |= TypeinfoFlags.ACYCLIC; if (instance !== abvInstance && instance.extends(abvPrototype)) { @@ -4998,8 +7942,10 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // if (__instanceof(ref, ID[i])) return true var instances = prototype.instances; - if (instances !== null && instances.size) { - for (let instance of instances.values()) { + if (instances !== null && instances.size > 0) { + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); stmts.push( module.if( module.call(instanceofInstance.internalName, [ @@ -5027,28 +7973,26 @@ export function compileClassInstanceOf(compiler: Compiler, prototype: ClassProto // Helpers /** Evaluates the constant type of a type argument *or* expression. */ -function evaluateConstantType( - compiler: Compiler, - typeArguments: Type[] | null, - operands: Expression[], - reportNode: CallExpression -): Type | null { +function evaluateConstantType(ctx: BuiltinContext): Type | null { + var compiler = ctx.compiler; + var operands = ctx.operands; + var typeArguments = ctx.typeArguments; if (operands.length == 0) { // requires type argument if (!typeArguments || typeArguments.length != 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString(10) : "0" + ctx.reportNode.typeArgumentsRange, "1", typeArguments ? typeArguments.length.toString() : "0" ); return null; } return typeArguments[0]; } if (operands.length == 1) { // optional type argument - if (typeArguments !== null && typeArguments.length) { + if (typeArguments !== null && typeArguments.length > 0) { if (typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) + ctx.reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); return null; } @@ -5058,15 +8002,15 @@ function evaluateConstantType( } return compiler.currentType; } - if (typeArguments && typeArguments.length > 1) { + if (typeArguments !== null && typeArguments.length > 1) { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", typeArguments.length.toString(10) + ctx.reportNode.typeArgumentsRange, "1", typeArguments.length.toString() ); } compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.argumentsRange, "1", operands.length.toString(10) + ctx.reportNode.argumentsRange, "1", operands.length.toString() ); return null; } @@ -5107,15 +8051,12 @@ function evaluateImmediateOffset(expression: Expression, compiler: Compiler): i3 } /** Checks that the specified feature is enabled. */ -function checkFeatureEnabled( - feature: Feature, - reportNode: Node, - compiler: Compiler -): i32 { +function checkFeatureEnabled(ctx: BuiltinContext, feature: Feature): i32 { + var compiler = ctx.compiler; if (!compiler.options.hasFeature(feature)) { compiler.error( DiagnosticCode.Feature_0_is_not_enabled, - reportNode.range, featureToString(feature) + ctx.reportNode.range, featureToString(feature) ); return 1; } @@ -5123,12 +8064,9 @@ function checkFeatureEnabled( } /** Checks a call with a single required type argument. Returns `1` on error. */ -function checkTypeRequired( - typeArguments: Type[] | null, - reportNode: CallExpression, - compiler: Compiler, - setCurrentTypeOnError: bool = false -): i32 { +function checkTypeRequired(ctx: BuiltinContext, setCurrentTypeOnError: bool = false): i32 { + var compiler = ctx.compiler; + var typeArguments = ctx.typeArguments; if (typeArguments) { let numTypeArguments = typeArguments.length; if (numTypeArguments == 1) return 0; @@ -5136,32 +8074,29 @@ function checkTypeRequired( if (setCurrentTypeOnError) compiler.currentType = typeArguments[0]; compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", numTypeArguments.toString() + ctx.reportNode.typeArgumentsRange, "1", numTypeArguments.toString() ); } else { compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.range, "1", "0" + ctx.reportNode.range, "1", "0" ); } return 1; } /** Checks a call with a single optional type argument. Returns `1` on error. */ -function checkTypeOptional( - typeArguments: Type[] | null, - reportNode: CallExpression, - compiler: Compiler, - setCurrentTypeOnError: bool = false -): i32 { +function checkTypeOptional(ctx: BuiltinContext, setCurrentTypeOnError: bool = false): i32 { + var typeArguments = ctx.typeArguments; if (typeArguments) { + let compiler = ctx.compiler; let numTypeArguments = typeArguments.length; if (numTypeArguments == 1) return 0; assert(numTypeArguments); // invalid if 0, must not be set at all instead if (setCurrentTypeOnError) compiler.currentType = typeArguments[0]; compiler.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - reportNode.typeArgumentsRange, "1", numTypeArguments.toString() + ctx.reportNode.typeArgumentsRange, "1", numTypeArguments.toString() ); return 1; } @@ -5169,15 +8104,13 @@ function checkTypeOptional( } /** Checks a call that is not generic. Returns `1` on error. */ -function checkTypeAbsent( - typeArguments: Type[] | null, - reportNode: CallExpression, - prototype: FunctionPrototype -): i32 { +function checkTypeAbsent(ctx: BuiltinContext): i32 { + var typeArguments = ctx.typeArguments; if (typeArguments) { + let prototype = ctx.prototype; prototype.program.error( DiagnosticCode.Type_0_is_not_generic, - reportNode.typeArgumentsRange, prototype.internalName + ctx.reportNode.typeArgumentsRange, prototype.internalName ); return 1; } @@ -5185,16 +8118,12 @@ function checkTypeAbsent( } /** Checks a call that requires a fixed number of arguments. Returns `1` on error. */ -function checkArgsRequired( - operands: Expression[], - expected: i32, - reportNode: CallExpression, - compiler: Compiler -): i32 { +function checkArgsRequired(ctx: BuiltinContext, expected: i32): i32 { + var operands = ctx.operands; if (operands.length != expected) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, expected.toString(), operands.length.toString() + ctx.reportNode.range, expected.toString(), operands.length.toString() ); return 1; } @@ -5202,26 +8131,61 @@ function checkArgsRequired( } /** Checks a call that requires a variable number of arguments. Returns `1` on error. */ -function checkArgsOptional( - operands: Expression[], - expectedMinimum: i32, - expectedMaximum: i32, - reportNode: CallExpression, - compiler: Compiler -): i32 { +function checkArgsOptional(ctx: BuiltinContext, expectedMinimum: i32, expectedMaximum: i32): i32 { + var operands = ctx.operands; var numOperands = operands.length; if (numOperands < expectedMinimum) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_at_least_0_arguments_but_got_1, - reportNode.range, expectedMinimum.toString(), numOperands.toString() + ctx.reportNode.range, expectedMinimum.toString(), numOperands.toString() ); return 1; } else if (numOperands > expectedMaximum) { - compiler.error( + ctx.compiler.error( DiagnosticCode.Expected_0_arguments_but_got_1, - reportNode.range, expectedMaximum.toString(), numOperands.toString() + ctx.reportNode.range, expectedMaximum.toString(), numOperands.toString() ); return 1; } return 0; } + +/** Makes an usize constant matching contextual type if reasonable. */ +function contextualUsize(compiler: Compiler, value: i64, contextualType: Type): ExpressionRef { + var module = compiler.module; + // Check if contextual type fits + if (contextualType != Type.auto && contextualType.is(TypeFlags.INTEGER | TypeFlags.VALUE)) { + switch (contextualType.kind) { + case TypeKind.I32: { + if (i64_is_i32(value)) { + compiler.currentType = Type.i32; + return module.i32(i64_low(value)); + } + break; + } + case TypeKind.U32: { + if (i64_is_u32(value)) { + compiler.currentType = Type.u32; + return module.i32(i64_low(value)); + } + break; + } + case TypeKind.I64: + case TypeKind.U64: { + compiler.currentType = contextualType; + return module.i64(i64_low(value), i64_high(value)); + } + // isize/usize falls through + // small int is probably not intended + } + } + // Default to usize + if (compiler.options.isWasm64) { + compiler.currentType = Type.usize64; + return module.i64(i64_low(value), i64_high(value)); + } else { + compiler.currentType = Type.usize32; + assert(!i64_high(value)); + return module.i32(i64_low(value)); + } +} diff --git a/src/compiler.ts b/src/compiler.ts index 238527644a..197ed9d50d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5,7 +5,8 @@ import { BuiltinNames, - compileCall as compileBuiltinCall, + BuiltinContext, + builtins, compileVisitGlobals, compileVisitMembers, compileRTTI, @@ -28,6 +29,7 @@ import { ExpressionId, GlobalRef, FeatureFlags, + Index, getExpressionId, getExpressionType, getConstValueI32, @@ -101,13 +103,13 @@ import { import { Token, + Range, operatorTokenToString } from "./tokenizer"; import { Node, NodeKind, - Range, DecoratorKind, AssertionKind, SourceKind, @@ -126,6 +128,7 @@ import { ExpressionStatement, FieldDeclaration, ForStatement, + ForOfStatement, FunctionDeclaration, IfStatement, ImportStatement, @@ -321,7 +324,7 @@ export class Compiler extends DiagnosticEmitter { /** Start function statements. */ currentBody: ExpressionRef[]; /** Counting memory offset. */ - memoryOffset: I64; + memoryOffset: i64; /** Memory segments being compiled. */ memorySegments: MemorySegment[] = []; /** Map of already compiled static string segments. */ @@ -340,6 +343,8 @@ export class Compiler extends DiagnosticEmitter { lazyLibraryFunctions: Set = new Set(); /** Pending class-specific instanceof helpers. */ pendingClassInstanceOf: Set = new Set(); + /** Functions potentially involving a virtual call. */ + virtualCalls: Set = new Set(); /** Compiles a {@link Program} to a {@link Module} using the specified options. */ static compile(program: Program): Module { @@ -398,7 +403,9 @@ export class Compiler extends DiagnosticEmitter { // compile entry file(s) while traversing reachable elements var files = program.filesByName; - for (let file of files.values()) { + // TODO: for (let file of files.values()) { + for (let _values = Map_values(files), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) { this.compileFile(file); this.compileExports(file); @@ -436,7 +443,9 @@ export class Compiler extends DiagnosticEmitter { var cyclicClasses = program.findCyclicClasses(); if (cyclicClasses.size) { if (options.pedantic) { - for (let classInstance of cyclicClasses) { + // TODO: for (let classInstance of cyclicClasses) { + for (let _values = Set_values(cyclicClasses), i = 0, k = _values.length; i < k; ++i) { + let classInstance = unchecked(_values[i]); this.pedantic( DiagnosticCode.Type_0_is_cyclic_Module_will_include_deferred_garbage_collection, classInstance.identifierNode.range, classInstance.internalName @@ -451,7 +460,9 @@ export class Compiler extends DiagnosticEmitter { var lazyLibraryFunctions = this.lazyLibraryFunctions; do { let functionsToCompile = new Array(); - for (let instance of lazyLibraryFunctions) { + // TODO: for (let instance of lazyLibraryFunctions) { + for (let _values = Set_values(lazyLibraryFunctions), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); functionsToCompile.push(instance); } lazyLibraryFunctions.clear(); @@ -461,10 +472,15 @@ export class Compiler extends DiagnosticEmitter { } while (lazyLibraryFunctions.size); // compile pending class-specific instanceof helpers - for (let prototype of this.pendingClassInstanceOf.values()) { + // TODO: for (let prototype of this.pendingClassInstanceOf.values()) { + for (let _values = Set_values(this.pendingClassInstanceOf), i = 0, k = _values.length; i < k; ++i) { + let prototype = unchecked(_values[i]); compileClassInstanceOf(this, prototype); } + // set up virtual lookup tables + this.setupVirtualLookupTables(); + // finalize runtime features module.removeGlobal(BuiltinNames.rtti_base); if (this.runtimeFeatures & RuntimeFeatures.RTTI) compileRTTI(this); @@ -537,21 +553,62 @@ export class Compiler extends DiagnosticEmitter { } // set up module exports - for (let file of this.program.filesByName.values()) { + // TODO: for (let file of this.program.filesByName.values()) { + for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.ensureModuleExports(file); } return module; } + private setupVirtualLookupTables(): void { + // TODO: :-) + var program = this.program; + var virtualCalls = this.virtualCalls; + + // Virtual instance methods in the function table are potentially called virtually + var functionTable = this.functionTable; + var elementsByName = program.elementsByName; + for (let i = 0, k = functionTable.length; i < k; ++i) { + let instanceName = unchecked(functionTable[i]); + if (elementsByName.has(instanceName)) { // otherwise ~anonymous + let instance = assert(elementsByName.get(instanceName)); + if (instance.is(CommonFlags.INSTANCE | CommonFlags.VIRTUAL)) { + assert(instance.kind == ElementKind.FUNCTION); + virtualCalls.add(instance); + } + } + } + + // Inject a virtual lookup table into each function potentially called virtually + // TODO: for (let instance of virtualCalls.values()) { + for (let _values = Set_values(virtualCalls), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + this.warning( + DiagnosticCode.Function_0_is_possibly_called_virtually_which_is_not_yet_supported, + instance.identifierNode.range, instance.internalName + ); + } + } + // === Exports ================================================================================== /** Applies the respective module exports for the specified file. */ private ensureModuleExports(file: File): void { - var members = file.exports; - if (members) for (let [name, member] of members) this.ensureModuleExport(name, member); + var exports = file.exports; + if (exports) { + // TODO: for (let [elementName, element] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let elementName = unchecked(_keys[i]); + let element = assert(exports.get(elementName)); + this.ensureModuleExport(elementName, element); + } + } var exportsStar = file.exportsStar; if (exportsStar) { - for (let i = 0, k = exportsStar.length; i < k; ++i) this.ensureModuleExports(exportsStar[i]); + for (let i = 0, k = exportsStar.length; i < k; ++i) { + this.ensureModuleExports(exportsStar[i]); + } } } @@ -563,7 +620,9 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (element).instances; if (instances) { - for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { let fullName = instance.internalName; @@ -577,7 +636,9 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.CLASS_PROTOTYPE: { let instances = (element).instances; if (instances) { - for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); let instanceName = name; if (instance.is(CommonFlags.GENERIC)) { let fullName = instance.internalName; @@ -610,10 +671,11 @@ export class Compiler extends DiagnosticEmitter { break; } case ElementKind.ENUMVALUE: { - if (!(element).isImmutable && !this.options.hasFeature(Feature.MUTABLE_GLOBALS)) { + let enumValue = element; + if (!enumValue.isImmutable && !this.options.hasFeature(Feature.MUTABLE_GLOBALS)) { this.error( DiagnosticCode.Cannot_export_a_mutable_global, - (element).identifierNode.range + enumValue.identifierNode.range ); } else { this.module.addGlobalExport(element.internalName, prefix + name); @@ -662,7 +724,6 @@ export class Compiler extends DiagnosticEmitter { // just traverse members below case ElementKind.ENUM: case ElementKind.NAMESPACE: - case ElementKind.FILE: case ElementKind.TYPEDEFINITION: case ElementKind.INDEXSIGNATURE: break; @@ -676,18 +737,24 @@ export class Compiler extends DiagnosticEmitter { ? INSTANCE_DELIMITER : STATIC_DELIMITER ); - if ( - element.kind == ElementKind.NAMESPACE || - element.kind == ElementKind.FILE - ) { - for (let member of members.values()) { - if (!member.is(CommonFlags.EXPORT)) continue; - this.ensureModuleExport(member.name, member, subPrefix); + if (element.kind == ElementKind.NAMESPACE) { + let implicitExport = element.is(CommonFlags.SCOPED); + // TODO: for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); + if (implicitExport || member.is(CommonFlags.EXPORT)) { + this.ensureModuleExport(memberName, member, subPrefix); + } } } else { - for (let member of members.values()) { - if (member.is(CommonFlags.PRIVATE)) continue; - this.ensureModuleExport(member.name, member, subPrefix); + // TODO: for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); + if (!member.is(CommonFlags.PRIVATE)) { + this.ensureModuleExport(memberName, member, subPrefix); + } } } } @@ -739,21 +806,34 @@ export class Compiler extends DiagnosticEmitter { case ElementKind.TYPEDEFINITION: case ElementKind.ENUMVALUE: case ElementKind.INDEXSIGNATURE: break; - default: assert(false, ElementKind[element.kind]); + default: assert(false); } if (compileMembers) { let members = element.members; - if (members) for (let element of members.values()) this.compileElement(element); + if (members) { + // TODO: for (let element of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); + this.compileElement(element); + } + } } } /** Compiles a file's exports. */ compileExports(file: File): void { var exports = file.exports; - if (exports) for (let element of exports.values()) this.compileElement(element); + if (exports) { + // TODO: for (let element of exports.values()) { + for (let _values = Map_values(exports), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); + this.compileElement(element); + } + } var exportsStar = file.exportsStar; if (exportsStar) { - for (let exportStar of exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + let exportStar = unchecked(exportsStar[i]); this.compileFile(exportStar); this.compileExports(exportStar); } @@ -768,9 +848,9 @@ export class Compiler extends DiagnosticEmitter { var filesByName = this.program.filesByName; var pathWithIndex: string; if (filesByName.has(normalizedPathWithoutExtension)) { - file = filesByName.get(normalizedPathWithoutExtension)!; + file = assert(filesByName.get(normalizedPathWithoutExtension)); } else if (filesByName.has(pathWithIndex = normalizedPathWithoutExtension + INDEX_SUFFIX)) { - file = filesByName.get(pathWithIndex)!; + file = assert(filesByName.get(pathWithIndex)); } else { this.error( DiagnosticCode.File_0_not_found, @@ -955,7 +1035,7 @@ export class Compiler extends DiagnosticEmitter { if (!isGlobalMutable(module.getGlobal(fromName))) { let elementsByName = this.program.elementsByName; if (elementsByName.has(fromName)) { - let global = elementsByName.get(fromName)!; + let global = assert(elementsByName.get(fromName)); if (global.is(CommonFlags.AMBIENT)) initializeInStart = false; } } @@ -1019,7 +1099,7 @@ export class Compiler extends DiagnosticEmitter { if (isDeclaredInline) { this.error( DiagnosticCode.Decorator_0_is_not_valid_here, - assert(findDecorator(DecoratorKind.INLINE, global.decoratorNodes)).range, "inline" + findDecorator(DecoratorKind.INLINE, global.decoratorNodes)!.range, "inline" ); } module.addGlobal(internalName, nativeType, true, this.makeZero(type)); @@ -1047,8 +1127,11 @@ export class Compiler extends DiagnosticEmitter { var previousValueIsMut = false; var isInline = element.is(CommonFlags.CONST) || element.hasDecorator(DecoratorFlags.INLINE); - if (element.members) { - for (let member of element.members.values()) { + var members = element.members; + if (members) { + // TODO: for (let member of element.members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) continue; // happens if an enum is also a namespace let initInStart = false; let val = member; @@ -1215,27 +1298,22 @@ export class Compiler extends DiagnosticEmitter { this.currentFlow = previousFlow; // create the function + let body = module.flatten(stmts, instance.signature.returnType.toNativeType()); + if (instance.is(CommonFlags.VIRTUAL)) { + body = module.block("vtable", [ body ], getExpressionType(body)); + } funcRef = module.addFunction( instance.internalName, signature.nativeParams, signature.nativeResults, typesToNativeTypes(instance.additionalLocals), - module.flatten(stmts, instance.signature.returnType.toNativeType()) + body ); // imported function - } else { - if (!instance.is(CommonFlags.AMBIENT)) { - this.error( - DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, - instance.identifierNode.range - ); - } - + } else if (instance.is(CommonFlags.AMBIENT)) { instance.set(CommonFlags.MODULE_IMPORT); mangleImportName(instance, instance.declaration); // TODO: check for duplicates - - // create the import module.addFunctionImport( instance.internalName, mangleImportName_moduleName, @@ -1244,6 +1322,23 @@ export class Compiler extends DiagnosticEmitter { signature.nativeResults ); funcRef = module.getFunction(instance.internalName); + + // abstract function + } else if (instance.is(CommonFlags.ABSTRACT)) { + funcRef = module.addFunction( + instance.internalName, + signature.nativeParams, + signature.nativeResults, + null, + module.unreachable() + ); + this.virtualCalls.add(instance); + } else { + this.error( + DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, + instance.identifierNode.range + ); + funcRef = 0; // TODO? } instance.finalize(module, funcRef); @@ -1306,7 +1401,9 @@ export class Compiler extends DiagnosticEmitter { if (instance.is(CommonFlags.CONSTRUCTOR)) { let nativeSizeType = this.options.nativeSizeType; assert(instance.is(CommonFlags.INSTANCE)); - let classInstance = assert(instance.parent); assert(classInstance.kind == ElementKind.CLASS); + let parent = assert(instance.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; if (!flow.is(FlowFlags.TERMINATES)) { let thisLocal = assert(flow.lookupLocal(CommonNames.this_)); @@ -1325,12 +1422,12 @@ export class Compiler extends DiagnosticEmitter { ), module.local_set(thisLocal.index, this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance) ), ) ) ); - this.makeFieldInitializationInConstructor(classInstance, stmts); + this.makeFieldInitializationInConstructor(classInstance, stmts); } this.performAutoreleases(flow, stmts); // `this` is excluded anyway this.finishAutoreleases(flow, stmts); @@ -1339,7 +1436,7 @@ export class Compiler extends DiagnosticEmitter { } // check that super has been called if this is a derived class - if ((classInstance).base && !flow.is(FlowFlags.CALLS_SUPER)) { + if (classInstance.base !== null && !flow.is(FlowFlags.CALLS_SUPER)) { this.error( DiagnosticCode.Constructors_for_derived_classes_must_contain_a_super_call, instance.prototype.declaration.range @@ -1366,7 +1463,9 @@ export class Compiler extends DiagnosticEmitter { var prototype = instance.prototype; var staticMembers = (prototype).members; if (staticMembers) { - for (let element of staticMembers.values()) { + // TODO: for (let element of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); switch (element.kind) { case ElementKind.GLOBAL: { this.compileGlobal(element); @@ -1401,7 +1500,9 @@ export class Compiler extends DiagnosticEmitter { if (ctorInstance) this.compileFunction(ctorInstance); var instanceMembers = instance.members; if (instanceMembers) { - for (let element of instanceMembers.values()) { + // TODO: for (let element of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let element = unchecked(_values[i]); switch (element.kind) { case ElementKind.FUNCTION_PROTOTYPE: { if (!element.is(CommonFlags.GENERIC)) { @@ -1551,7 +1652,7 @@ export class Compiler extends DiagnosticEmitter { var stringSegment: MemorySegment; var segments = this.stringSegments; if (segments.has(stringValue)) { - stringSegment = segments.get(stringValue)!; // reuse + stringSegment = assert(segments.get(stringValue)); // reuse } else { let length = stringValue.length; let buffer = new Uint8Array(rtHeaderSize + (length << 1)); @@ -1827,6 +1928,10 @@ export class Compiler extends DiagnosticEmitter { stmt = this.compileForStatement(statement); break; } + case NodeKind.FOROF: { + stmt = this.compileForOfStatement(statement); + break; + } case NodeKind.IF: { stmt = this.compileIfStatement(statement); break; @@ -1899,7 +2004,7 @@ export class Compiler extends DiagnosticEmitter { switch (getExpressionId(stmt)) { case ExpressionId.Block: { if (!getBlockName(stmt)) { - for (let j = 0, k = getBlockChildCount(stmt); j < k; ++j) stmts.push(getBlockChild(stmt, j)); + for (let j: Index = 0, k = getBlockChildCount(stmt); j < k; ++j) stmts.push(getBlockChild(stmt, j)); break; } // fall-through @@ -1935,10 +2040,11 @@ export class Compiler extends DiagnosticEmitter { statement: BreakStatement ): ExpressionRef { var module = this.module; - if (statement.label) { + var labelNode = statement.label; + if (labelNode) { this.error( DiagnosticCode.Not_implemented, - statement.label.range + labelNode.range ); return module.unreachable(); } @@ -1990,7 +2096,7 @@ export class Compiler extends DiagnosticEmitter { var stmts = new Array(); this.performAutoreleases(flow, stmts); var current: Flow | null = flow.parent; - while (current && current.continueLabel === continueLabel) { + while (current !== null && current.continueLabel === continueLabel) { this.performAutoreleases(current, stmts, /* finalize */ false); current = current.parent; } @@ -2078,6 +2184,20 @@ export class Compiler extends DiagnosticEmitter { } this.performAutoreleases(condFlow, bodyStmts); flow.inherit(bodyFlow); + + // Terminate if condition is always true and body never breaks + } else if (condKind == ConditionKind.TRUE && !bodyFlow.isAny(FlowFlags.BREAKS | FlowFlags.CONDITIONALLY_BREAKS)) { + if (hasSideEffects(condExpr)) { + bodyStmts.push( + module.drop(condExpr) + ); + } + this.performAutoreleases(condFlow, bodyStmts); + bodyStmts.push( + module.br(continueLabel) + ); + flow.set(FlowFlags.TERMINATES); + } else { let tcond = condFlow.getTempLocal(Type.bool); bodyStmts.push( @@ -2098,7 +2218,7 @@ export class Compiler extends DiagnosticEmitter { assert(!flowAfter); // should work on the first attempt outerFlow.popBreakLabel(); this.currentFlow = outerFlow; - return this.doCompileWhileStatement(statement, flow); + return this.doCompileDoStatement(statement, flow); } } } @@ -2328,6 +2448,16 @@ export class Compiler extends DiagnosticEmitter { return module.flatten(stmts); } + private compileForOfStatement( + statement: ForOfStatement + ): ExpressionRef { + this.error( + DiagnosticCode.Not_implemented, + statement.range + ); + return this.module.unreachable(); + } + private compileIfStatement( statement: IfStatement ): ExpressionRef { @@ -2398,7 +2528,8 @@ export class Compiler extends DiagnosticEmitter { } else { thenStmts.push(this.compileStatement(ifTrue)); } - if (thenFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS)) { + var thenTerminates = thenFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS); + if (thenTerminates) { thenStmts.push(module.unreachable()); } else { this.performAutoreleases(thenFlow, thenStmts); @@ -2417,14 +2548,19 @@ export class Compiler extends DiagnosticEmitter { } else { elseStmts.push(this.compileStatement(ifFalse)); } - if (elseFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS)) { + let elseTerminates = elseFlow.isAny(FlowFlags.TERMINATES | FlowFlags.BREAKS); + if (elseTerminates) { elseStmts.push(module.unreachable()); } else { this.performAutoreleases(elseFlow, elseStmts); } elseFlow.freeScopedLocals(); this.currentFlow = flow; - flow.inheritMutual(thenFlow, elseFlow); + if (elseTerminates && !thenTerminates) { + flow.inherit(thenFlow); + } else { + flow.inheritMutual(thenFlow, elseFlow); + } return module.if(condExpr, module.flatten(thenStmts), module.flatten(elseStmts) @@ -2481,7 +2617,7 @@ export class Compiler extends DiagnosticEmitter { this.performAutoreleases(flow, stmts); this.finishAutoreleases(flow, stmts); - if (returnType != Type.void && stmts.length) { + if (returnType != Type.void && stmts.length > 0) { let temp = flow.getTempLocal(returnType); if (flow.isNonnull(expr, returnType)) flow.setLocalFlag(temp.index, LocalFlags.NONNULL); stmts.unshift( @@ -2493,7 +2629,7 @@ export class Compiler extends DiagnosticEmitter { flow.freeScopedLocals(); // If the last statement anyway, make it the block's return value - if (isLastInBody && expr && returnType != Type.void) { + if (isLastInBody && expr != 0 && returnType != Type.void) { if (!stmts.length) return expr; stmts.push(expr); return module.flatten(stmts, returnType.toNativeType()); @@ -2550,7 +2686,7 @@ export class Compiler extends DiagnosticEmitter { let case_ = cases[i]; let label = case_.label; if (label) { - breaks[breakIndex++] = module.br("case" + i.toString(10) + "|" + context, + breaks[breakIndex++] = module.br("case" + i.toString() + "|" + context, module.binary(BinaryOp.EqI32, module.local_get(tempLocalIndex, NativeType.I32), this.compileExpression(label, Type.u32, @@ -2567,7 +2703,7 @@ export class Compiler extends DiagnosticEmitter { // otherwise br to default respectively out of the switch if there is no default case breaks[breakIndex] = module.br((defaultIndex >= 0 - ? "case" + defaultIndex.toString(10) + ? "case" + defaultIndex.toString() : "break" ) + "|" + context); @@ -2587,7 +2723,7 @@ export class Compiler extends DiagnosticEmitter { innerFlow.breakLabel = breakLabel; let isLast = i == numCases - 1; - let nextLabel = isLast ? breakLabel : "case" + (i + 1).toString(10) + "|" + context; + let nextLabel = isLast ? breakLabel : "case" + (i + 1).toString() + "|" + context; let stmts = new Array(1 + numStatements); stmts[0] = currentBlock; let count = 1; @@ -2683,23 +2819,25 @@ export class Compiler extends DiagnosticEmitter { let initAutoreleaseSkipped = false; // Resolve type if annotated - if (declaration.type) { + let typeNode = declaration.type; + let initializerNode = declaration.initializer; + if (typeNode) { type = resolver.resolveType( // reports - declaration.type, + typeNode, flow.actualFunction, makeMap(flow.contextualTypeArguments) ); if (!type) continue; - if (declaration.initializer) { - initExpr = this.compileExpression(declaration.initializer, type, // reports + if (initializerNode) { + initExpr = this.compileExpression(initializerNode, type, // reports Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN ); initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr); } // Otherwise infer type from initializer - } else if (declaration.initializer) { - initExpr = this.compileExpression(declaration.initializer, Type.auto, + } else if (initializerNode) { + initExpr = this.compileExpression(initializerNode, Type.auto, Constraints.WILL_RETAIN ); // reports initAutoreleaseSkipped = this.skippedAutoreleases.has(initExpr); @@ -2767,7 +2905,7 @@ export class Compiler extends DiagnosticEmitter { let scopedLocals = flow.scopedLocals; if (!scopedLocals) flow.scopedLocals = scopedLocals = new Map(); else if (scopedLocals.has(name)) { - let existing = scopedLocals.get(name)!; + let existing = assert(scopedLocals.get(name)); this.errorRelated( DiagnosticCode.Duplicate_identifier_0, declaration.name.range, @@ -2967,13 +3105,22 @@ export class Compiler extends DiagnosticEmitter { bodyStmts.push(this.compileStatement(body)); } - // Check if body terminates + // Simplify if body always terminates if (bodyFlow.is(FlowFlags.TERMINATES)) { bodyStmts.push( module.unreachable() ); if (condKind == ConditionKind.TRUE) flow.inherit(bodyFlow); else flow.inheritBranch(bodyFlow); + + // Terminate if condition is always true and body never breaks + } else if (condKind == ConditionKind.TRUE && !bodyFlow.isAny(FlowFlags.BREAKS | FlowFlags.CONDITIONALLY_BREAKS)) { + this.performAutoreleases(bodyFlow, bodyStmts); + bodyStmts.push( + module.br(continueLabel) + ); + flow.set(FlowFlags.TERMINATES); + } else { let breaks = bodyFlow.is(FlowFlags.BREAKS); if (breaks) { @@ -3092,13 +3239,13 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.F64: { // monkey-patch for converting built-in floats to f32 implicitly if (!(element.hasDecorator(DecoratorFlags.BUILTIN) && contextualType == Type.f32)) { - return this.module.f64((element).constantFloatValue); + return this.module.f64(element.constantFloatValue); } // otherwise fall-through: basically precomputes f32.demote/f64 of NaN / Infinity this.currentType = Type.f32; } case TypeKind.F32: { - return this.module.f32((element).constantFloatValue); + return this.module.f32(element.constantFloatValue); } default: { assert(false); @@ -3456,6 +3603,14 @@ export class Compiler extends DiagnosticEmitter { expr = this.ensureSmallIntegerWrap(expr, fromType); // must clear garbage bits wrap = false; } + // same size + } else { + if (!explicit && !this.options.isWasm64 && fromType.is(TypeFlags.POINTER) && !toType.is(TypeFlags.POINTER)) { + this.warning( + DiagnosticCode.Conversion_from_type_0_to_1_will_require_an_explicit_cast_when_switching_between_32_64_bit, + reportNode.range, fromType.toString(), toType.toString() + ); + } } } } @@ -3571,18 +3726,8 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, true)) { - leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, - false, true, // ! - left - ); - rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, - false, true, // ! - right - ); - } else { + commonType = Type.commonDenominator(leftType, rightType, true); + if (!commonType) { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, expression.range, "<", leftType.toString(), rightType.toString() @@ -3590,6 +3735,16 @@ export class Compiler extends DiagnosticEmitter { this.currentType = contextualType; return module.unreachable(); } + leftExpr = this.convertExpression(leftExpr, + leftType, leftType = commonType, + false, true, // ! + left + ); + rightExpr = this.convertExpression(rightExpr, + rightType, rightType = commonType, + false, true, // ! + right + ); switch (commonType.kind) { case TypeKind.I8: case TypeKind.I16: @@ -3671,17 +3826,20 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, true)) { + commonType = Type.commonDenominator(leftType, rightType, true); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -3974,17 +4132,20 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4071,17 +4232,20 @@ export class Compiler extends DiagnosticEmitter { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4268,17 +4432,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4358,17 +4525,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4449,7 +4619,8 @@ export class Compiler extends DiagnosticEmitter { if (this.currentType.kind == TypeKind.F32) { rightExpr = this.compileExpression(right, Type.f32, Constraints.CONV_IMPLICIT); rightType = this.currentType; - if (!(instance = this.f32PowInstance)) { + instance = this.f32PowInstance; + if (!instance) { let namespace = this.program.lookupGlobal(CommonNames.Mathf); if (!namespace) { this.error( @@ -4483,7 +4654,8 @@ export class Compiler extends DiagnosticEmitter { leftType = this.currentType; rightExpr = this.compileExpression(right, Type.f64, Constraints.CONV_IMPLICIT); rightType = this.currentType; - if (!(instance = this.f64PowInstance)) { + instance = this.f64PowInstance; + if (!instance) { let namespace = this.program.lookupGlobal(CommonNames.Math); if (!namespace) { this.error( @@ -4506,7 +4678,7 @@ export class Compiler extends DiagnosticEmitter { this.f64PowInstance = instance = this.resolver.resolveFunction(prototype, null); } } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -4546,17 +4718,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4655,17 +4830,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, true, // ! left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, true, // ! right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -4747,7 +4925,7 @@ export class Compiler extends DiagnosticEmitter { assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); this.f32ModInstance = instance = this.resolver.resolveFunction(prototype, null); } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -4778,7 +4956,7 @@ export class Compiler extends DiagnosticEmitter { assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE); this.f64ModInstance = instance = this.resolver.resolveFunction(prototype, null); } - if (!(instance && this.compileFunction(instance))) { + if (!instance || !this.compileFunction(instance)) { expr = module.unreachable(); } else { expr = this.makeCallDirect(instance, [ leftExpr, rightExpr ], expression); @@ -5133,17 +5311,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -5226,17 +5407,20 @@ export class Compiler extends DiagnosticEmitter { } else { rightExpr = this.compileExpression(right, leftType); rightType = this.currentType; - if (commonType = Type.commonDenominator(leftType, rightType, false)) { + commonType = Type.commonDenominator(leftType, rightType, false); + if (commonType) { leftExpr = this.convertExpression(leftExpr, - leftType, leftType = commonType, + leftType, commonType, false, false, left ); + leftType = commonType; rightExpr = this.convertExpression(rightExpr, - rightType, rightType = commonType, + rightType, commonType, false, false, right ); + rightType = commonType; } else { this.error( DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2, @@ -5509,7 +5693,8 @@ export class Compiler extends DiagnosticEmitter { var resolver = this.resolver; var target = resolver.lookupExpression(left, this.currentFlow); if (!target) return module.unreachable(); - var targetType = resolver.getTypeOfElement(target) || Type.void; + var targetType = resolver.getTypeOfElement(target); + if (!targetType) targetType = Type.void; if (!this.currentType.isStrictlyAssignableTo(targetType)) { this.error( DiagnosticCode.Type_0_is_not_assignable_to_type_1, @@ -5597,7 +5782,7 @@ export class Compiler extends DiagnosticEmitter { ); return this.module.unreachable(); } - let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); + let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); if (!setterInstance) return this.module.unreachable(); assert(setterInstance.signature.parameterTypes.length == 1); // parser must guarantee this targetType = setterInstance.signature.parameterTypes[0]; @@ -5726,7 +5911,7 @@ export class Compiler extends DiagnosticEmitter { (target).is(CommonFlags.READONLY) && !( flow.actualFunction.is(CommonFlags.CONSTRUCTOR) || - initializerNode + initializerNode !== null ) ) { this.error( @@ -5751,7 +5936,7 @@ export class Compiler extends DiagnosticEmitter { ); return module.unreachable(); } - let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); + let setterInstance = this.resolver.resolveFunction(setterPrototype, null, makeMap(), ReportMode.REPORT); if (!setterInstance) return module.unreachable(); assert(setterInstance.signature.parameterTypes.length == 1); let valueType = setterInstance.signature.parameterTypes[0]; @@ -5760,7 +5945,7 @@ export class Compiler extends DiagnosticEmitter { if (!tee) return this.makeCallDirect(setterInstance, [ valueExpr ], valueExpression); // otherwise call the setter first, then the getter let getterPrototype = assert((target).getterPrototype); // must be present - let getterInstance = this.resolver.resolveFunction(getterPrototype, null, makeMap(), ReportMode.REPORT); + let getterInstance = this.resolver.resolveFunction(getterPrototype, null, makeMap(), ReportMode.REPORT); if (!getterInstance) return module.unreachable(); let returnType = getterInstance.signature.returnType; assert(valueType == returnType); @@ -5935,8 +6120,8 @@ export class Compiler extends DiagnosticEmitter { /** Makes an assignment to a global, possibly retaining and releasing affected references. */ private makeGlobalAssignment( - /** The global to assign to. */ - global: Global, + /** The global variable to assign to. */ + global: VariableLikeElement, /** The value to assign. */ valueExpr: ExpressionRef, /** Whether to tee the value. */ @@ -6097,8 +6282,10 @@ export class Compiler extends DiagnosticEmitter { return module.unreachable(); } - let classInstance = assert(actualFunction.parent); assert(classInstance.kind == ElementKind.CLASS); - let baseClassInstance = assert((classInstance).base); + let parent = assert(actualFunction.parent); + assert(parent.kind == ElementKind.CLASS); + let classInstance = parent; + let baseClassInstance = assert(classInstance.base); let thisLocal = assert(flow.lookupLocal(CommonNames.this_)); let nativeSizeType = this.options.nativeSizeType; @@ -6115,7 +6302,7 @@ export class Compiler extends DiagnosticEmitter { module.local_get(thisLocal.index, nativeSizeType), module.local_get(thisLocal.index, nativeSizeType), this.makeRetain( - this.makeAllocation(classInstance) + this.makeAllocation(classInstance) ) ), Constraints.WILL_RETAIN @@ -6124,7 +6311,7 @@ export class Compiler extends DiagnosticEmitter { let stmts: ExpressionRef[] = [ module.local_set(thisLocal.index, theCall) ]; - this.makeFieldInitializationInConstructor(classInstance, stmts); + this.makeFieldInitializationInConstructor(classInstance, stmts); // check that super had been called before accessing `this` if (flow.isAny( @@ -6159,7 +6346,7 @@ export class Compiler extends DiagnosticEmitter { return this.compileCallExpressionBuiltin(prototype, expression, contextualType); } - let thisExpression = this.resolver.currentThisExpression; + let thisExpression = this.resolver.currentThisExpression; // compileCallDirect may reset let instance = this.resolver.maybeInferCall(expression, prototype, flow); if (!instance) return this.module.unreachable(); return this.compileCallDirect( @@ -6175,36 +6362,37 @@ export class Compiler extends DiagnosticEmitter { // indirect call: index argument with signature (non-generic, can't be inlined) case ElementKind.LOCAL: { - if (signature = (target).type.signatureReference) { + signature = (target).type.signatureReference; + if (signature) { if ((target).is(CommonFlags.INLINED)) { indexArg = module.i32(i64_low((target).constantIntegerValue)); } else { indexArg = module.local_get((target).index, NativeType.I32); } break; - } else { - this.error( - DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() - ); - return module.unreachable(); } + this.error( + DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, + expression.range, (target).type.toString() + ); + return module.unreachable(); } case ElementKind.GLOBAL: { - if (signature = (target).type.signatureReference) { + signature = (target).type.signatureReference; + if (signature) { indexArg = module.global_get((target).internalName, (target).type.toNativeType()); break; - } else { - this.error( - DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, - expression.range, (target).type.toString() - ); - return module.unreachable(); } + this.error( + DiagnosticCode.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures, + expression.range, (target).type.toString() + ); + return module.unreachable(); } case ElementKind.FIELD: { let type = (target).type; - if (signature = type.signatureReference) { + signature = type.signatureReference; + if (signature) { let thisExpression = assert(this.resolver.currentThisExpression); let thisExpr = this.compileExpression(thisExpression, this.options.usizeType); indexArg = module.load( @@ -6278,7 +6466,7 @@ export class Compiler extends DiagnosticEmitter { } } return this.compileCallIndirect( - signature, + assert(signature), // FIXME: asc can't see this yet indexArg, expression.arguments, expression, @@ -6315,16 +6503,24 @@ export class Compiler extends DiagnosticEmitter { expression ); } - - // now compile the builtin, which usually returns a block of code that replaces the call. - return compileBuiltinCall( - this, - prototype, - typeArguments, - expression.arguments, - contextualType, - expression + var ctx = new BuiltinContext(); + ctx.compiler = this; + ctx.prototype = prototype; + ctx.typeArguments = typeArguments; + ctx.operands = expression.arguments; + ctx.contextualType = contextualType; + ctx.reportNode = expression; + ctx.contextIsExact = false; + var internalName = prototype.internalName; + if (builtins.has(internalName)) { + let fn = assert(builtins.get(internalName)); + return fn(ctx); + } + this.error( + DiagnosticCode.Not_implemented, + expression.expression.range ); + return this.module.unreachable(); } /** @@ -6489,6 +6685,9 @@ export class Compiler extends DiagnosticEmitter { thisArg: ExpressionRef = 0, immediatelyDropped: bool = false ): ExpressionRef { + if (instance.is(CommonFlags.VIRTUAL)) { + this.virtualCalls.add(instance); + } var module = this.module; var numArguments = operands ? operands.length : 0; var signature = instance.signature; @@ -6653,9 +6852,9 @@ export class Compiler extends DiagnosticEmitter { // create a br_table switching over the number of optional parameters provided var numNames = numOptional + 1; // incl. outer block var names = new Array(numNames); - var ofN = "of" + numOptional.toString(10); + var ofN = "of" + numOptional.toString(); for (let i = 0; i < numNames; ++i) { - let label = i.toString(10) + ofN; + let label = i.toString() + ofN; names[i] = label; } var body = module.block(names[0], [ @@ -6925,7 +7124,9 @@ export class Compiler extends DiagnosticEmitter { var scopedLocals = flow.scopedLocals; if (scopedLocals) { let module = this.module; - for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); if (local.is(CommonFlags.SCOPED)) { // otherwise an alias let localIndex = local.index; if (flow.isAnyLocalFlag(localIndex, LocalFlags.ANY_RETAINED)) { @@ -6997,12 +7198,16 @@ export class Compiler extends DiagnosticEmitter { while (parent = current.parent) current = parent; let scopedLocals = current.scopedLocals; if (scopedLocals) { - for (let local of scopedLocals.values()) { + // TODO: for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); this.maybeFinishAutorelease(local, flow, stmts); } } } else { - for (let local of flow.parentFunction.localsByIndex) { + let localsByIndex = flow.parentFunction.localsByIndex; + for (let i = 0, k = localsByIndex.length; i < k; ++i) { + let local = unchecked(localsByIndex[i]); this.maybeFinishAutorelease(local, flow, stmts); } } @@ -7040,6 +7245,9 @@ export class Compiler extends DiagnosticEmitter { /** Skip the usual autorelease and manage this at the callsite instead. */ skipAutorelease: bool = false ): ExpressionRef { + if (instance.is(CommonFlags.VIRTUAL)) { + this.virtualCalls.add(instance); + } if (instance.hasDecorator(DecoratorFlags.INLINE)) { assert(!instance.is(CommonFlags.TRAMPOLINE)); // doesn't make sense let inlineStack = this.inlineStack; @@ -7109,7 +7317,7 @@ export class Compiler extends DiagnosticEmitter { )); continue; } - let resolved = this.resolver.lookupExpression(initializer, instance.flow, parameterTypes[i]); + let resolved = this.resolver.lookupExpression(initializer, instance.flow, parameterTypes[i], ReportMode.SWALLOW); if (resolved) { if (resolved.kind == ElementKind.GLOBAL) { let global = resolved; @@ -7343,7 +7551,7 @@ export class Compiler extends DiagnosticEmitter { var prototype = new FunctionPrototype( declaration.name.text.length ? declaration.name.text - : "anonymous|" + (actualFunction.nextAnonymousId++).toString(10), + : "anonymous|" + (actualFunction.nextAnonymousId++).toString(), actualFunction, declaration, DecoratorFlags.NONE @@ -7471,7 +7679,7 @@ export class Compiler extends DiagnosticEmitter { var internalPath = expression.range.source.internalPath; var filesByName = this.program.filesByName; assert(filesByName.has(internalPath)); - var enclosingFile = filesByName.get(internalPath)!; + var enclosingFile = assert(filesByName.get(internalPath)); if (!enclosingFile.is(CommonFlags.COMPILED)) { this.compileFileByPath(internalPath, expression); } @@ -7610,10 +7818,12 @@ export class Compiler extends DiagnosticEmitter { this.maybeCompileEnclosingSource(expression); // otherwise resolve + var currentParent = this.currentParent; + if (!currentParent) currentParent = actualFunction; var target = this.resolver.lookupIdentifierExpression( // reports expression, flow, - this.currentParent || actualFunction + currentParent ); if (!target) { // make a guess to avoid assertions in calling code @@ -7679,7 +7889,7 @@ export class Compiler extends DiagnosticEmitter { null, makeMap(flow.contextualTypeArguments) ); - if (!(instance && this.compileFunction(instance))) return module.unreachable(); + if (!instance || !this.compileFunction(instance)) return module.unreachable(); if (contextualType.is(TypeFlags.HOST | TypeFlags.REFERENCE)) { this.currentType = Type.anyref; return module.ref_func(instance.internalName); @@ -8007,7 +8217,7 @@ export class Compiler extends DiagnosticEmitter { assert(element.kind == ElementKind.CLASS); var arrayInstance = element; var arrayType = arrayInstance.type; - var elementType = assert(arrayInstance.getTypeArgumentsTo(program.arrayPrototype))[0]; + var elementType = arrayInstance.getTypeArgumentsTo(program.arrayPrototype)![0]; var arrayBufferInstance = assert(program.arrayBufferInstance); // block those here so compiling expressions doesn't conflict @@ -8177,7 +8387,7 @@ export class Compiler extends DiagnosticEmitter { assert(contextualType.is(TypeFlags.REFERENCE)); var arrayInstance = assert(contextualType.classReference); var arrayType = arrayInstance.type; - var elementType = assert(arrayInstance.getTypeArgumentsTo(program.staticArrayPrototype))[0]; + var elementType = arrayInstance.getTypeArgumentsTo(program.staticArrayPrototype)![0]; // block those here so compiling expressions doesn't conflict var tempThis = flow.getTempLocal(this.options.usizeType); @@ -8695,7 +8905,6 @@ export class Compiler extends DiagnosticEmitter { ): ExpressionRef { var ifThen = expression.ifThen; var ifElse = expression.ifElse; - var outerFlow = this.currentFlow; var condExpr = this.module.precomputeExpression( this.makeIsTrueish( @@ -8705,27 +8914,25 @@ export class Compiler extends DiagnosticEmitter { ); // Try to eliminate unnecesssary branches if the condition is constant - // FIXME: skips common denominator, inconsistently picking left type - if ( - getExpressionId(condExpr) == ExpressionId.Const && - getExpressionType(condExpr) == NativeType.I32 - ) { - return getConstValueI32(condExpr) - ? this.compileExpression(ifThen, ctxType) - : this.compileExpression(ifElse, ctxType); - } + // FIXME: skips common denominator, inconsistently picking branch type + var condKind = evaluateConditionKind(condExpr); + if (condKind == ConditionKind.TRUE) return this.compileExpression(ifThen, ctxType); + if (condKind == ConditionKind.FALSE) return this.compileExpression(ifElse, ctxType); var inheritedConstraints = constraints & Constraints.WILL_RETAIN; + var outerFlow = this.currentFlow; var ifThenFlow = outerFlow.fork(); + ifThenFlow.inheritNonnullIfTrue(condExpr); this.currentFlow = ifThenFlow; var ifThenExpr = this.compileExpression(ifThen, ctxType, inheritedConstraints); var ifThenType = this.currentType; var ifThenAutoreleaseSkipped = this.skippedAutoreleases.has(ifThenExpr); var ifElseFlow = outerFlow.fork(); + ifElseFlow.inheritNonnullIfFalse(condExpr); this.currentFlow = ifElseFlow; - var ifElseExpr = this.compileExpression(ifElse, ctxType, inheritedConstraints); + var ifElseExpr = this.compileExpression(ifElse, ctxType == Type.auto ? ifThenType : ctxType, inheritedConstraints); var ifElseType = this.currentType; var ifElseAutoreleaseSkipped = this.skippedAutoreleases.has(ifElseExpr); @@ -9737,11 +9944,13 @@ export class Compiler extends DiagnosticEmitter { var flow = this.currentFlow; var isInline = flow.isInline; var thisLocalIndex = isInline - ? assert(flow.lookupLocal(CommonNames.this_)).index + ? flow.lookupLocal(CommonNames.this_)!.index : 0; var nativeSizeType = this.options.nativeSizeType; - for (let member of members.values()) { + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if ( member.kind != ElementKind.FIELD || // not a field member.parent != classInstance // inherited field @@ -9760,7 +9969,7 @@ export class Compiler extends DiagnosticEmitter { if (parameterIndex >= 0) { initExpr = module.local_get( isInline - ? assert(flow.lookupLocal(field.name)).index + ? flow.lookupLocal(field.name)!.index : 1 + parameterIndex, // this is local 0 nativeFieldType ); @@ -9875,7 +10084,7 @@ export class Compiler extends DiagnosticEmitter { expr = module.if( module.call(instanceofInstance.internalName, [ module.local_tee(temp.index, expr), - module.i32(assert(toType.classReference).id) + module.i32(toType.classReference!.id) ], NativeType.I32), module.local_get(temp.index, type.toNativeType()), this.makeAbort(null, reportNode) // TODO: throw @@ -9904,7 +10113,7 @@ function mangleImportName( var program = element.program; var decorator = assert(findDecorator(DecoratorKind.EXTERNAL, declaration.decorators)); var args = decorator.arguments; - if (args && args.length) { + if (args !== null && args.length > 0) { let arg = args[0]; // if one argument is given, override just the element name // if two arguments are given, override both module and element name diff --git a/src/definitions.ts b/src/definitions.ts index c9d34d726b..239cc3c139 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -58,20 +58,30 @@ export abstract class ExportsWalker { /** Walks all elements and calls the respective handlers. */ walk(): void { - for (let file of this.program.filesByName.values()) { + // TODO: for (let file of this.program.filesByName.values()) { + for (let _values = Map_values(this.program.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); if (file.source.sourceKind == SourceKind.USER_ENTRY) this.visitFile(file); } } /** Visits all exported elements of a file. */ visitFile(file: File): void { - var members = file.exports; - if (members) { - for (let [name, member] of members) this.visitElement(name, member); + var exports = file.exports; + if (exports) { + // TODO: for (let [memberName, member] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(exports.get(memberName)); + this.visitElement(memberName, member); + } } var exportsStar = file.exportsStar; if (exportsStar) { - for (let exportStar of exportsStar) this.visitFile(exportStar); + for (let i = 0, k = exportsStar.length; i < k; ++i) { + let exportStar = unchecked(exportsStar[i]); + this.visitFile(exportStar); + } } } @@ -79,7 +89,7 @@ export abstract class ExportsWalker { visitElement(name: string, element: Element): void { if (element.is(CommonFlags.PRIVATE) && !this.includePrivate) return; var seen = this.seen; - if (seen.has(element)) { + if (seen.has(element) && !element.is(CommonFlags.INSTANCE)) { this.visitAlias(name, element, seen.get(element)); return; } @@ -93,6 +103,7 @@ export abstract class ExportsWalker { if (element.is(CommonFlags.COMPILED)) this.visitEnum(name, element); break; } + case ElementKind.ENUMVALUE: break; // handled by visitEnum case ElementKind.FUNCTION_PROTOTYPE: { this.visitFunctionInstances(name, element); break; @@ -129,8 +140,10 @@ export abstract class ExportsWalker { private visitFunctionInstances(name: string, element: FunctionPrototype): void { var instances = element.instances; if (instances) { - for (let instance of instances.values()) { - if (instance.is(CommonFlags.COMPILED)) this.visitFunction(name, instance); + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + if (instance.is(CommonFlags.COMPILED)) this.visitFunction(name, instance); } } } @@ -138,8 +151,10 @@ export abstract class ExportsWalker { private visitClassInstances(name: string, element: ClassPrototype): void { var instances = element.instances; if (instances) { - for (let instance of instances.values()) { - if (instance.is(CommonFlags.COMPILED)) this.visitClass(name, instance); + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); + if (instance.is(CommonFlags.COMPILED)) this.visitClass(name, instance); } } } @@ -214,23 +229,29 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - for (let [name, member] of members) { + // TODO: for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { - let isConst = (member).is(CommonFlags.INLINED); + let value = member; + let isConst = value.is(CommonFlags.INLINED); indent(sb, this.indentLevel); if (isConst) sb.push("const "); else sb.push("readonly "); sb.push("unsigned long "); - sb.push(name); + sb.push(memberName); if (isConst) { sb.push(" = "); - assert((member).constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low((member).constantIntegerValue).toString(10)); + assert(value.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(value.constantIntegerValue).toString()); } sb.push(";\n"); } } - for (let member of members.values()) { + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind != ElementKind.ENUMVALUE) this.visitElement(member.name, member); } } @@ -258,12 +279,16 @@ export class IDLBuilder extends ExportsWalker { } sb.push(");\n"); var members = element.members; - if (members && members.size) { + if (members !== null && members.size > 0) { indent(sb, this.indentLevel); sb.push("interface "); sb.push(element.name); sb.push(" {\n"); - for (let member of members.values()) this.visitElement(member.name, member); + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } indent(sb, --this.indentLevel); sb.push("}\n"); } @@ -296,7 +321,11 @@ export class IDLBuilder extends ExportsWalker { sb.push(" {\n"); var members = element.members; if (members) { - for (let member of members.values()) this.visitElement(member.name, member); + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } } indent(sb, --this.indentLevel); sb.push("}\n"); @@ -380,29 +409,36 @@ export class TSDBuilder extends ExportsWalker { visitEnum(name: string, element: Enum): void { var sb = this.sb; indent(sb, this.indentLevel++); - sb.push("export enum "); + sb.push("export "); + if (element.is(CommonFlags.CONST)) sb.push("const "); + sb.push("enum "); sb.push(name); sb.push(" {\n"); var members = element.members; + var remainingMembers = 0; if (members) { - let numMembers = members.size; - for (let [name, member] of members) { + remainingMembers = members.size; + // TODO: for (let [memberName, member] of members) { + for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(members.get(memberName)); if (member.kind == ElementKind.ENUMVALUE) { + let value = member; indent(sb, this.indentLevel); - sb.push(name); + sb.push(memberName); if (member.is(CommonFlags.INLINED)) { sb.push(" = "); - assert((member).constantValueKind == ConstantValueKind.INTEGER); - sb.push(i64_low((member).constantIntegerValue).toString(10)); + assert(value.constantValueKind == ConstantValueKind.INTEGER); + sb.push(i64_low(value.constantIntegerValue).toString()); } sb.push(",\n"); - --numMembers; + --remainingMembers; } } - if (numMembers) this.visitNamespace(name, element); } indent(sb, --this.indentLevel); sb.push("}\n"); + if (remainingMembers) this.visitNamespace(name, element); } visitFunction(name: string, element: Function): void { @@ -451,23 +487,35 @@ export class TSDBuilder extends ExportsWalker { if (isInterface) { sb.push("export interface "); } else { + sb.push("export "); if (element.is(CommonFlags.ABSTRACT)) sb.push("abstract "); - sb.push("export class "); + sb.push("class "); } sb.push(name); - // var base = element.base; - // if (base && base.is(CommonFlags.COMPILED | CommonFlags.MODULE_EXPORT)) { - // sb.push(" extends "); - // sb.push(base.name); // TODO: fqn - // } + var base = element.base; + if (base !== null && base.is(CommonFlags.COMPILED | CommonFlags.MODULE_EXPORT)) { + sb.push(" extends "); + let extendsNode = assert(element.prototype.extendsNode); + sb.push(extendsNode.name.identifier.text); // TODO: fqn? + } sb.push(" {\n"); var staticMembers = element.prototype.members; if (staticMembers) { - for (let member of staticMembers.values()) this.visitElement(member.name, member); + // TODO: for (let member of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } } var instanceMembers = element.members; if (instanceMembers) { - for (let member of instanceMembers.values()) this.visitElement(member.name, member); + // TODO: for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + if (member.parent == element) { // own member + this.visitElement(member.name, member); + } + } } indent(sb, --this.indentLevel); sb.push("}\n"); @@ -492,13 +540,17 @@ export class TSDBuilder extends ExportsWalker { visitNamespace(name: string, element: Element): void { var members = element.members; - if (members && members.size) { + if (members !== null && members.size > 0) { let sb = this.sb; indent(sb, this.indentLevel++); sb.push("export namespace "); sb.push(name); sb.push(" {\n"); - for (let member of members.values()) this.visitElement(member.name, member); + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.visitElement(member.name, member); + } indent(sb, --this.indentLevel); sb.push("}\n"); } @@ -519,14 +571,14 @@ export class TSDBuilder extends ExportsWalker { case TypeKind.I8: return "i8"; case TypeKind.I16: return "i16"; case TypeKind.I32: return "i32"; - case TypeKind.I64: return "I64"; - case TypeKind.ISIZE: return this.program.options.isWasm64 ? "I64" : "i32"; + case TypeKind.I64: return "i64"; + case TypeKind.ISIZE: return "isize"; case TypeKind.U8: return "u8"; case TypeKind.U16: return "u16"; case TypeKind.U32: return "u32"; // ^ TODO: function types - case TypeKind.U64: return "U64"; - case TypeKind.USIZE: return this.program.options.isWasm64 ? "U64" : "u32"; + case TypeKind.U64: return "u64"; + case TypeKind.USIZE: return "usize"; // ^ TODO: class types case TypeKind.BOOL: return "bool"; case TypeKind.F32: return "f32"; @@ -542,13 +594,26 @@ export class TSDBuilder extends ExportsWalker { build(): string { var sb = this.sb; + var isWasm64 = this.program.options.isWasm64; sb.push("declare module ASModule {\n"); sb.push(" type i8 = number;\n"); sb.push(" type i16 = number;\n"); sb.push(" type i32 = number;\n"); + sb.push(" type i64 = BigInt;\n"); + if (isWasm64) { + sb.push(" type isize = BigInt;\n"); + } else { + sb.push(" type isize = number;\n"); + } sb.push(" type u8 = number;\n"); sb.push(" type u16 = number;\n"); sb.push(" type u32 = number;\n"); + sb.push(" type u64 = BigInt;\n"); + if (isWasm64) { + sb.push(" type usize = BigInt;\n"); + } else { + sb.push(" type usize = number;\n"); + } sb.push(" type f32 = number;\n"); sb.push(" type f64 = number;\n"); sb.push(" type bool = any;\n"); @@ -567,12 +632,16 @@ export class TSDBuilder extends ExportsWalker { function hasCompiledMember(element: Element): bool { var members = element.members; if (members) { - for (let member of members.values()) { + // TODO: for (let member of members.values()) { + for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); switch (member.kind) { case ElementKind.FUNCTION_PROTOTYPE: { let instances = (member).instances; if (instances) { - for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { + let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; } } @@ -581,7 +650,9 @@ function hasCompiledMember(element: Element): bool { case ElementKind.CLASS_PROTOTYPE: { let instances = (member).instances; if (instances) { - for (let instance of instances.values()) { + // TODO: for (let instance of instances.values()) { + for (let _values = Map_values(instances), j = 0, l = _values.length; j < l; ++j) { + let instance = unchecked(_values[j]); if (instance.is(CommonFlags.COMPILED)) return true; } } diff --git a/src/diagnosticMessages.generated.ts b/src/diagnosticMessages.generated.ts index 68e21cfa2d..a6de0f5569 100644 --- a/src/diagnosticMessages.generated.ts +++ b/src/diagnosticMessages.generated.ts @@ -11,6 +11,7 @@ export enum DiagnosticCode { Operation_is_unsafe = 101, User_defined_0 = 102, Feature_0_is_not_enabled = 103, + Function_0_is_possibly_called_virtually_which_is_not_yet_supported = 104, Conversion_from_type_0_to_1_requires_an_explicit_cast = 200, Conversion_from_type_0_to_1_will_require_an_explicit_cast_when_switching_between_32_64_bit = 201, Type_0_cannot_be_changed_to_type_1 = 202, @@ -93,6 +94,7 @@ export enum DiagnosticCode { Binary_digit_expected = 1177, Octal_digit_expected = 1178, An_implementation_cannot_be_declared_in_ambient_contexts = 1183, + The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer = 1190, An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive = 1198, Unterminated_Unicode_escape_sequence = 1199, Decorators_are_not_valid_here = 1206, @@ -162,6 +164,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 101: return "Operation is unsafe."; case 102: return "User-defined: {0}"; case 103: return "Feature '{0}' is not enabled."; + case 104: return "Function '{0}' is possibly called virtually, which is not yet supported."; case 200: return "Conversion from type '{0}' to '{1}' requires an explicit cast."; case 201: return "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit."; case 202: return "Type '{0}' cannot be changed to type '{1}'."; @@ -244,6 +247,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string { case 1177: return "Binary digit expected."; case 1178: return "Octal digit expected."; case 1183: return "An implementation cannot be declared in ambient contexts."; + case 1190: return "The variable declaration of a 'for...of' statement cannot have an initializer."; case 1198: return "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive."; case 1199: return "Unterminated Unicode escape sequence."; case 1206: return "Decorators are not valid here."; diff --git a/src/diagnosticMessages.json b/src/diagnosticMessages.json index 655b26c520..049e89ceb4 100644 --- a/src/diagnosticMessages.json +++ b/src/diagnosticMessages.json @@ -3,6 +3,7 @@ "Operation is unsafe.": 101, "User-defined: {0}": 102, "Feature '{0}' is not enabled.": 103, + "Function '{0}' is possibly called virtually, which is not yet supported.": 104, "Conversion from type '{0}' to '{1}' requires an explicit cast.": 200, "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit.": 201, @@ -88,6 +89,7 @@ "Binary digit expected.": 1177, "Octal digit expected.": 1178, "An implementation cannot be declared in ambient contexts.": 1183, + "The variable declaration of a 'for...of' statement cannot have an initializer.": 1190, "An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.": 1198, "Unterminated Unicode escape sequence.": 1199, "Decorators are not valid here.": 1206, diff --git a/src/diagnostics.ts b/src/diagnostics.ts index 36df68a519..2f8054a03a 100644 --- a/src/diagnostics.ts +++ b/src/diagnostics.ts @@ -5,7 +5,10 @@ *//***/ import { - Range, + Range +} from "./tokenizer"; + +import { Source } from "./ast"; @@ -104,9 +107,9 @@ export class DiagnosticMessage { arg2: string | null = null ): DiagnosticMessage { var message = diagnosticCodeToString(code); - if (arg0 != null) message = message.replace("{0}", arg0); - if (arg1 != null) message = message.replace("{1}", arg1); - if (arg2 != null) message = message.replace("{2}", arg2); + if (arg0 !== null) message = message.replace("{0}", arg0); + if (arg1 !== null) message = message.replace("{1}", arg1); + if (arg2 !== null) message = message.replace("{2}", arg2); return new DiagnosticMessage(code, category, message); } @@ -124,25 +127,26 @@ export class DiagnosticMessage { /** Converts this message to a string. */ toString(): string { - if (this.range) { + var range = this.range; + if (range) { return ( diagnosticCategoryToString(this.category) + " " + - this.code.toString(10) + + this.code.toString() + ": \"" + this.message + "\" in " + - this.range.source.normalizedPath + + range.source.normalizedPath + ":" + - this.range.line.toString(10) + + range.line.toString() + ":" + - this.range.column.toString(10) + range.column.toString() ); } return ( diagnosticCategoryToString(this.category) + " " + - this.code.toString(10) + + this.code.toString() + ": " + this.message ); @@ -162,15 +166,15 @@ export function formatDiagnosticMessage( sb.push(diagnosticCategoryToString(message.category)); if (useColors) sb.push(COLOR_RESET); sb.push(message.code < 1000 ? " AS" : " TS"); - sb.push(message.code.toString(10)); + sb.push(message.code.toString()); sb.push(": "); sb.push(message.message); // include range information if available - if (message.range) { + var range = message.range; + if (range) { // include context information if requested - let range = message.range; if (showContext) { sb.push("\n"); sb.push(formatDiagnosticContext(range, useColors)); @@ -179,9 +183,9 @@ export function formatDiagnosticMessage( sb.push(" in "); sb.push(range.source.normalizedPath); sb.push("("); - sb.push(range.line.toString(10)); + sb.push(range.line.toString()); sb.push(","); - sb.push(range.column.toString(10)); + sb.push(range.column.toString()); sb.push(")"); let relatedRange = message.relatedRange; @@ -194,9 +198,9 @@ export function formatDiagnosticMessage( sb.push(" in "); sb.push(relatedRange.source.normalizedPath); sb.push("("); - sb.push(relatedRange.line.toString(10)); + sb.push(relatedRange.line.toString()); sb.push(","); - sb.push(relatedRange.column.toString(10)); + sb.push(relatedRange.column.toString()); sb.push(")"); } } @@ -266,16 +270,16 @@ export abstract class DiagnosticEmitter { if (range) { let seen = this.seen; if (seen.has(range.source)) { - let seenInSource = seen.get(range.source)!; + let seenInSource = assert(seen.get(range.source)); if (seenInSource.has(range.start)) { - let seenCodesAtPos = seenInSource.get(range.start)!; + let seenCodesAtPos = assert(seenInSource.get(range.start)); if (seenCodesAtPos.includes(code)) return; seenCodesAtPos.push(code); } else { seenInSource.set(range.start, [ code ]); } } else { - let seenInSource = new Map(); + let seenInSource = new Map(); seenInSource.set(range.start, [ code ]); seen.set(range.source, seenInSource); } diff --git a/src/extra/ast.ts b/src/extra/ast.ts index 2b0d711419..e3c4300542 100644 --- a/src/extra/ast.ts +++ b/src/extra/ast.ts @@ -55,6 +55,7 @@ import { ExportDefaultStatement, ExpressionStatement, ForStatement, + ForOfStatement, IfStatement, ImportStatement, InstanceOfExpression, @@ -251,6 +252,10 @@ export class ASTBuilder { this.visitForStatement(node); break; } + case NodeKind.FOROF: { + this.visitForOfStatement(node); + break; + } case NodeKind.IF: { this.visitIfStatement(node); break; @@ -651,7 +656,7 @@ export class ASTBuilder { } visitFloatLiteralExpression(node: FloatLiteralExpression): void { - this.sb.push(node.value.toString(10)); + this.sb.push(node.value.toString()); } visitInstanceOfExpression(node: InstanceOfExpression): void { @@ -1126,6 +1131,16 @@ export class ASTBuilder { this.visitNode(node.statement); } + visitForOfStatement(node: ForOfStatement): void { + var sb = this.sb; + sb.push("for ("); + this.visitNode(node.variable); + sb.push(" of "); + this.visitNode(node.iterable); + sb.push(") "); + this.visitNode(node.statement); + } + visitFunctionDeclaration(node: FunctionDeclaration, isDefault: bool = false): void { var sb = this.sb; var decorators = node.decorators; diff --git a/src/flow.ts b/src/flow.ts index 061c1aacca..5a1c8a2417 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -213,7 +213,7 @@ export class Flow { static createInline(parentFunction: Function, inlineFunction: Function): Flow { var flow = Flow.create(parentFunction); flow.inlineFunction = inlineFunction; - flow.inlineReturnLabel = inlineFunction.internalName + "|inlined." + (inlineFunction.nextInlineId++).toString(10); + flow.inlineReturnLabel = inlineFunction.internalName + "|inlined." + (inlineFunction.nextInlineId++).toString(); flow.returnType = inlineFunction.signature.returnType; flow.contextualTypeArguments = inlineFunction.contextualTypeArguments; return flow; @@ -228,7 +228,9 @@ export class Flow { /** Gets the actual function being compiled, The inlined function when inlining, otherwise the parent function. */ get actualFunction(): Function { - return this.inlineFunction || this.parentFunction; + var inlineFunction = this.inlineFunction; + if (inlineFunction) return inlineFunction; + return this.parentFunction; } /** Tests if this flow has the specified flag or flags. */ @@ -281,7 +283,7 @@ export class Flow { } var local: Local; if (except) { - if (temps && temps.length) { + if (temps !== null && temps.length > 0) { for (let i = 0, k = temps.length; i < k; ++i) { if (!except.has(temps[i].index)) { local = temps[i]; @@ -297,8 +299,8 @@ export class Flow { } local = parentFunction.addLocal(type); } else { - if (temps && temps.length) { - local = temps.pop()!; + if (temps !== null && temps.length > 0) { + local = assert(temps.pop()); local.type = type; local.flags = CommonFlags.NONE; } else { @@ -315,7 +317,7 @@ export class Flow { local.set(CommonFlags.SCOPED); var scopedLocals = this.scopedLocals; if (!scopedLocals) this.scopedLocals = scopedLocals = new Map(); - scopedLocals.set("~auto" + (this.parentFunction.nextAutoreleaseId++), local); + scopedLocals.set("~auto" + (this.parentFunction.nextAutoreleaseId++).toString(), local); this.setLocalFlag(local.index, LocalFlags.RETAINED); return local; } @@ -329,31 +331,45 @@ export class Flow { assert(local.type != null); // internal error switch (local.type.toNativeType()) { case NativeType.I32: { - temps = parentFunction.tempI32s || (parentFunction.tempI32s = []); + let tempI32s = parentFunction.tempI32s; + if (tempI32s) temps = tempI32s; + else parentFunction.tempI32s = temps = []; break; } case NativeType.I64: { - temps = parentFunction.tempI64s || (parentFunction.tempI64s = []); + let tempI64s = parentFunction.tempI64s; + if (tempI64s) temps = tempI64s; + else parentFunction.tempI64s = temps = []; break; } case NativeType.F32: { - temps = parentFunction.tempF32s || (parentFunction.tempF32s = []); + let tempF32s = parentFunction.tempF32s; + if (tempF32s) temps = tempF32s; + else parentFunction.tempF32s = temps = []; break; } case NativeType.F64: { - temps = parentFunction.tempF64s || (parentFunction.tempF64s = []); + let tempF64s = parentFunction.tempF64s; + if (tempF64s) temps = tempF64s; + else parentFunction.tempF64s = temps = []; break; } case NativeType.V128: { - temps = parentFunction.tempV128s || (parentFunction.tempV128s = []); + let tempV128s = parentFunction.tempV128s; + if (tempV128s) temps = tempV128s; + else parentFunction.tempV128s = temps = []; break; } case NativeType.Anyref: { - temps = parentFunction.tempAnyrefs || (parentFunction.tempAnyrefs = []); + let tempAnyrefs = parentFunction.tempAnyrefs; + if (tempAnyrefs) temps = tempAnyrefs; + else parentFunction.tempAnyrefs = temps = []; break; } case NativeType.Exnref: { - temps = parentFunction.tempExnrefs || (parentFunction.tempExnrefs = []); + let tempExnrefs = parentFunction.tempExnrefs; + if (tempExnrefs) temps = tempExnrefs; + else parentFunction.tempExnrefs = temps = []; break; } default: throw new Error("concrete type expected"); @@ -365,7 +381,7 @@ export class Flow { /** Gets the scoped local of the specified name. */ getScopedLocal(name: string): Local | null { var scopedLocals = this.scopedLocals; - if (scopedLocals && scopedLocals.has(name)) return scopedLocals.get(name)!; + if (scopedLocals !== null && scopedLocals.has(name)) return assert(scopedLocals.get(name)); return null; } @@ -413,9 +429,12 @@ export class Flow { /** Tests if this flow has any scoped locals that must be free'd. */ get hasScopedLocals(): bool { - if (this.scopedLocals) { - for (let scopedLocal of this.scopedLocals.values()) { - if (scopedLocal.is(CommonFlags.SCOPED)) { // otherwise an alias + var scopedLocals = this.scopedLocals; + if (scopedLocals) { + // TODO: for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); + if (local.is(CommonFlags.SCOPED)) { // otherwise an alias return true; } } @@ -425,10 +444,13 @@ export class Flow { /** Frees this flow's scoped variables and returns its parent flow. */ freeScopedLocals(): void { - if (this.scopedLocals) { - for (let scopedLocal of this.scopedLocals.values()) { - if (scopedLocal.is(CommonFlags.SCOPED)) { // otherwise an alias - this.freeTempLocal(scopedLocal); + var scopedLocals = this.scopedLocals; + if (scopedLocals) { + // TODO: for (let local of scopedLocals.values()) { + for (let _values = Map_values(scopedLocals), i = 0, k = _values.length; i < k; ++i) { + let local = unchecked(_values[i]); + if (local.is(CommonFlags.SCOPED)) { // otherwise an alias + this.freeTempLocal(local); } } this.scopedLocals = null; @@ -438,10 +460,14 @@ export class Flow { /** Looks up the local of the specified name in the current scope. */ lookupLocal(name: string): Local | null { var current: Flow | null = this; - var scope: Map | null; - do if ((scope = current.scopedLocals) && scope.has(name)) return scope.get(name)!; - while (current = current.parent); - return this.parentFunction.localsByName.get(name)!; + do { + let scope = current.scopedLocals; + if (scope !== null && scope.has(name)) return assert(scope.get(name)); + current = current.parent; + } while (current); + var localsByName = this.parentFunction.localsByName; + if (localsByName.has(name)) return assert(localsByName.get(name)); + return null; } /** Looks up the element with the specified name relative to the scope of this flow. */ @@ -488,7 +514,9 @@ export class Flow { var stack = parentFunction.breakStack; if (!stack) parentFunction.breakStack = [ id ]; else stack.push(id); - return parentFunction.breakLabel = id.toString(10); + var label = id.toString(); + parentFunction.breakLabel = label; + return label; } /** Pops the most recent break label from the stack. */ @@ -498,7 +526,7 @@ export class Flow { var length = assert(stack.length); stack.pop(); if (length > 1) { - parentFunction.breakLabel = stack[length - 2].toString(10); + parentFunction.breakLabel = stack[length - 2].toString(); } else { parentFunction.breakLabel = null; parentFunction.breakStack = null; @@ -927,11 +955,9 @@ export class Flow { case ExpressionId.Call: { let name = getCallTarget(expr); let program = this.parentFunction.program; - switch (name) { - case program.retainInstance.internalName: { - this.inheritNonnullIfTrue(getCallOperand(expr, 0), iff); - break; - } + if (name == program.retainInstance.internalName) { + // __retain just passes through the argument + this.inheritNonnullIfTrue(getCallOperand(expr, 0), iff); } break; } @@ -1057,7 +1083,7 @@ export class Flow { // overflows if the conversion does (globals are wrapped on set) case ExpressionId.GlobalGet: { // TODO: this is inefficient because it has to read a string - let global = assert(this.parentFunction.program.elementsByName.get(assert(getGlobalGetName(expr)))!); + let global = assert(this.parentFunction.program.elementsByName.get(assert(getGlobalGetName(expr)))); assert(global.kind == ElementKind.GLOBAL); return canConversionOverflow(assert((global).type), type); } @@ -1212,10 +1238,10 @@ export class Flow { default: assert(false); } switch (type.kind) { - case TypeKind.I8: return value < i8.MIN_VALUE || value > i8.MAX_VALUE; - case TypeKind.I16: return value < i16.MIN_VALUE || value > i16.MAX_VALUE; - case TypeKind.U8: return value < 0 || value > u8.MAX_VALUE; - case TypeKind.U16: return value < 0 || value > u16.MAX_VALUE; + case TypeKind.I8: return value < i8.MIN_VALUE || value > i8.MAX_VALUE; + case TypeKind.I16: return value < i16.MIN_VALUE || value > i16.MAX_VALUE; + case TypeKind.U8: return value < 0 || value > u8.MAX_VALUE; + case TypeKind.U16: return value < 0 || value > u16.MAX_VALUE; case TypeKind.BOOL: return (value & ~1) != 0; } break; @@ -1263,7 +1289,7 @@ export class Flow { let instancesByName = program.instancesByName; let instanceName = assert(getCallTarget(expr)); if (instancesByName.has(instanceName)) { - let instance = instancesByName.get(instanceName)!; + let instance = assert(instancesByName.get(instanceName)); assert(instance.kind == ElementKind.FUNCTION); let returnType = (instance).signature.returnType; return !(instance).flow.is(FlowFlags.RETURNS_WRAPPED) @@ -1300,7 +1326,7 @@ export class Flow { if (this.is(FlowFlags.CONDITIONALLY_BREAKS)) sb.push("CONDITIONALLY_BREAKS"); if (this.is(FlowFlags.CONDITIONALLY_CONTINUES)) sb.push("CONDITIONALLY_CONTINUES"); if (this.is(FlowFlags.CONDITIONALLY_ALLOCATES)) sb.push("CONDITIONALLY_ALLOCATES"); - return "Flow(" + this.actualFunction + ")[" + levels.toString() + "] " + sb.join(" "); + return "Flow(" + this.actualFunction.toString() + ")[" + levels.toString() + "] " + sb.join(" "); } } @@ -1312,7 +1338,7 @@ function canConversionOverflow(fromType: Type, toType: Type): bool { } /** Finds all indexes of locals used in the specified expression. */ -export function findUsedLocals(expr: ExpressionRef, used: Set = new Set()): Set { +export function findUsedLocals(expr: ExpressionRef, used: Set = new Set()): Set { traverse(expr, used, findUsedLocalsVisit); return used; } diff --git a/src/glue/binaryen.d.ts b/src/glue/binaryen.d.ts index 4b608b9e1d..547b31e95b 100644 --- a/src/glue/binaryen.d.ts +++ b/src/glue/binaryen.d.ts @@ -14,13 +14,13 @@ export declare function __i32_store16(ptr: usize, value: number): void; export declare function __i32_store(ptr: usize, value: number): void; export declare function __f32_store(ptr: usize, value: number): void; export declare function __f64_store(ptr: usize, value: number): void; -export declare function __i32_load8_s(ptr: usize): number; -export declare function __i32_load8_u(ptr: usize): number; -export declare function __i32_load16_s(ptr: usize): number; -export declare function __i32_load16_u(ptr: usize): number; -export declare function __i32_load(ptr: usize): number; -export declare function __f32_load(ptr: usize): number; -export declare function __f64_load(ptr: usize): number; +export declare function __i32_load8_s(ptr: usize): i8; +export declare function __i32_load8_u(ptr: usize): u8; +export declare function __i32_load16_s(ptr: usize): i16; +export declare function __i32_load16_u(ptr: usize): u16; +export declare function __i32_load(ptr: usize): i32; +export declare function __f32_load(ptr: usize): f32; +export declare function __f64_load(ptr: usize): f64; type BinaryenIndex = u32; @@ -476,7 +476,7 @@ export declare function _BinaryenBinary(module: BinaryenModuleRef, op: BinaryenO export declare function _BinaryenSelect(module: BinaryenModuleRef, condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef; export declare function _BinaryenDrop(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; export declare function _BinaryenReturn(module: BinaryenModuleRef, value: BinaryenExpressionRef): BinaryenExpressionRef; -export declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: usize | 0, operands: usize, numOperands: BinaryenIndex): BinaryenExpressionRef; +export declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: usize, operands: usize, numOperands: BinaryenIndex): BinaryenExpressionRef; export declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef; export declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef; @@ -725,7 +725,7 @@ export declare function _BinaryenRemoveGlobal(module: BinaryenModuleRef, name: u export declare function _BinaryenGlobalGetName(global: BinaryenGlobalRef): usize; export declare function _BinaryenGlobalGetType(global: BinaryenGlobalRef): BinaryenType; export declare function _BinaryenGlobalIsMutable(global: BinaryenGlobalRef): bool; -export declare function _BinaryenGlobalGetInit(global: BinaryenGlobalRef): BinaryenExpressionRef; +export declare function _BinaryenGlobalGetInitExpr(global: BinaryenGlobalRef): BinaryenExpressionRef; type BinaryenEventRef = usize; @@ -735,9 +735,8 @@ export declare function _BinaryenRemoveEvent(module: BinaryenModuleRef, name: us export declare function _BinaryenEventGetName(event: BinaryenEventRef): usize; export declare function _BinaryenEventGetAttribute(event: BinaryenEventRef): u32; -export declare function _BinaryenEventGetType(event: BinaryenEventRef): usize; -export declare function _BinaryenEventGetNumParams(event: BinaryenEventRef): BinaryenIndex; -export declare function _BinaryenEventGetParam(event: BinaryenEventRef, index: BinaryenIndex): BinaryenType; +export declare function _BinaryenEventGetParams(event: BinaryenEventRef): BinaryenType; +export declare function _BinaryenEventGetResults(event: BinaryenEventRef): BinaryenType; export declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, initial: BinaryenIndex, maximum: BinaryenIndex, funcs: usize, numFuncs: BinaryenIndex, offset: BinaryenExpressionRef): void; diff --git a/src/glue/js/float.d.ts b/src/glue/js/float.d.ts index dc28597e54..f40a1dd317 100644 --- a/src/glue/js/float.d.ts +++ b/src/glue/js/float.d.ts @@ -2,5 +2,5 @@ declare function f32_as_i32(value: f32): i32; declare function i32_as_f32(value: i32): f32; -declare function f64_as_i64(value: f64): I64; -declare function i64_as_f64(value: I64): f64; +declare function f64_as_i64(value: f64): i64; +declare function i64_as_f64(value: i64): f64; diff --git a/src/glue/js/i64.d.ts b/src/glue/js/i64.d.ts index 23ca983a6e..7bcc0941b2 100644 --- a/src/glue/js/i64.d.ts +++ b/src/glue/js/i64.d.ts @@ -1,44 +1,44 @@ /** @module glue/js *//***/ -declare type I64 = { __Long__: true }; // opaque - -declare const i64_zero: I64; -declare const i64_one: I64; - -declare function i64_new(lo: i32, hi?: i32): I64; -declare function i64_low(value: I64): i32; -declare function i64_high(value: I64): i32; - -declare function i64_add(left: I64, right: I64): I64; -declare function i64_sub(left: I64, right: I64): I64; -declare function i64_mul(left: I64, right: I64): I64; -declare function i64_div(left: I64, right: I64): I64; -declare function i64_div_u(left: I64, right: I64): I64; -declare function i64_rem(left: I64, right: I64): I64; -declare function i64_rem_u(left: I64, right: I64): I64; -declare function i64_and(left: I64, right: I64): I64; -declare function i64_or(left: I64, right: I64): I64; -declare function i64_xor(left: I64, right: I64): I64; -declare function i64_shl(left: I64, right: I64): I64; -declare function i64_shr(left: I64, right: I64): I64; -declare function i64_shr_u(left: I64, right: I64): I64; -declare function i64_not(value: I64): I64; - -declare function i64_eq(left: I64, right: I64): bool; -declare function i64_ne(left: I64, right: I64): bool; - -declare function i64_align(value: I64, alignment: i32): I64; - -declare function i64_is_i8(value: I64): bool; -declare function i64_is_i16(value: I64): bool; -declare function i64_is_i32(value: I64): bool; -declare function i64_is_u8(value: I64): bool; -declare function i64_is_u16(value: I64): bool; -declare function i64_is_u32(value: I64): bool; -declare function i64_is_bool(value: I64): bool; -declare function i64_is_f32(value: I64): bool; -declare function i64_is_f64(value: I64): bool; - -declare function i64_to_f32(value: I64): f64; -declare function i64_to_f64(value: I64): f64; -declare function i64_to_string(value: I64, unsigned?: bool): string; +declare type i64 = { __Long__: true }; // opaque + +declare const i64_zero: i64; +declare const i64_one: i64; + +declare function i64_new(lo: i32, hi?: i32): i64; +declare function i64_low(value: i64): i32; +declare function i64_high(value: i64): i32; + +declare function i64_add(left: i64, right: i64): i64; +declare function i64_sub(left: i64, right: i64): i64; +declare function i64_mul(left: i64, right: i64): i64; +declare function i64_div(left: i64, right: i64): i64; +declare function i64_div_u(left: i64, right: i64): i64; +declare function i64_rem(left: i64, right: i64): i64; +declare function i64_rem_u(left: i64, right: i64): i64; +declare function i64_and(left: i64, right: i64): i64; +declare function i64_or(left: i64, right: i64): i64; +declare function i64_xor(left: i64, right: i64): i64; +declare function i64_shl(left: i64, right: i64): i64; +declare function i64_shr(left: i64, right: i64): i64; +declare function i64_shr_u(left: i64, right: i64): i64; +declare function i64_not(value: i64): i64; + +declare function i64_eq(left: i64, right: i64): bool; +declare function i64_ne(left: i64, right: i64): bool; + +declare function i64_align(value: i64, alignment: i32): i64; + +declare function i64_is_i8(value: i64): bool; +declare function i64_is_i16(value: i64): bool; +declare function i64_is_i32(value: i64): bool; +declare function i64_is_u8(value: i64): bool; +declare function i64_is_u16(value: i64): bool; +declare function i64_is_u32(value: i64): bool; +declare function i64_is_bool(value: i64): bool; +declare function i64_is_f32(value: i64): bool; +declare function i64_is_f64(value: i64): bool; + +declare function i64_to_f32(value: i64): f64; +declare function i64_to_f64(value: i64): f64; +declare function i64_to_string(value: i64, unsigned?: bool): string; diff --git a/src/glue/js/i64.js b/src/glue/js/i64.js index 4338536350..d685ab75af 100644 --- a/src/glue/js/i64.js +++ b/src/glue/js/i64.js @@ -140,5 +140,5 @@ global.i64_to_f64 = function(value) { }; global.i64_to_string = function(value, unsigned) { - return (unsigned ? value.toUnsigned() : value).toString(10); + return (unsigned ? value.toUnsigned() : value).toString(); }; diff --git a/src/glue/js/index.ts b/src/glue/js/index.ts index b0a101f9e3..fb9f71a11e 100644 --- a/src/glue/js/index.ts +++ b/src/glue/js/index.ts @@ -8,3 +8,4 @@ import "../../../std/portable/index"; import "../binaryen"; import "./float"; import "./i64"; +import "./mapset"; diff --git a/src/glue/js/mapset.d.ts b/src/glue/js/mapset.d.ts new file mode 100644 index 0000000000..7a5e8a5753 --- /dev/null +++ b/src/glue/js/mapset.d.ts @@ -0,0 +1,3 @@ +declare function Map_keys(map: Map): K[]; +declare function Map_values(map: Map): V[]; +declare function Set_values(set: Set): V[]; diff --git a/src/glue/js/mapset.js b/src/glue/js/mapset.js new file mode 100644 index 0000000000..3164caf25e --- /dev/null +++ b/src/glue/js/mapset.js @@ -0,0 +1,11 @@ +global.Map_keys = function(map) { + return Array.from(map.keys()); +}; + +global.Map_values = function(map) { + return Array.from(map.values()); +}; + +global.Set_values = function(set) { + return Array.from(set.values()); +}; diff --git a/src/glue/wasm/float.ts b/src/glue/wasm/float.ts index a7a363a0b7..104994afef 100644 --- a/src/glue/wasm/float.ts +++ b/src/glue/wasm/float.ts @@ -1,20 +1,24 @@ /** @module glue/wasm *//***/ +// @ts-ignore: decorator @global function f32_as_i32(value: f32): i32 { return reinterpret(value); } +// @ts-ignore: decorator @global function i32_as_f32(value: i32): f32 { return reinterpret(value); } +// @ts-ignore: decorator @global function f64_as_i64(value: f64): i64 { return reinterpret(value); } +// @ts-ignore: decorator @global function i64_as_f64(value: i64): f64 { return reinterpret(value); diff --git a/src/glue/wasm/i64.ts b/src/glue/wasm/i64.ts index 633a5f0aad..753bd2f0fd 100644 --- a/src/glue/wasm/i64.ts +++ b/src/glue/wasm/i64.ts @@ -1,181 +1,213 @@ /** @module glue/wasm *//***/ -type I64 = i64; - +// @ts-ignore: decorator @global -const i64_zero: I64 = 0; +const i64_zero: i64 = 0; +// @ts-ignore: decorator @global -const i64_one: I64 = 1; +const i64_one: i64 = 1; +// @ts-ignore: decorator @global -function i64_new(lo: i32, hi: i32 = 0): I64 { +function i64_new(lo: i32, hi: i32 = 0): i64 { return lo | (hi << 32); } +// @ts-ignore: decorator @global -function i64_low(value: I64): i32 { +function i64_low(value: i64): i32 { return value; } +// @ts-ignore: decorator @global -function i64_high(value: I64): i32 { +function i64_high(value: i64): i32 { return (value >>> 32); } +// @ts-ignore: decorator @global -function i64_add(left: I64, right: I64): I64 { +function i64_add(left: i64, right: i64): i64 { return left + right; } +// @ts-ignore: decorator @global -function i64_sub(left: I64, right: I64): I64 { +function i64_sub(left: i64, right: i64): i64 { return left - right; } +// @ts-ignore: decorator @global -function i64_mul(left: I64, right: I64): I64 { +function i64_mul(left: i64, right: i64): i64 { return left * right; } +// @ts-ignore: decorator @global -function i64_div(left: I64, right: I64): I64 { +function i64_div(left: i64, right: i64): i64 { return left / right; } +// @ts-ignore: decorator @global -function i64_div_u(left: I64, right: I64): I64 { +function i64_div_u(left: i64, right: i64): i64 { return left / right; } +// @ts-ignore: decorator @global -function i64_rem(left: I64, right: I64): I64 { +function i64_rem(left: i64, right: i64): i64 { return left % right; } +// @ts-ignore: decorator @global -function i64_rem_u(left: I64, right: I64): I64 { +function i64_rem_u(left: i64, right: i64): i64 { return left % right; } +// @ts-ignore: decorator @global -function i64_and(left: I64, right: I64): I64 { +function i64_and(left: i64, right: i64): i64 { return left & right; } +// @ts-ignore: decorator @global -function i64_or(left: I64, right: I64): I64 { +function i64_or(left: i64, right: i64): i64 { return left | right; } +// @ts-ignore: decorator @global -function i64_xor(left: I64, right: I64): I64 { +function i64_xor(left: i64, right: i64): i64 { return left ^ right; } +// @ts-ignore: decorator @global -function i64_shl(left: I64, right: I64): I64 { +function i64_shl(left: i64, right: i64): i64 { return left << right; } +// @ts-ignore: decorator @global -function i64_shr(left: I64, right: I64): I64 { +function i64_shr(left: i64, right: i64): i64 { return left >> right; } +// @ts-ignore: decorator @global -function i64_shr_u(left: I64, right: I64): I64 { +function i64_shr_u(left: i64, right: i64): i64 { return left >>> right; } +// @ts-ignore: decorator @global -function i64_not(value: I64): I64 { +function i64_not(value: i64): i64 { return ~value; } +// @ts-ignore: decorator @global -function i64_eq(left: I64, right: I64): bool { +function i64_eq(left: i64, right: i64): bool { return left == right; } +// @ts-ignore: decorator @global -function i64_ne(left: I64, right: I64): bool { +function i64_ne(left: i64, right: i64): bool { return left != right; } +// @ts-ignore: decorator @global -function i64_align(value: I64, alignment: i64): I64 { +function i64_align(value: i64, alignment: i64): i64 { var mask: i64 = alignment - 1; assert(alignment && (alignment & mask) == 0); return (value + mask) & ~mask; } +// @ts-ignore: decorator @global -function i64_is_i8(value: I64): bool { - return value >= i8.MIN_VALUE && value <= i8.MAX_VALUE; +function i64_is_i8(value: i64): bool { + return value >= i8.MIN_VALUE && value <= i8.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_i16(value: I64): bool { - return value >= i16.MIN_VALUE && value <= i16.MAX_VALUE; +function i64_is_i16(value: i64): bool { + return value >= i16.MIN_VALUE && value <= i16.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_i32(value: I64): bool { - return value >= i32.MIN_VALUE && value <= i32.MAX_VALUE; +function i64_is_i32(value: i64): bool { + return value >= i32.MIN_VALUE && value <= i32.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_u8(value: I64): bool { - return value >= 0 && value <= u8.MAX_VALUE; +function i64_is_u8(value: i64): bool { + return value >= 0 && value <= u8.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_u16(value: I64): bool { - return value >= 0 && value <= u16.MAX_VALUE; +function i64_is_u16(value: i64): bool { + return value >= 0 && value <= u16.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_u32(value: I64): bool { - return value >= 0 && value <= u32.MAX_VALUE; +function i64_is_u32(value: i64): bool { + return value >= 0 && value <= u32.MAX_VALUE; } +// @ts-ignore: decorator @global -function i64_is_bool(value: I64): bool { +function i64_is_bool(value: i64): bool { return value === 0 || value === 1; } +// @ts-ignore: decorator @global -function i64_is_f32(value: I64): bool { - return value >= f32.MIN_SAFE_INTEGER && value <= f32.MAX_SAFE_INTEGER; +function i64_is_f32(value: i64): bool { + return value >= f32.MIN_SAFE_INTEGER && value <= f32.MAX_SAFE_INTEGER; } +// @ts-ignore: decorator @global -function i64_is_f64(value: I64): bool { - return value >= f64.MIN_SAFE_INTEGER && value <= f64.MAX_SAFE_INTEGER; +function i64_is_f64(value: i64): bool { + return value >= f64.MIN_SAFE_INTEGER && value <= f64.MAX_SAFE_INTEGER; } +// @ts-ignore: decorator @global -function i64_to_f32(value: I64): f32 { +function i64_to_f32(value: i64): f32 { return value; } +// @ts-ignore: decorator @global -function i64_to_f64(value: I64): f64 { +function i64_to_f64(value: i64): f64 { return value; } import { CharCode } from "../../util"; +// @ts-ignore: decorator @global -function i64_to_string(value: I64, unsigned: bool = false): string { - var chars = new Array(); +function i64_to_string(value: i64, unsigned: bool = false): string { + var chars = new Array(); if (!unsigned && value < 0) { chars.push(CharCode.MINUS); value = -value; } do { - chars.push(CharCode._0 + (value % 10)); + chars.push(CharCode._0 + (value % 10)); value = value / 10; } while (value); return String.fromCharCodes(chars); diff --git a/src/glue/wasm/index.ts b/src/glue/wasm/index.ts index 4742c5ad01..6652e0047d 100644 --- a/src/glue/wasm/index.ts +++ b/src/glue/wasm/index.ts @@ -4,6 +4,6 @@ * @preferred *//***/ -import "../binaryen.d"; import "./i64"; import "./float"; +import "./mapset"; diff --git a/src/glue/wasm/mapset.ts b/src/glue/wasm/mapset.ts new file mode 100644 index 0000000000..cd040b37ac --- /dev/null +++ b/src/glue/wasm/mapset.ts @@ -0,0 +1,17 @@ +// @ts-ignore: decorator +@global +function Map_keys(map: Map): K[] { + return map.keys(); // preliminary +} + +// @ts-ignore: decorator +@global +function Map_values(map: Map): V[] { + return map.values(); // preliminary +} + +// @ts-ignore: decorator +@global +function Set_values(set: Set): V[] { + return set.values(); // preliminary +} diff --git a/src/index.ts b/src/index.ts index ea4fa60787..23bf8d6074 100644 --- a/src/index.ts +++ b/src/index.ts @@ -204,20 +204,26 @@ export function buildTSD(program: Program): string { export function buildRTTI(program: Program): string { var sb = new Array(); sb.push("{\n \"names\": [\n"); - for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); sb.push(" \""); sb.push(cls.internalName); sb.push("\",\n"); } sb.push(" ],\n \"base\": [\n"); - for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); let base = cls.base; sb.push(" "); sb.push(base ? base.id.toString() : "0"); sb.push(",\n"); } sb.push(" ],\n \"flags\": [\n"); - for (let cls of program.managedClasses.values()) { + // TODO: for (let cls of program.managedClasses.values()) { + for (let _values = Map_values(program.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let cls = unchecked(_values[i]); sb.push(" "); sb.push(cls.rttiFlags.toString()); sb.push(",\n"); @@ -226,15 +232,11 @@ export function buildRTTI(program: Program): string { return sb.join(""); } -/** Prefix indicating a library file. */ -export { LIBRARY_PREFIX } from "./common"; - // Full API export * from "./ast"; export * from "./common"; export * from "./compiler"; export * from "./definitions"; -export * from "./diagnosticMessages.generated"; export * from "./diagnostics"; export * from "./flow"; export * from "./module"; @@ -243,4 +245,5 @@ export * from "./program"; export * from "./resolver"; export * from "./tokenizer"; export * from "./types"; -export * from "./util/index"; +import * as util from "./util/index"; +export { util }; diff --git a/src/module.ts b/src/module.ts index e136f2a09d..3553a5b5a0 100644 --- a/src/module.ts +++ b/src/module.ts @@ -463,9 +463,9 @@ export enum SIMDLoadOp { export class MemorySegment { buffer: Uint8Array; - offset: I64; + offset: i64; - static create(buffer: Uint8Array, offset: I64): MemorySegment { + static create(buffer: Uint8Array, offset: i64): MemorySegment { var segment = new MemorySegment(); segment.buffer = buffer; segment.offset = offset; @@ -607,7 +607,6 @@ export class Module { offset: Index = 0, align: Index = bytes // naturally aligned by default ): ExpressionRef { - if (type < NativeType.None || type > NativeType.V128) throw new Error("here: " + type); return binaryen._BinaryenStore(this.ref, bytes, offset, align, ptr, value, type); } @@ -790,7 +789,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { strs[i] = this.allocStringCached(names[i]); } - var cArr = allocI32Array(strs); + var cArr = allocPtrArray(strs); var cStr = this.allocStringCached(defaultName); var ret = binaryen._BinaryenSwitch(this.ref, cArr, numNames, cStr, condition, value); binaryen._free(cArr); @@ -806,8 +805,8 @@ export class Module { var cStr = this.allocStringCached(target); var cArr = allocPtrArray(operands); var ret = isReturn - ? binaryen._BinaryenReturnCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType) - : binaryen._BinaryenCall(this.ref, cStr, cArr, operands && operands.length || 0, returnType); + ? binaryen._BinaryenReturnCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType) + : binaryen._BinaryenCall(this.ref, cStr, cArr, operands ? operands.length : 0, returnType); binaryen._free(cArr); return ret; } @@ -829,8 +828,8 @@ export class Module { ): ExpressionRef { var cArr = allocPtrArray(operands); var ret = isReturn - ? binaryen._BinaryenReturnCallIndirect(this.ref, index, cArr, operands && operands.length || 0, params, results) - : binaryen._BinaryenCallIndirect(this.ref, index, cArr, operands && operands.length || 0, params, results); + ? binaryen._BinaryenReturnCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results) + : binaryen._BinaryenCallIndirect(this.ref, index, cArr, operands ? operands.length : 0, params, results); binaryen._free(cArr); return ret; } @@ -1241,10 +1240,10 @@ export class Module { : this.i32(i64_low(offset)); sizs[i] = buffer.length; } - var cArr1 = allocI32Array(segs); + var cArr1 = allocPtrArray(segs); var cArr2 = allocU8Array(psvs); - var cArr3 = allocI32Array(offs); - var cArr4 = allocI32Array(sizs); + var cArr3 = allocPtrArray(offs); + var cArr4 = allocU32Array(sizs); binaryen._BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, cArr4, k, shared); binaryen._free(cArr4); binaryen._free(cArr3); @@ -1269,7 +1268,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { names[i] = this.allocStringCached(funcs[i]); } - var cArr = allocI32Array(names); + var cArr = allocPtrArray(names); binaryen._BinaryenSetFunctionTable(this.ref, initial, maximum, cArr, numNames, offset); binaryen._free(cArr); } @@ -1381,7 +1380,7 @@ export class Module { for (let i = 0; i < numNames; ++i) { names[i] = allocString(passes[i]); } - var cArr = allocI32Array(names); + var cArr = allocPtrArray(names); if (func) { binaryen._BinaryenFunctionRunPasses(func, this.ref, cArr, numNames); } else { @@ -1407,7 +1406,7 @@ export class Module { var func = this.addTemporaryFunction(type, null, expr); var names = this.cachedPrecomputeNames; if (!names) { - this.cachedPrecomputeNames = names = allocI32Array([ + this.cachedPrecomputeNames = names = allocPtrArray([ this.allocStringCached("vacuum"), this.allocStringCached("precompute") ]); @@ -1440,20 +1439,17 @@ export class Module { var cStr = allocString(sourceMapUrl); var binaryPtr: usize = 0; var sourceMapPtr: usize = 0; - try { - binaryen._BinaryenModuleAllocateAndWrite(out, this.ref, cStr); - binaryPtr = binaryen.__i32_load(out); - let binaryLen = binaryen.__i32_load(out + 4); - sourceMapPtr = binaryen.__i32_load(out + 8); - let ret = new BinaryModule(); - ret.output = readBuffer(binaryPtr, binaryLen); - ret.sourceMap = readString(sourceMapPtr); - return ret; - } finally { - if (cStr) binaryen._free(cStr); - if (binaryPtr) binaryen._free(binaryPtr); - if (sourceMapPtr) binaryen._free(sourceMapPtr); - } + binaryen._BinaryenModuleAllocateAndWrite(out, this.ref, cStr); + binaryPtr = assert(binaryen.__i32_load(out)); + var binaryLen = binaryen.__i32_load(out + 4); + sourceMapPtr = binaryen.__i32_load(out + 8); // may be NULL + var ret = new BinaryModule(); + ret.output = readBuffer(binaryPtr, binaryLen); + ret.sourceMap = readString(sourceMapPtr); + binaryen._free(cStr); + binaryen._free(binaryPtr); + if (sourceMapPtr) binaryen._free(sourceMapPtr); + return ret; } toText(): string { @@ -1467,7 +1463,7 @@ export class Module { private cachedStrings: Map = new Map(); private allocStringCached(str: string | null): usize { - if (str == null) return 0; + if (str === null) return 0; var cachedStrings = this.cachedStrings; if (cachedStrings.has(str)) return cachedStrings.get(str); var ptr = allocString(str); @@ -1477,7 +1473,11 @@ export class Module { dispose(): void { assert(this.ref); - for (let ptr of this.cachedStrings.values()) binaryen._free(ptr); + // TODO: for (let ptr of this.cachedStrings.values()) { + for (let _values = Map_values(this.cachedStrings), i = 0, k = _values.length; i < k; ++i) { + let ptr = unchecked(_values[i]); + binaryen._free(ptr); + } this.cachedStrings = new Map(); binaryen._free(this.lit); binaryen._free(this.cachedPrecomputeNames); @@ -1626,8 +1626,8 @@ export function expandType(type: NativeType): NativeType[] { var arity = binaryen._BinaryenTypeArity(type); var cArr = binaryen._malloc(arity << 2); binaryen._BinaryenTypeExpand(type, cArr); - var types = new Array(arity); - for (let i = 0; i < arity; ++i) { + var types = new Array(arity); + for (let i: u32 = 0; i < arity; ++i) { types[i] = binaryen.__i32_load(cArr + (i << 2)); } binaryen._free(cArr); @@ -1660,7 +1660,7 @@ export function getConstValueF32(expr: ExpressionRef): f32 { return binaryen._BinaryenConstGetValueF32(expr); } -export function getConstValueF64(expr: ExpressionRef): f32 { +export function getConstValueF64(expr: ExpressionRef): f64 { return binaryen._BinaryenConstGetValueF64(expr); } @@ -1846,7 +1846,7 @@ export function getFunctionVars(func: FunctionRef): NativeType { // TODO: unify this on Binaryen's side? var count = binaryen._BinaryenFunctionGetNumVars(func); var types = new Array(count); - for (let i = 0; i < count; ++i) { + for (let i: Index = 0; i < count; ++i) { types[i] = binaryen._BinaryenFunctionGetVar(func, i); } return createType(types); @@ -1867,7 +1867,7 @@ export function isGlobalMutable(global: GlobalRef): bool { } export function getGlobalInit(global: GlobalRef): ExpressionRef { - return binaryen._BinaryenGlobalGetInit(global); + return binaryen._BinaryenGlobalGetInitExpr(global); } // events @@ -1880,16 +1880,12 @@ export function getEventAttribute(event: EventRef): u32 { return binaryen._BinaryenEventGetAttribute(event); } -export function getEventType(event: EventRef): string | null { - return readString(binaryen._BinaryenEventGetType(event)); -} - -export function getEventParamCount(event: EventRef): Index { - return binaryen._BinaryenEventGetNumParams(event); +export function getEventParams(event: EventRef): NativeType { + return binaryen._BinaryenEventGetParams(event); } -export function getEventParam(event: EventRef, index: Index): NativeType { - return binaryen._BinaryenEventGetParam(event, index); +export function getEventResults(event: EventRef): NativeType { + return binaryen._BinaryenEventGetResults(event); } export class Relooper { @@ -1989,8 +1985,30 @@ function allocI32Array(i32s: i32[] | null): usize { return ptr; } +function allocU32Array(u32s: u32[] | null): usize { + if (!u32s) return 0; + var ptr = binaryen._malloc(u32s.length << 2); + var idx = ptr; + for (let i = 0, k = u32s.length; i < k; ++i) { + let val = u32s[i]; + binaryen.__i32_store(idx, val); + idx += 4; + } + return ptr; +} + function allocPtrArray(ptrs: usize[] | null): usize { - return allocI32Array(ptrs); // TODO: WASM64 one day + if (!ptrs) return 0; + // TODO: WASM64 + assert(ASC_TARGET != Target.WASM64); + var ptr = binaryen._malloc(ptrs.length << 2); + var idx = ptr; + for (let i = 0, k = ptrs.length; i < k; ++i) { + let val = ptrs[i]; + binaryen.__i32_store(idx, val); + idx += 4; + } + return ptr; } function stringLengthUTF8(str: string): usize { @@ -2018,7 +2036,7 @@ function stringLengthUTF8(str: string): usize { } function allocString(str: string | null): usize { - if (str == null) return 0; + if (str === null) return 0; var ptr = binaryen._malloc(stringLengthUTF8(str) + 1); // the following is based on Emscripten's stringToUTF8Array var idx = ptr; @@ -2060,10 +2078,10 @@ function allocString(str: string | null): usize { return ptr; } -function readBuffer(ptr: usize, length: usize): Uint8Array { +function readBuffer(ptr: usize, length: i32): Uint8Array { var ret = new Uint8Array(length); - for (let i: usize = 0; i < length; ++i) { - ret[i] = binaryen.__i32_load8_u(ptr + i); + for (let i = 0; i < length; ++i) { + ret[i] = binaryen.__i32_load8_u(ptr + i); } return ret; } @@ -2102,16 +2120,16 @@ export function readString(ptr: usize): string | null { } } arr.push(cp); - // if (cp < 0x10000) { - // arr.push(cp); - // } else { - // var ch = cp - 0x10000; - // arr.push(0xD800 | (ch >> 10)); - // arr.push(0xDC00 | (ch & 0x3FF)); - // } + if (cp < 0x10000) { + arr.push(cp); + } else { + let ch = cp - 0x10000; + arr.push(0xD800 | (ch >> 10)); + arr.push(0xDC00 | (ch & 0x3FF)); + } } - // return String.fromCharCodes(arr); - return String.fromCodePoints(arr); + return String.fromCharCodes(arr); + // return String.fromCodePoints(arr); } /** Result structure of {@link Module#toBinary}. */ @@ -2145,7 +2163,7 @@ export function needsExplicitUnreachable(expr: ExpressionRef): bool { export function traverse(expr: ExpressionRef, data: T, visit: (expr: ExpressionRef, data: T) => void): bool { switch (getExpressionId(expr)) { case ExpressionId.Block: { - for (let i = 0, n = binaryen._BinaryenBlockGetNumChildren(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenBlockGetNumChildren(expr); i < n; ++i) { visit(binaryen._BinaryenBlockGetChild(expr, i), data); } break; @@ -2171,13 +2189,13 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Call: { - for (let i = 0, n = binaryen._BinaryenCallGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenCallGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallGetOperand(expr, i), data); } break; } case ExpressionId.CallIndirect: { - for (let i = 0, n = binaryen._BinaryenCallIndirectGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenCallIndirectGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenCallIndirectGetOperand(expr, i), data); } break; @@ -2232,7 +2250,7 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Host: { - for (let i = 0, n = binaryen._BinaryenHostGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenHostGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenHostGetOperand(expr, i), data); } break; @@ -2340,7 +2358,7 @@ export function traverse(expr: ExpressionRef, data: T, visit: (expr: Expressi break; } case ExpressionId.Throw: { - for (let i = 0, n = binaryen._BinaryenThrowGetNumOperands(expr); i < n; ++i) { + for (let i: Index = 0, n = binaryen._BinaryenThrowGetNumOperands(expr); i < n; ++i) { visit(binaryen._BinaryenThrowGetOperand(expr, i), data); } break; diff --git a/src/parser.ts b/src/parser.ts index a77639bd3f..7954e1bf0e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -64,7 +64,7 @@ import { ExportMember, ExportStatement, ExpressionStatement, - ForStatement, + ForOfStatement, FunctionDeclaration, IfStatement, ImportDeclaration, @@ -378,7 +378,7 @@ export class Parser extends DiagnosticEmitter { /** Obtains the next file to parse. */ nextFile(): string | null { var backlog = this.backlog; - return backlog.length ? backlog.shift()! : null; + return backlog.length ? assert(backlog.shift()) : null; } /** Obtains the dependee of the given imported file. */ @@ -532,7 +532,7 @@ export class Parser extends DiagnosticEmitter { } else if (token == Token.IDENTIFIER) { let name = this.parseTypeName(tn); if (!name) return null; - let parameters: NamedTypeNode[] | null = null; + let parameters: TypeNode[] | null = null; let nullable = false; // Name @@ -540,8 +540,8 @@ export class Parser extends DiagnosticEmitter { do { let parameter = this.parseType(tn, true, suppressErrors); if (!parameter) return null; - if (!parameters) parameters = [parameter]; - else parameters.push(parameter); + if (!parameters) parameters = [ parameter ]; + else parameters.push(parameter); } while (tn.skip(Token.COMMA)); if (!tn.skip(Token.GREATERTHAN)) { if (!suppressErrors) { @@ -567,7 +567,8 @@ export class Parser extends DiagnosticEmitter { return null; } } - type = Node.createNamedType(name, parameters || [], nullable, tn.range(startPos, tn.pos)); + if (!parameters) parameters = []; + type = Node.createNamedType(name, parameters, nullable, tn.range(startPos, tn.pos)); } else { if (!suppressErrors) { this.error( @@ -787,8 +788,9 @@ export class Parser extends DiagnosticEmitter { return null; } this.tryParseSignatureIsSignature = true; + if (!parameters) parameters = []; return Node.createFunctionType( - parameters || [], + parameters, returnType, thisType, false, @@ -846,14 +848,15 @@ export class Parser extends DiagnosticEmitter { tn: Tokenizer, flags: CommonFlags, decorators: DecoratorNode[] | null, - startPos: i32 + startPos: i32, + isFor: bool = false ): VariableStatement | null { // at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'? var members = new Array(); do { - let member = this.parseVariableDeclaration(tn, flags, decorators); + let member = this.parseVariableDeclaration(tn, flags, decorators, isFor); if (!member) return null; members.push(member); } while (tn.skip(Token.COMMA)); @@ -866,7 +869,8 @@ export class Parser extends DiagnosticEmitter { parseVariableDeclaration( tn: Tokenizer, parentFlags: CommonFlags, - parentDecorators: DecoratorNode[] | null + parentDecorators: DecoratorNode[] | null, + isFor: bool = false ): VariableDeclaration | null { // before: Identifier (':' Type)? ('=' Expression)? @@ -892,7 +896,7 @@ export class Parser extends DiagnosticEmitter { var type: TypeNode | null = null; if (tn.skip(Token.COLON)) { - type = this.parseType(tn); + type = this.parseType(tn, true); } var initializer: Expression | null = null; @@ -905,7 +909,7 @@ export class Parser extends DiagnosticEmitter { } initializer = this.parseExpression(tn, Precedence.COMMA + 1); if (!initializer) return null; - } else { + } else if (!isFor) { if (flags & CommonFlags.CONST) { if (!(flags & CommonFlags.AMBIENT)) { this.error( @@ -921,7 +925,7 @@ export class Parser extends DiagnosticEmitter { } } var range = Range.join(identifier.range, tn.range()); - if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && initializer) { + if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) != 0 && initializer !== null) { this.error( DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, range); @@ -1184,7 +1188,7 @@ export class Parser extends DiagnosticEmitter { while (!tn.skip(Token.CLOSEPAREN)) { let param = this.parseParameter(tn, isConstructor); // reports if (!param) return null; - if (seenRest && !reportedRest) { + if (seenRest !== null && !reportedRest) { this.error( DiagnosticCode.A_rest_parameter_must_be_last_in_a_parameter_list, seenRest.name.range @@ -1288,6 +1292,7 @@ export class Parser extends DiagnosticEmitter { if (!type) return null; } else { type = Node.createOmittedType(tn.range(tn.pos)); + type = type!; // FIXME: WHY? } let initializer: Expression | null = null; if (tn.skip(Token.EQUALS)) { @@ -1387,7 +1392,7 @@ export class Parser extends DiagnosticEmitter { name.range ); // recoverable } - if (parameters.length && parameters[0].initializer) { + if (parameters.length > 0 && parameters[0].initializer !== null) { this.error( DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, name.range @@ -1414,6 +1419,7 @@ export class Parser extends DiagnosticEmitter { returnType = Node.createOmittedType( tn.range(tn.pos) ); + returnType = returnType!; // FIXME: WHY? if (!isSetter) { this.error( DiagnosticCode.Type_expected, @@ -1522,6 +1528,7 @@ export class Parser extends DiagnosticEmitter { if (!returnType) return null; } else { returnType = Node.createOmittedType(tn.range(tn.pos)); + returnType = returnType!; // FIXME: WHY? } if (arrowKind) { @@ -1771,7 +1778,7 @@ export class Parser extends DiagnosticEmitter { if (!decorators) decorators = [decorator]; else decorators.push(decorator); } while (tn.skip(Token.AT)); - if (decorators && isInterface) { + if (decorators !== null && isInterface) { this.error( DiagnosticCode.Decorators_are_not_valid_here, Range.join(decorators[0].range, decorators[decorators.length - 1].range) @@ -1975,7 +1982,7 @@ export class Parser extends DiagnosticEmitter { tn.skip(Token.SEMICOLON); return retIndex; } - if (!tn.skipIdentifier()) { + if (!tn.skipIdentifier(IdentifierHandling.ALWAYS)) { this.error( DiagnosticCode.Identifier_expected, tn.range() @@ -2046,7 +2053,7 @@ export class Parser extends DiagnosticEmitter { name.range ); } - if (parameters.length && parameters[0].initializer) { + if (parameters.length > 0 && parameters[0].initializer !== null) { this.error( DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, name.range @@ -2071,6 +2078,7 @@ export class Parser extends DiagnosticEmitter { if (!returnType) return null; } else { returnType = Node.createOmittedType(tn.range(tn.pos)); + returnType = returnType!; // FIXME: WHY? if (!isSetter && name.kind != NodeKind.CONSTRUCTOR) { this.error( DiagnosticCode.Type_expected, @@ -2102,7 +2110,7 @@ export class Parser extends DiagnosticEmitter { } body = this.parseBlockStatement(tn, false); if (!body) return null; - } else if (!(flags & CommonFlags.AMBIENT) && !isInterface) { + } else if (!(flags & (CommonFlags.AMBIENT | CommonFlags.ABSTRACT)) && !isInterface) { this.error( DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range() @@ -2181,7 +2189,7 @@ export class Parser extends DiagnosticEmitter { if (!initializer) return null; } let range = tn.range(startPos, tn.pos); - if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) && ((flags & CommonFlags.STATIC) || isInterface || initializer)) { + if ((flags & CommonFlags.DEFINITE_ASSIGNMENT) != 0 && ((flags & CommonFlags.STATIC) != 0 || isInterface || initializer !== null)) { this.error( DiagnosticCode.A_definite_assignment_assertion_is_not_permitted_in_this_context, range @@ -2209,7 +2217,7 @@ export class Parser extends DiagnosticEmitter { // at: '[': 'key' ':' Type ']' ':' Type - if (decorators && decorators.length) { + if (decorators !== null && decorators.length > 0) { this.error( DiagnosticCode.Decorators_are_not_valid_here, Range.join(decorators[0].range, decorators[decorators.length - 1].range) @@ -2424,12 +2432,17 @@ export class Parser extends DiagnosticEmitter { return null; } } + if (asIdentifier) { + return Node.createExportMember( + identifier, + asIdentifier, + Range.join(identifier.range, asIdentifier.range) + ); + } return Node.createExportMember( identifier, - asIdentifier, - asIdentifier - ? Range.join(identifier.range, asIdentifier.range) - : identifier.range + null, + identifier.range ); } else { this.error( @@ -2584,12 +2597,17 @@ export class Parser extends DiagnosticEmitter { return null; } } + if (asIdentifier) { + return Node.createImportDeclaration( + identifier, + asIdentifier, + Range.join(identifier.range, asIdentifier.range) + ); + } return Node.createImportDeclaration( identifier, - asIdentifier, - asIdentifier - ? Range.join(identifier.range, asIdentifier.range) - : identifier.range + null, + identifier.range ); } else { this.error( @@ -2853,7 +2871,7 @@ export class Parser extends DiagnosticEmitter { parseForStatement( tn: Tokenizer - ): ForStatement | null { + ): Statement | null { // at 'for': '(' Statement? Expression? ';' Expression? ')' Statement @@ -2863,17 +2881,72 @@ export class Parser extends DiagnosticEmitter { let initializer: Statement | null = null; if (tn.skip(Token.CONST)) { - initializer = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.CONST, null, tn.tokenPos, true); } else if (tn.skip(Token.LET)) { - initializer = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.LET, null, tn.tokenPos, true); } else if (tn.skip(Token.VAR)) { - initializer = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos); + initializer = this.parseVariable(tn, CommonFlags.NONE, null, tn.tokenPos, true); } else if (!tn.skip(Token.SEMICOLON)) { initializer = this.parseExpressionStatement(tn); if (!initializer) return null; } + if (initializer) { + if (tn.skip(Token.OF)) { + // TODO: for (let [key, val] of ...) + if (initializer.kind == NodeKind.EXPRESSION) { + if ((initializer).expression.kind != NodeKind.IDENTIFIER) { + this.error( + DiagnosticCode.Identifier_expected, + initializer.range + ); + return null; + } + return this.parseForOfStatement(tn, startPos, initializer); + } + if (initializer.kind == NodeKind.VARIABLE) { + let declarations = (initializer).declarations; + for (let i = 0, k = declarations.length; i < k; ++i) { + let declaration = declarations[i]; + let initializer = declaration.initializer; + if (initializer) { + this.error( + DiagnosticCode.The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer, + initializer.range + ); // recoverable + } + } + return this.parseForOfStatement(tn, startPos, initializer); + } + this.error( + DiagnosticCode.Identifier_expected, + initializer.range + ); + return null; + } + // non-for..of needs type or initializer + if (initializer.kind == NodeKind.VARIABLE) { + let declarations = (initializer).declarations; + for (let i = 0, k = declarations.length; i < k; ++i) { + let declaration = declarations[i]; + if (!declaration.initializer) { + if (declaration.flags & CommonFlags.CONST) { + this.error( + DiagnosticCode._const_declarations_must_be_initialized, + declaration.name.range + ); + } else if (!declaration.type) { + this.error( + DiagnosticCode.Type_expected, + declaration.name.range.atEnd + ); + } + } + } + } + } + if (tn.token == Token.SEMICOLON) { let condition: ExpressionStatement | null = null; if (!tn.skip(Token.SEMICOLON)) { @@ -2930,6 +3003,36 @@ export class Parser extends DiagnosticEmitter { return null; } + parseForOfStatement( + tn: Tokenizer, + startPos: i32, + variable: Statement, + ): ForOfStatement | null { + + // at 'of': Expression ')' Statement + + var iterable = this.parseExpression(tn); + if (!iterable) return null; + + if (!tn.skip(Token.CLOSEPAREN)) { + this.error( + DiagnosticCode._0_expected, + tn.range(), ")" + ); + return null; + } + + var statement = this.parseStatement(tn); + if (!statement) return null; + + return Node.createForOfStatement( + variable, + iterable, + statement, + tn.range(startPos, tn.pos) + ); + } + parseIfStatement( tn: Tokenizer ): IfStatement | null { @@ -3436,6 +3539,7 @@ export class Parser extends DiagnosticEmitter { return null; } inner = Node.createParenthesizedExpression(inner, tn.range(startPos, tn.pos)); + inner = inner!; // FIXME: WHY? return this.maybeParseCallExpression(tn, inner); } // ArrayLiteralExpression @@ -3725,6 +3829,7 @@ export class Parser extends DiagnosticEmitter { null, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? expr = this.maybeParseCallExpression(tn, expr); break; } @@ -3755,6 +3860,7 @@ export class Parser extends DiagnosticEmitter { next, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? expr = this.maybeParseCallExpression(tn, expr); break; } @@ -3815,13 +3921,14 @@ export class Parser extends DiagnosticEmitter { } // PropertyAccessExpression case Token.DOT: { - if (tn.skipIdentifier()) { // expr '.' Identifier + if (tn.skipIdentifier(IdentifierHandling.ALWAYS)) { // expr '.' Identifier let next = Node.createIdentifierExpression(tn.readIdentifier(), tn.range()); expr = Node.createPropertyAccessExpression( expr, next, tn.range(startPos, tn.pos) ); + expr = expr!; // FIXME: WHY? } else { let next = this.parseExpression(tn, nextPrecedence + 1); if (!next) return null; diff --git a/src/program.ts b/src/program.ts index d4e740e75e..5b7f48c53e 100644 --- a/src/program.ts +++ b/src/program.ts @@ -37,11 +37,14 @@ import { import { Token, + Range +} from "./tokenizer"; + +import { Node, NodeKind, Source, SourceKind, - Range, DecoratorNode, DecoratorKind, TypeParameterNode, @@ -565,17 +568,19 @@ export class Program extends DiagnosticEmitter { flags: CommonFlags = CommonFlags.NONE ): FunctionDeclaration { var range = this.nativeSource.range; - return Node.createFunctionDeclaration( - Node.createIdentifierExpression(name, range), - null, - this.nativeDummySignature || (this.nativeDummySignature = Node.createFunctionType([], + var signature = this.nativeDummySignature; + if (!signature) { + this.nativeDummySignature = signature = Node.createFunctionType([], Node.createNamedType( // ^ AST signature doesn't really matter, is overridden anyway Node.createSimpleTypeName(CommonNames.void_, range), null, false, range ), - null, false, range) - ), - null, null, flags, ArrowKind.NONE, range + null, false, range + ); + } + return Node.createFunctionDeclaration( + Node.createIdentifierExpression(name, range), + null, signature, null, null, flags, ArrowKind.NONE, range ); } @@ -622,7 +627,7 @@ export class Program extends DiagnosticEmitter { getElementByDeclaration(declaration: DeclarationStatement): DeclaredElement | null { var elementsByDeclaration = this.elementsByDeclaration; return elementsByDeclaration.has(declaration) - ? elementsByDeclaration.get(declaration)! + ? assert(elementsByDeclaration.get(declaration)) : null; } @@ -769,9 +774,12 @@ export class Program extends DiagnosticEmitter { } // queued exports * should be linkable now that all files have been processed - for (let [file, exportsStar] of queuedExportsStar) { - for (let i = 0, k = exportsStar.length; i < k; ++i) { - let exportStar = exportsStar[i]; + // TODO: for (let [file, starExports] of queuedExportsStar) { + for (let _keys = Map_keys(queuedExportsStar), i = 0, k = _keys.length; i < k; ++i) { + let file = _keys[i]; + let starExports = assert(queuedExportsStar.get(file)); + for (let j = 0, l = starExports.length; j < l; ++j) { + let exportStar = unchecked(starExports[j]); let foreignFile = this.lookupForeignFile(exportStar.foreignPath, exportStar.foreignPathAlt); if (!foreignFile) { this.error( @@ -830,8 +838,14 @@ export class Program extends DiagnosticEmitter { } // queued exports should be resolvable now that imports are finalized - for (let [file, exports] of queuedExports) { - for (let [exportName, queuedExport] of exports) { + // TODO: for (let [file, exports] of queuedExports) { + for (let _keys = Map_keys(queuedExports), i = 0, k = _keys.length; i < k; ++i) { + let file = unchecked(_keys[i]); + let exports = assert(queuedExports.get(file)); + // TODO: for (let [exportName, queuedExport] of exports) { + for (let exportNames = Map_keys(exports), j = 0, l = exportNames.length; j < l; ++j) { + let exportName = unchecked(exportNames[j]); + let queuedExport = assert(exports.get(exportName)); let localName = queuedExport.localIdentifier.text; let foreignPath = queuedExport.foreignPath; if (foreignPath) { // i.e. export { foo [as bar] } from "./baz" @@ -856,7 +870,7 @@ export class Program extends DiagnosticEmitter { file.ensureExport(exportName, element); } else { let globalElement = this.lookupGlobal(localName); - if (globalElement && globalElement instanceof DeclaredElement) { // export { memory } + if (globalElement !== null && isDeclaredElement(globalElement.kind)) { // export { memory } file.ensureExport(exportName, globalElement); } else { this.error( @@ -946,7 +960,10 @@ export class Program extends DiagnosticEmitter { { let globalAliases = options.globalAliases; if (globalAliases) { - for (let [alias, name] of globalAliases) { + // TODO: for (let [alias, name] of globalAliases) { + for (let _keys = Map_keys(globalAliases), i = 0, k = _keys.length; i < k; ++i) { + let alias = unchecked(_keys[i]); + let name = assert(globalAliases.get(alias)); if (!name.length) continue; // explicitly disabled let firstChar = name.charCodeAt(0); if (firstChar >= CharCode._0 && firstChar <= CharCode._9) { @@ -983,10 +1000,11 @@ export class Program extends DiagnosticEmitter { this.allocArrayInstance = this.requireFunction(CommonNames.allocArray); // mark module exports, i.e. to apply proper wrapping behavior on the boundaries - for (let file of this.filesByName.values()) { - let exports = file.exports; - if (exports !== null && file.source.sourceKind == SourceKind.USER_ENTRY) { - for (let element of exports.values()) this.markModuleExport(element); + // TODO: for (let file of this.filesByName.values()) { + for (let _values = Map_values(this.filesByName), i = 0, k = _values.length; i < k; ++i) { + let file = unchecked(_values[i]); + if (file.source.sourceKind == SourceKind.USER_ENTRY) { + this.markModuleExports(file); } } } @@ -1022,13 +1040,37 @@ export class Program extends DiagnosticEmitter { return resolved; } + /** Marks all exports of the specified file as module exports. */ + private markModuleExports(file: File): void { + var exports = file.exports; + if (exports) { + // TODO: for (let element of exports.values()) { + for (let _values = Map_values(exports), j = 0, l = _values.length; j < l; ++j) { + let element = unchecked(_values[j]); + this.markModuleExport(element); + } + } + var exportsStar = file.exportsStar; + if (exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + this.markModuleExports(exportsStar[i]); + } + } + } + /** Marks an element and its children as a module export. */ private markModuleExport(element: Element): void { element.set(CommonFlags.MODULE_EXPORT); switch (element.kind) { case ElementKind.CLASS_PROTOTYPE: { let instanceMembers = (element).instanceMembers; - if (instanceMembers) for (let member of instanceMembers.values()) this.markModuleExport(member); + if (instanceMembers) { + // TODO: for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.markModuleExport(member); + } + } break; } case ElementKind.PROPERTY_PROTOTYPE: { @@ -1043,9 +1085,13 @@ export class Program extends DiagnosticEmitter { case ElementKind.FIELD: case ElementKind.CLASS: assert(false); // assumes that there are no instances yet } - { - let members = element.members; - if (members) for (let member of members.values()) this.markModuleExport(member); + var staticMembers = element.members; + if (staticMembers) { + // TODO: for (let member of staticMembers.values()) { + for (let _values = Map_values(staticMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); + this.markModuleExport(member); + } } } @@ -1075,7 +1121,7 @@ export class Program extends DiagnosticEmitter { } /** Registers a constant integer value within the global scope. */ - registerConstantInteger(name: string, type: Type, value: I64): void { + registerConstantInteger(name: string, type: Type, value: i64): void { assert(type.is(TypeFlags.INTEGER)); // must be an integer type var global = new Global( name, @@ -1104,7 +1150,7 @@ export class Program extends DiagnosticEmitter { ensureGlobal(name: string, element: DeclaredElement): DeclaredElement { var elementsByName = this.elementsByName; if (elementsByName.has(name)) { - let existing = elementsByName.get(name)!; + let existing = assert(elementsByName.get(name)); // NOTE: this is effectively only performed when merging native types with // their respective namespaces in std/builtins, but can also trigger when a // user has multiple global elements of the same name in different files, @@ -1138,14 +1184,14 @@ export class Program extends DiagnosticEmitter { /** Looks up the element of the specified name in the global scope. */ lookupGlobal(name: string): Element | null { var elements = this.elementsByName; - if (elements.has(name)) return elements.get(name)!; + if (elements.has(name)) return assert(elements.get(name)); return null; } /** Looks up the element of the specified name in the global scope. Errors if not present. */ requireGlobal(name: string): Element { var elements = this.elementsByName; - if (elements.has(name)) return elements.get(name)!; + if (elements.has(name)) return assert(elements.get(name)); throw new Error("missing global"); } @@ -1158,9 +1204,9 @@ export class Program extends DiagnosticEmitter { ): File | null { var filesByName = this.filesByName; return filesByName.has(foreignPath) - ? filesByName.get(foreignPath)! + ? assert(filesByName.get(foreignPath)) : filesByName.has(foreignPathAlt) - ? filesByName.get(foreignPathAlt)! + ? assert(filesByName.get(foreignPathAlt)) : null; } @@ -1185,12 +1231,13 @@ export class Program extends DiagnosticEmitter { // otherwise traverse queued exports if (queuedExports.has(foreignFile)) { - let fileQueuedExports = queuedExports.get(foreignFile)!; + let fileQueuedExports = assert(queuedExports.get(foreignFile)); if (fileQueuedExports.has(foreignName)) { - let queuedExport = fileQueuedExports.get(foreignName)!; - if (queuedExport.foreignPath) { // imported from another file + let queuedExport = assert(fileQueuedExports.get(foreignName)); + let queuedExportForeignPath = queuedExport.foreignPath; + if (queuedExportForeignPath) { // imported from another file foreignName = queuedExport.localIdentifier.text; - foreignPath = queuedExport.foreignPath; + foreignPath = queuedExportForeignPath; foreignPathAlt = assert(queuedExport.foreignPathAlt); continue; } else { // local element of this file @@ -1411,7 +1458,8 @@ export class Program extends DiagnosticEmitter { case DecoratorKind.OPERATOR_BINARY: case DecoratorKind.OPERATOR_PREFIX: case DecoratorKind.OPERATOR_POSTFIX: { - let numArgs = decorator.arguments && decorator.arguments.length || 0; + let args = decorator.arguments; + let numArgs = args ? args.length : 0; if (numArgs == 1) { let firstArg = (decorator.arguments)[0]; if ( @@ -1446,7 +1494,7 @@ export class Program extends DiagnosticEmitter { } else { this.error( DiagnosticCode.Expected_0_arguments_but_got_1, - decorator.range, "1", numArgs.toString(10) + decorator.range, "1", numArgs.toString() ); } } @@ -1465,8 +1513,8 @@ export class Program extends DiagnosticEmitter { var name = declaration.name.text; if (declaration.is(CommonFlags.STATIC)) { let parentMembers = parent.members; - if (parentMembers && parentMembers.has(name)) { - let element = parentMembers.get(name)!; + if (parentMembers !== null && parentMembers.has(name)) { + let element = assert(parentMembers.get(name)); if (element.kind == ElementKind.PROPERTY_PROTOTYPE) return element; } else { let element = new PropertyPrototype(name, parent, declaration); @@ -1475,8 +1523,8 @@ export class Program extends DiagnosticEmitter { } } else { let parentMembers = parent.instanceMembers; - if (parentMembers && parentMembers.has(name)) { - let element = parentMembers.get(name); + if (parentMembers !== null && parentMembers.has(name)) { + let element = assert(parentMembers.get(name)); if (element.kind == ElementKind.PROPERTY_PROTOTYPE) return element; } else { let element = new PropertyPrototype(name, parent, declaration); @@ -1597,9 +1645,9 @@ export class Program extends DiagnosticEmitter { } } else { // export * from "./baz" let queued: QueuedExportStar[]; - if (queuedExportsStar.has(parent)) queued = queuedExportsStar.get(parent)!; + if (queuedExportsStar.has(parent)) queued = assert(queuedExportsStar.get(parent)); else queuedExportsStar.set(parent, queued = []); - let foreignPath = assert(statement.internalPath); // must be set for export * + let foreignPath = statement.internalPath!; // must be set for export * queued.push(new QueuedExportStar( foreignPath, foreignPath.endsWith(INDEX_SUFFIX) // strip or add index depending on what's already present @@ -1643,7 +1691,7 @@ export class Program extends DiagnosticEmitter { // otherwise queue it } else { let queued: Map; - if (queuedExports.has(localFile)) queued = queuedExports.get(localFile)!; + if (queuedExports.has(localFile)) queued = assert(queuedExports.get(localFile)); else queuedExports.set(localFile, queued = new Map()); queued.set(foreignName, new QueuedExport( member.localName, @@ -1655,7 +1703,7 @@ export class Program extends DiagnosticEmitter { // foreign element, i.e. export { foo } from "./bar" } else { let queued: Map; - if (queuedExports.has(localFile)) queued = queuedExports.get(localFile)!; + if (queuedExports.has(localFile)) queued = assert(queuedExports.get(localFile)); else queuedExports.set(localFile, queued = new Map()); queued.set(foreignName, new QueuedExport( member.localName, @@ -1708,7 +1756,7 @@ export class Program extends DiagnosticEmitter { if (!exports) parent.exports = exports = new Map(); else { if (exports.has("default")) { - let existing = exports.get("default")!; + let existing = assert(exports.get("default")); this.errorRelated( DiagnosticCode.Duplicate_identifier_0, declaration.name.range, @@ -1744,16 +1792,19 @@ export class Program extends DiagnosticEmitter { queuedExports ); } - } else if (statement.namespaceName) { // import * as foo from "./bar" - queuedImports.push(new QueuedImport( - parent, - statement.namespaceName, - null, // indicates import * - statement.internalPath, - statement.internalPath + INDEX_SUFFIX - )); } else { - // import "./foo" + let namespaceName = statement.namespaceName; + if (namespaceName) { // import * as foo from "./bar" + queuedImports.push(new QueuedImport( + parent, + namespaceName, + null, // indicates import * + statement.internalPath, + statement.internalPath + INDEX_SUFFIX + )); + } else { + // import "./foo" + } } } @@ -1872,7 +1923,7 @@ export class Program extends DiagnosticEmitter { queuedExtends: ClassPrototype[], /** So far queued `implements` clauses. */ queuedImplements: ClassPrototype[] - ): Namespace | null { + ): DeclaredElement | null { var name = declaration.name.text; var original = new Namespace( name, @@ -1995,9 +2046,10 @@ export class Program extends DiagnosticEmitter { /** Finds all cyclic classes. */ findCyclicClasses(): Set { - var managedClasses = this.managedClasses; var cyclics = new Set(); - for (let instance of managedClasses.values()) { + // TODO: for (let instance of this.managedClasses.values()) { + for (let _values = Map_values(this.managedClasses), i = 0, k = _values.length; i < k; ++i) { + let instance = unchecked(_values[i]); if (!instance.isAcyclic) cyclics.add(instance); } return cyclics; @@ -2137,8 +2189,10 @@ export abstract class Element { /** Gets the enclosing file. */ get file(): File { var current: Element = this; - do if ((current = current.parent).kind == ElementKind.FILE) return current; - while (true); + do { + current = current.parent; + if (current.kind == ElementKind.FILE) return current; + } while (true); } /** Tests if this element has a specific flag or flags. */ @@ -2155,7 +2209,7 @@ export abstract class Element { /** Looks up the element with the specified name within this element. */ lookupInSelf(name: string): DeclaredElement | null { var members = this.members; - if (members && members.has(name)) return members.get(name)!; + if (members !== null && members.has(name)) return assert(members.get(name)); return null; } @@ -2168,7 +2222,7 @@ export abstract class Element { var members = this.members; if (!members) this.members = members = new Map(); else if (members.has(name)) { - let existing = members.get(name)!; + let existing = assert(members.get(name)); if (existing.parent !== this) { // override non-own element } else { @@ -2176,7 +2230,9 @@ export abstract class Element { if (merged) { element = merged; // use merged element } else { - let reportedIdentifier = localIdentifierIfImport || element.identifierNode; + let reportedIdentifier = localIdentifierIfImport + ? localIdentifierIfImport + : element.identifierNode; if (isDeclaredElement(existing.kind)) { this.program.errorRelated( DiagnosticCode.Duplicate_identifier_0, @@ -2206,7 +2262,7 @@ export abstract class Element { /** Returns a string representation of this element. */ toString(): string { - return ElementKind[this.kind] + ":" + this.internalName; + return this.internalName + ", kind=" + this.kind.toString(); } } @@ -2395,7 +2451,7 @@ export class File extends Element { /** Looks up the export of the specified name. */ lookupExport(name: string): DeclaredElement | null { var exports = this.exports; - if (exports && exports.has(name)) return exports.get(name)!; + if (exports !== null && exports.has(name)) return assert(exports.get(name)); var exportsStar = this.exportsStar; if (exportsStar) { for (let i = 0, k = exportsStar.length; i < k; ++i) { @@ -2411,13 +2467,28 @@ export class File extends Element { var declaration = this.program.makeNativeNamespaceDeclaration(name); declaration.name = localIdentifier; var ns = new Namespace(name, parent, declaration); + ns.set(CommonFlags.SCOPED); + this.copyExportsToNamespace(ns); + return ns; + } + + /** Recursively copies the exports of this file to the specified namespace. */ + private copyExportsToNamespace(ns: Namespace): void { var exports = this.exports; if (exports) { - for (let [memberName, member] of exports) { + // TODO: for (let [memberName, member] of exports) { + for (let _keys = Map_keys(exports), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(exports.get(memberName)); ns.add(memberName, member); } } - return ns; + var exportsStar = this.exportsStar; + if (exportsStar) { + for (let i = 0, k = exportsStar.length; i < k; ++i) { + exportsStar[i].copyExportsToNamespace(ns); + } + } } } @@ -2489,8 +2560,9 @@ export class Namespace extends DeclaredElement { /* @override */ lookup(name: string): Element | null { - return this.lookupInSelf(name) - || this.parent.lookup(name); + var inSelf = this.lookupInSelf(name); + if (inSelf) return inSelf; + return this.parent.lookup(name); } } @@ -2522,8 +2594,9 @@ export class Enum extends TypedElement { /* @override */ lookup(name: string): Element | null { - return this.lookupInSelf(name) - || this.parent.lookup(name); + var inSelf = this.lookupInSelf(name); + if (inSelf) return inSelf; + return this.parent.lookup(name); } } @@ -2543,7 +2616,7 @@ export abstract class VariableLikeElement extends TypedElement { /** Constant value kind. */ constantValueKind: ConstantValueKind = ConstantValueKind.NONE; /** Constant integer value, if applicable. */ - constantIntegerValue: I64; + constantIntegerValue: i64; /** Constant float value, if applicable. */ constantFloatValue: f64; @@ -2580,7 +2653,7 @@ export abstract class VariableLikeElement extends TypedElement { } /** Applies a constant integer value to this element. */ - setConstantIntegerValue(value: I64, type: Type): void { + setConstantIntegerValue(value: i64, type: Type): void { assert(type.is(TypeFlags.INTEGER)); this.type = type; this.constantValueKind = ConstantValueKind.INTEGER; @@ -2772,7 +2845,7 @@ export class FunctionPrototype extends DeclaredElement { assert(!this.isBound); var boundPrototypes = this.boundPrototypes; if (!boundPrototypes) this.boundPrototypes = boundPrototypes = new Map(); - else if (boundPrototypes.has(classInstance)) return boundPrototypes.get(classInstance)!; + else if (boundPrototypes.has(classInstance)) return assert(boundPrototypes.get(classInstance)); var declaration = this.declaration; assert(declaration.kind == NodeKind.METHODDECLARATION); var bound = new FunctionPrototype( this.name, @@ -2790,7 +2863,7 @@ export class FunctionPrototype extends DeclaredElement { /** Gets the resolved instance for the specified instance key, if already resolved. */ getResolvedInstance(instanceKey: string): Function | null { var instances = this.instances; - if (instances && instances.has(instanceKey)) return instances.get(instanceKey); + if (instances !== null && instances.has(instanceKey)) return instances.get(instanceKey); return null; } @@ -2905,12 +2978,13 @@ export class Function extends TypedElement { var localName = name !== null ? name : "var$" + localIndex.toString(); + if (!declaration) declaration = this.program.makeNativeVariableDeclaration(localName); var local = new Local( localName, localIndex, type, this, - declaration || this.program.makeNativeVariableDeclaration(localName) + declaration ); if (name) { if (this.localsByName.has(name)) throw new Error("duplicate local name"); @@ -2924,7 +2998,7 @@ export class Function extends TypedElement { /* @override */ lookup(name: string): Element | null { var locals = this.localsByName; - if (locals.has(name)) return locals.get(name)!; + if (locals.has(name)) return assert(locals.get(name)); return this.parent.lookup(name); } @@ -3207,6 +3281,8 @@ export class ClassPrototype extends DeclaredElement { overloadPrototypes: Map = new Map(); /** Already resolved instances. */ instances: Map | null = null; + /** Classes extending this class. */ + extendees: Set = new Set(); constructor( /** Simple name. */ @@ -3259,7 +3335,8 @@ export class ClassPrototype extends DeclaredElement { if (seen.has(current)) break; seen.add(current); if (current === basePtototype) return true; - } while (current = current.basePrototype); + current = current.basePrototype; + } while (current); return false; } @@ -3269,7 +3346,7 @@ export class ClassPrototype extends DeclaredElement { var instanceMembers = this.instanceMembers; if (!instanceMembers) this.instanceMembers = instanceMembers = new Map(); else if (instanceMembers.has(name)) { - let existing = instanceMembers.get(name)!; + let existing = assert(instanceMembers.get(name)); let merged = tryMerge(existing, element); if (!merged) { if (isDeclaredElement(existing.kind)) { @@ -3300,7 +3377,7 @@ export class ClassPrototype extends DeclaredElement { /** Gets the resolved instance for the specified instance key, if already resolved. */ getResolvedInstance(instanceKey: string): Class | null { var instances = this.instances; - if (instances && instances.has(instanceKey)) return instances.get(instanceKey); + if (instances !== null && instances.has(instanceKey)) return instances.get(instanceKey); return null; } @@ -3332,7 +3409,7 @@ export class Class extends TypedElement { /** Resolved type arguments. */ typeArguments: Type[] | null; /** Base class, if applicable. */ - base: Class | null; + base: Class | null = null; /** Contextual type arguments for fields and methods. */ contextualTypeArguments: Map | null = null; /** Current member memory offset. */ @@ -3422,7 +3499,7 @@ export class Class extends TypedElement { this.contextualTypeArguments.set(typeParameters[i].name.text, typeArguments[i]); } } - } else if (typeParameters && typeParameters.length) { + } else if (typeParameters !== null && typeParameters.length > 0) { throw new Error("type argument count mismatch"); } registerConcreteElement(program, this); @@ -3433,11 +3510,38 @@ export class Class extends TypedElement { assert(!this.base); this.base = base; + // Remember extendees and mark overloaded methods virtual + var basePrototype: ClassPrototype = base.prototype; + var thisPrototype = this.prototype; + assert(basePrototype != thisPrototype); + basePrototype.extendees.add(thisPrototype); + var thisInstanceMembers = thisPrototype.instanceMembers; + if (thisInstanceMembers) { + do { + let baseInstanceMembers = basePrototype.instanceMembers; + if (baseInstanceMembers) { + for (let _keys = Map_keys(baseInstanceMembers), i = 0, k = _keys.length; i < k; ++i) { + let memberName = _keys[i]; + let member = assert(baseInstanceMembers.get(memberName)); + if (thisInstanceMembers.has(memberName)) { + member.set(CommonFlags.VIRTUAL); + } + } + } + let nextPrototype = basePrototype.basePrototype; + if (!nextPrototype) break; + basePrototype = nextPrototype; + } while (true); + } + // Inherit contextual type arguments from base class var inheritedTypeArguments = base.contextualTypeArguments; if (inheritedTypeArguments) { let contextualTypeArguments = this.contextualTypeArguments; - for (let [baseName, baseType] of inheritedTypeArguments) { + // TODO: for (let [baseName, baseType] of inheritedTypeArguments) { + for (let _keys = Map_keys(inheritedTypeArguments), i = 0, k = _keys.length; i < k; ++i) { + let baseName = unchecked(_keys[i]); + let baseType = assert(inheritedTypeArguments.get(baseName)); if (!contextualTypeArguments) { this.contextualTypeArguments = contextualTypeArguments = new Map(); contextualTypeArguments.set(baseName, baseType); @@ -3451,8 +3555,10 @@ export class Class extends TypedElement { /** Tests if a value of this class type is assignable to a target of the specified class type. */ isAssignableTo(target: Class): bool { var current: Class | null = this; - do if (current == target) return true; - while (current = current.base); + do { + if (current == target) return true; + current = current.base; + } while (current); return false; } @@ -3480,7 +3586,8 @@ export class Class extends TypedElement { let overload = overloads.get(kind); if (overload) return overload; } - } while (instance = instance.base); + instance = instance.base; + } while (instance); return null; } @@ -3547,8 +3654,10 @@ export class Class extends TypedElement { /** Gets the concrete type arguments to the specified extendend prototype. */ getTypeArgumentsTo(extendedPrototype: ClassPrototype): Type[] | null { var current: Class | null = this; - do if (current.prototype === extendedPrototype) return current.typeArguments; - while (current = current.base); + do { + if (current.prototype === extendedPrototype) return current.typeArguments; + current = current.base; + } while (current); return null; } @@ -3560,21 +3669,22 @@ export class Class extends TypedElement { while (current.base !== abvInstance) { current = assert(current.base); } - switch (current.prototype) { - case program.i8ArrayPrototype: return Type.i8; - case program.i16ArrayPrototype: return Type.i16; - case program.i32ArrayPrototype: return Type.i32; - case program.i64ArrayPrototype: return Type.i64; - case program.u8ArrayPrototype: - case program.u8ClampedArrayPrototype: return Type.u8; - case program.u16ArrayPrototype: return Type.u16; - case program.u32ArrayPrototype: return Type.u32; - case program.u64ArrayPrototype: return Type.u64; - case program.f32ArrayPrototype: return Type.f32; - case program.f64ArrayPrototype: return Type.f64; - case program.arrayPrototype: return assert(this.getTypeArgumentsTo(program.arrayPrototype))[0]; - default: assert(false); - } + var prototype = current.prototype; + if (prototype == program.arrayPrototype) { + return this.getTypeArgumentsTo(program.arrayPrototype)![0]; + } + if (prototype == program.i8ArrayPrototype) return Type.i8; + if (prototype == program.i16ArrayPrototype) return Type.i16; + if (prototype == program.i32ArrayPrototype) return Type.i32; + if (prototype == program.i64ArrayPrototype) return Type.i64; + if (prototype == program.u8ArrayPrototype) return Type.u8; + if (prototype == program.u8ClampedArrayPrototype) return Type.u8; + if (prototype == program.u16ArrayPrototype) return Type.u16; + if (prototype == program.u32ArrayPrototype) return Type.u32; + if (prototype == program.u64ArrayPrototype) return Type.u64; + if (prototype == program.f32ArrayPrototype) return Type.f32; + if (prototype == program.f64ArrayPrototype) return Type.f64; + assert(false); return Type.void; } @@ -3606,13 +3716,15 @@ export class Class extends TypedElement { // Find out if any field references 'other' directly or indirectly var current: Class | null; - var members = this.members; - if (members) { - for (let member of members.values()) { + var instanceMembers = this.members; + if (instanceMembers) { + // TODO: for (let member of instanceMembers.values()) { + for (let _values = Map_values(instanceMembers), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); if (member.kind == ElementKind.FIELD) { - let type = (member).type; - if (type.is(TypeFlags.REFERENCE)) { - if ((current = type.classReference) !== null && ( + let fieldType = (member).type; + if (fieldType.is(TypeFlags.REFERENCE)) { + if ((current = fieldType.classReference) !== null && ( current === other || current.cyclesTo(other, except) )) return true; @@ -3625,7 +3737,7 @@ export class Class extends TypedElement { var basePrototype: ClassPrototype | null; // Arrayother?> - if ((basePrototype = this.program.arrayPrototype) && this.prototype.extends(basePrototype)) { + if ((basePrototype = this.program.arrayPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 1); if ( @@ -3637,7 +3749,7 @@ export class Class extends TypedElement { ) return true; // Setother?> - } else if ((basePrototype = this.program.setPrototype) && this.prototype.extends(basePrototype)) { + } else if ((basePrototype = this.program.setPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 1); if ( @@ -3649,7 +3761,7 @@ export class Class extends TypedElement { ) return true; // Mapother?,V->other?> - } else if ((basePrototype = this.program.mapPrototype) && this.prototype.extends(basePrototype)) { + } else if ((basePrototype = this.program.mapPrototype) !== null && this.prototype.extends(basePrototype)) { let typeArguments = assert(this.getTypeArgumentsTo(basePrototype)); assert(typeArguments.length == 2); if ( @@ -3820,7 +3932,10 @@ function copyMembers(src: Element, dest: Element): void { if (srcMembers) { let destMembers = dest.members; if (!destMembers) dest.members = destMembers = new Map(); - for (let [memberName, member] of srcMembers) { + // TODO: for (let [memberName, member] of srcMembers) { + for (let _keys = Map_keys(srcMembers), i = 0, k = _keys.length; i < k; ++i) { + let memberName = unchecked(_keys[i]); + let member = assert(srcMembers.get(memberName)); destMembers.set(memberName, member); } } diff --git a/src/resolver.ts b/src/resolver.ts index 0cd448561b..1843cb9e34 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -34,6 +34,10 @@ import { Flow } from "./flow"; +import { + Range +} from "./tokenizer"; + import { FunctionTypeNode, ParameterKind, @@ -43,7 +47,6 @@ import { TypeName, TypeParameterNode, Node, - Range, IdentifierExpression, CallExpression, ElementAccessExpression, @@ -178,8 +181,8 @@ export class Resolver extends DiagnosticEmitter { if (isSimpleType) { let simpleName = nameNode.identifier.text; if (ctxTypes !== null && ctxTypes.has(simpleName)) { - let type = ctxTypes.get(simpleName)!; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + let type = assert(ctxTypes.get(simpleName)); + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -205,14 +208,15 @@ export class Resolver extends DiagnosticEmitter { if (!element) return null; // Use shadow type if present (i.e. namespace sharing a type) - if (element.shadowType) { - element = element.shadowType; + var shadowType = element.shadowType; + if (shadowType) { + element = shadowType; } else { // Handle enums (become i32) if (element.kind == ElementKind.ENUM) { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -251,7 +255,7 @@ export class Resolver extends DiagnosticEmitter { // Shortcut already resolved (mostly builtins) if (element.is(CommonFlags.RESOLVED)) { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -277,12 +281,11 @@ export class Resolver extends DiagnosticEmitter { // Handle special built-in types if (isSimpleType) { - switch (nameNode.identifier.text) { - case CommonNames.native: return this.resolveBuiltinNativeType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.indexof: return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.valueof: return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode); - case CommonNames.returnof: return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode); - } + let text = nameNode.identifier.text; + if (text == CommonNames.native) return this.resolveBuiltinNativeType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.indexof) return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.valueof) return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode); + if (text == CommonNames.returnof) return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode); } // Resolve normally @@ -298,7 +301,7 @@ export class Resolver extends DiagnosticEmitter { reportMode ); if (!typeArguments) return null; - } else if (typeArgumentNodes && typeArgumentNodes.length) { + } else if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { this.error( DiagnosticCode.Type_0_is_not_generic, node.range, nameNode.identifier.text @@ -432,11 +435,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", numTypeArguments.toString() ); } return null; @@ -475,11 +480,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", numTypeArguments.toString() ); } return null; @@ -526,11 +533,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", numTypeArguments.toString() ); } return null; @@ -570,11 +579,13 @@ export class Resolver extends DiagnosticEmitter { reportMode: ReportMode = ReportMode.REPORT ): Type | null { var typeArgumentNodes = node.typeArguments; - if (!(typeArgumentNodes && typeArgumentNodes.length == 1)) { + if (!typeArgumentNodes || typeArgumentNodes.length != 1) { if (reportMode == ReportMode.REPORT) { + let numTypeArguments = 0; + if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length; this.error( DiagnosticCode.Expected_0_type_arguments_but_got_1, - node.range, "1", (typeArgumentNodes ? typeArgumentNodes.length : 1).toString(10) + node.range, "1", numTypeArguments.toString() ); } return null; @@ -601,7 +612,7 @@ export class Resolver extends DiagnosticEmitter { /** Contextual element. */ ctxElement: Element, /** How to proceed with eventual diagnostics. */ - reportMode = ReportMode.REPORT + reportMode: ReportMode = ReportMode.REPORT ): Element | null { var element = ctxElement.lookup(node.identifier.text); if (!element) { @@ -654,24 +665,26 @@ export class Resolver extends DiagnosticEmitter { } var argumentCount = typeArgumentNodes ? typeArgumentNodes.length : 0; if (argumentCount < minParameterCount || argumentCount > maxParameterCount) { - this.error( - DiagnosticCode.Expected_0_type_arguments_but_got_1, - argumentCount - ? Range.join( - (typeArgumentNodes)[0].range, - (typeArgumentNodes)[argumentCount - 1].range - ) - : assert(alternativeReportNode).range, - (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(10), - argumentCount.toString(10) - ); + if (reportMode == ReportMode.REPORT) { + this.error( + DiagnosticCode.Expected_0_type_arguments_but_got_1, + argumentCount + ? Range.join( + typeArgumentNodes![0].range, + typeArgumentNodes![argumentCount - 1].range + ) + : alternativeReportNode!.range, + (argumentCount < minParameterCount ? minParameterCount : maxParameterCount).toString(), + argumentCount.toString() + ); + } return null; } var typeArguments = new Array(maxParameterCount); for (let i = 0; i < maxParameterCount; ++i) { let type = i < argumentCount ? this.resolveType( // reports - (typeArgumentNodes)[i], + typeArgumentNodes![i], ctxElement, ctxTypes, reportMode @@ -746,7 +759,7 @@ export class Resolver extends DiagnosticEmitter { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Expected_0_arguments_but_got_1, - node.range, numParameters.toString(10), numArguments.toString(10) + node.range, numParameters.toString(), numArguments.toString() ); } return null; @@ -763,7 +776,7 @@ export class Resolver extends DiagnosticEmitter { for (let i = 0; i < numTypeParameters; ++i) { let name = typeParameterNodes[i].name.text; if (contextualTypeArguments.has(name)) { - let inferredType = contextualTypeArguments.get(name)!; + let inferredType = assert(contextualTypeArguments.get(name)); if (inferredType != Type.auto) { resolvedTypeArguments[i] = inferredType; continue; @@ -806,7 +819,7 @@ export class Resolver extends DiagnosticEmitter { ): void { if (node.kind == NodeKind.NAMEDTYPE) { let typeArgumentNodes = (node).typeArguments; - if (typeArgumentNodes !== null && typeArgumentNodes.length) { // foo(bar: Array) + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { // foo(bar: Array) let classReference = type.classReference; if (classReference) { let classPrototype = this.resolveTypeName((node).name, ctxFlow.actualFunction); @@ -824,7 +837,7 @@ export class Resolver extends DiagnosticEmitter { } else { // foo(bar: T) let name = (node).name.identifier.text; if (ctxTypes.has(name)) { - let currentType = ctxTypes.get(name)!; + let currentType = assert(ctxTypes.get(name)); if (currentType == Type.auto || (typeParameterNames.has(name) && currentType.isAssignableTo(type))) { ctxTypes.set(name, type); } @@ -832,7 +845,7 @@ export class Resolver extends DiagnosticEmitter { } } else if (node.kind == NodeKind.FUNCTIONTYPE) { // foo(bar: (baz: T) => i32)) let parameterNodes = (node).parameters; - if (parameterNodes !== null && parameterNodes.length) { + if (parameterNodes !== null && parameterNodes.length > 0) { let signatureReference = type.signatureReference; if (signatureReference) { let parameterTypes = signatureReference.parameterTypes; @@ -880,7 +893,7 @@ export class Resolver extends DiagnosticEmitter { } else if (type != Type.void) { let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(type)); - return wrapperClasses.get(type)!; + return assert(wrapperClasses.get(type)); } return null; } @@ -1206,7 +1219,7 @@ export class Resolver extends DiagnosticEmitter { var element = this.lookupIdentifierExpression(node, ctxFlow, ctxElement, reportMode); if (!element) return null; if (element.kind == ElementKind.FUNCTION_PROTOTYPE) { - let instance = this.resolveFunction(element, null, makeMap(), reportMode); + let instance = this.resolveFunction(element, null, makeMap(), reportMode); if (!instance) return null; element = instance; } @@ -1264,7 +1277,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1291,7 +1304,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1312,7 +1325,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(type)) { - classReference = wrapperClasses.get(type)!; + classReference = assert(wrapperClasses.get(type)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1345,7 +1358,7 @@ export class Resolver extends DiagnosticEmitter { if (!classReference) { let wrapperClasses = this.program.wrapperClasses; if (wrapperClasses.has(returnType)) { - classReference = wrapperClasses.get(returnType)!; + classReference = assert(wrapperClasses.get(returnType)); } else { if (reportMode == ReportMode.REPORT) { this.error( @@ -1379,10 +1392,10 @@ export class Resolver extends DiagnosticEmitter { case ElementKind.CLASS: { do { let members = target.members; - if (members && members.has(propertyName)) { + if (members !== null && members.has(propertyName)) { this.currentThisExpression = targetNode; this.currentElementExpression = null; - return members.get(propertyName)!; // instance FIELD, static GLOBAL, FUNCTION_PROTOTYPE... + return assert(members.get(propertyName)); // instance FIELD, static GLOBAL, FUNCTION_PROTOTYPE... } // traverse inherited static members on the base prototype if target is a class prototype if (target.kind == ElementKind.CLASS_PROTOTYPE) { @@ -1406,10 +1419,10 @@ export class Resolver extends DiagnosticEmitter { } default: { // enums or other namespace-like elements let members = target.members; - if (members && members.has(propertyName)) { + if (members !== null && members.has(propertyName)) { this.currentThisExpression = targetNode; this.currentElementExpression = null; - return members.get(propertyName)!; // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE... + return assert(members.get(propertyName)); // static ENUMVALUE, static GLOBAL, static FUNCTION_PROTOTYPE... } break; } @@ -1511,7 +1524,7 @@ export class Resolver extends DiagnosticEmitter { /** Determines the final type of an integer literal given the specified contextual type. */ determineIntegerLiteralType( /** Integer literal value. */ - intValue: I64, + intValue: i64, /** Contextual type. */ ctxType: Type ): Type { @@ -2153,10 +2166,13 @@ export class Resolver extends DiagnosticEmitter { } } var parent: Element | null = ctxFlow.actualFunction.parent; - if (parent && parent.kind == ElementKind.CLASS && (parent = (parent).base)) { - this.currentThisExpression = null; - this.currentElementExpression = null; - return parent; + if (parent !== null && parent.kind == ElementKind.CLASS) { + let base = (parent).base; + if (base) { + this.currentThisExpression = null; + this.currentElementExpression = null; + return base; + } } if (reportMode == ReportMode.REPORT) { this.error( @@ -2213,13 +2229,13 @@ export class Resolver extends DiagnosticEmitter { ); let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(intType)); - return wrapperClasses.get(intType)!; + return assert(wrapperClasses.get(intType)); } case LiteralKind.FLOAT: { let fltType = ctxType == Type.f32 ? Type.f32 : Type.f64; let wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(fltType)); - return wrapperClasses.get(fltType)!; + return assert(wrapperClasses.get(fltType)); } case LiteralKind.STRING: { return this.program.stringInstance; @@ -2417,7 +2433,7 @@ export class Resolver extends DiagnosticEmitter { ): Element | null { var wrapperClasses = this.program.wrapperClasses; assert(wrapperClasses.has(Type.bool)); - return wrapperClasses.get(Type.bool)!; + return assert(wrapperClasses.get(Type.bool)); } /** Resolves an instanceof expression to its static type. */ @@ -2636,8 +2652,8 @@ export class Resolver extends DiagnosticEmitter { var signatureNode = prototype.functionTypeNode; var typeParameterNodes = prototype.typeParameterNodes; var numFunctionTypeArguments: i32; - if (typeArguments && (numFunctionTypeArguments = typeArguments.length)) { - assert(typeParameterNodes && numFunctionTypeArguments == typeParameterNodes.length); + if (typeArguments !== null && (numFunctionTypeArguments = typeArguments.length) > 0) { + assert(typeParameterNodes !== null && numFunctionTypeArguments == typeParameterNodes.length); for (let i = 0; i < numFunctionTypeArguments; ++i) { ctxTypes.set( (typeParameterNodes)[i].name.text, @@ -2702,7 +2718,7 @@ export class Resolver extends DiagnosticEmitter { if (prototype.is(CommonFlags.SET)) { returnType = Type.void; // not annotated } else if (prototype.is(CommonFlags.CONSTRUCTOR)) { - returnType = assert(classInstance).type; // not annotated + returnType = classInstance!.type; // not annotated } else { let typeNode = signatureNode.returnType; if (isTypeOmitted(typeNode)) { @@ -2792,7 +2808,7 @@ export class Resolver extends DiagnosticEmitter { // Otherwise make sure that no type arguments have been specified } else { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, @@ -2853,7 +2869,7 @@ export class Resolver extends DiagnosticEmitter { } } else { let typeParameterNodes = prototype.typeParameterNodes; - assert(!(typeParameterNodes && typeParameterNodes.length)); + assert(!(typeParameterNodes !== null && typeParameterNodes.length > 0)); } instance.contextualTypeArguments = ctxTypes; @@ -2870,7 +2886,8 @@ export class Resolver extends DiagnosticEmitter { ); return null; } - } while (current = current.basePrototype); + current = current.basePrototype; + } while (current); let extendsNode = assert(prototype.extendsNode); // must be present if it has a base prototype let base = this.resolveClassInclTypeArguments( basePrototype, @@ -2913,7 +2930,10 @@ export class Resolver extends DiagnosticEmitter { assert(!pendingClasses.includes(base)); let baseMembers = base.members; if (baseMembers) { - for (let [baseMemberName, baseMember] of baseMembers) { + // TODO: for (let [baseMemberName, baseMember] of baseMembers) { + for (let _keys = Map_keys(baseMembers), i = 0, k = _keys.length; i < k; ++i) { + let baseMemberName = unchecked(_keys[i]); + let baseMember = assert(baseMembers.get(baseMemberName)); instanceMembers.set(baseMemberName, baseMember); } } @@ -2924,7 +2944,9 @@ export class Resolver extends DiagnosticEmitter { var prototype = instance.prototype; var instanceMemberPrototypes = prototype.instanceMembers; if (instanceMemberPrototypes) { - for (let member of instanceMemberPrototypes.values()) { + // TODO: for (let member of instanceMemberPrototypes.values()) { + for (let _values = Map_values(instanceMemberPrototypes), i = 0, k = _values.length; i < k; ++i) { + let member = unchecked(_values[i]); switch (member.kind) { case ElementKind.FIELD_PROTOTYPE: { @@ -2934,8 +2956,8 @@ export class Resolver extends DiagnosticEmitter { if (!fieldTypeNode) { if (base) { let baseMembers = base.members; - if (baseMembers && baseMembers.has((member).name)) { - let baseField = baseMembers.get((member).name)!; + if (baseMembers !== null && baseMembers.has((member).name)) { + let baseField = assert(baseMembers.get((member).name)); if (!baseField.is(CommonFlags.PRIVATE)) { assert(baseField.kind == ElementKind.FIELD); fieldType = (baseField).type; @@ -3018,7 +3040,7 @@ export class Resolver extends DiagnosticEmitter { // Link _own_ constructor if present { let ctorPrototype = instance.lookupInSelf(CommonNames.constructor); - if (ctorPrototype && ctorPrototype.parent === instance) { + if (ctorPrototype !== null && ctorPrototype.parent === instance) { assert(ctorPrototype.kind == ElementKind.FUNCTION_PROTOTYPE); let ctorInstance = this.resolveFunction( ctorPrototype, @@ -3031,8 +3053,12 @@ export class Resolver extends DiagnosticEmitter { } // Fully resolve operator overloads (don't have type parameters on their own) - for (let [kind, overloadPrototype] of prototype.overloadPrototypes) { - assert(kind != OperatorKind.INVALID); + var overloadPrototypes = prototype.overloadPrototypes; + // TODO: for (let [overloadKind, overloadPrototype] of overloadPrototypes) { + for (let _keys = Map_keys(overloadPrototypes), i = 0, k = _keys.length; i < k; ++i) { + let overloadKind = unchecked(_keys[i]); + let overloadPrototype = assert(overloadPrototypes.get(overloadKind)); + assert(overloadKind != OperatorKind.INVALID); let operatorInstance: Function | null; if (overloadPrototype.is(CommonFlags.INSTANCE)) { let boundPrototype = overloadPrototype.toBound(instance); @@ -3057,7 +3083,7 @@ export class Resolver extends DiagnosticEmitter { // the corresponding value, thus requiring a matching return type, while a // static overload works like any other overload. if (operatorInstance.is(CommonFlags.INSTANCE)) { - switch (kind) { + switch (overloadKind) { case OperatorKind.PREFIX_INC: case OperatorKind.PREFIX_DEC: case OperatorKind.POSTFIX_INC: @@ -3074,12 +3100,12 @@ export class Resolver extends DiagnosticEmitter { } } } - if (!overloads.has(kind)) { - overloads.set(kind, operatorInstance); - if (kind == OperatorKind.INDEXED_GET || kind == OperatorKind.INDEXED_SET) { + if (!overloads.has(overloadKind)) { + overloads.set(overloadKind, operatorInstance); + if (overloadKind == OperatorKind.INDEXED_GET || overloadKind == OperatorKind.INDEXED_SET) { let index = instance.indexSignature; if (!index) instance.indexSignature = index = new IndexSignature(instance); - if (kind == OperatorKind.INDEXED_GET) { + if (overloadKind == OperatorKind.INDEXED_GET) { index.setType(operatorInstance.signature.returnType); } } @@ -3143,7 +3169,7 @@ export class Resolver extends DiagnosticEmitter { // Otherwise make sure that no type arguments have been specified } else { - if (typeArgumentNodes !== null && typeArgumentNodes.length) { + if (typeArgumentNodes !== null && typeArgumentNodes.length > 0) { if (reportMode == ReportMode.REPORT) { this.error( DiagnosticCode.Type_0_is_not_generic, diff --git a/src/tokenizer.ts b/src/tokenizer.ts index b0103af3f7..fda08e1b52 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -176,164 +176,124 @@ export function tokenFromKeyword(text: string): Token { assert(text.length); switch (text.charCodeAt(0)) { case CharCode.a: { - switch (text) { - case "abstract": return Token.ABSTRACT; - case "as": return Token.AS; - case "async": return Token.ASYNC; - case "await": return Token.AWAIT; - } + if (text == "abstract") return Token.ABSTRACT; + if (text == "as") return Token.AS; + if (text == "async") return Token.ASYNC; + if (text == "await") return Token.AWAIT; break; } case CharCode.b: { - switch (text) { - case "break": return Token.BREAK; - } + if (text == "break") return Token.BREAK; break; } case CharCode.c: { - switch (text) { - case "case": return Token.CASE; - case "catch": return Token.CATCH; - case "class": return Token.CLASS; - case "continue": return Token.CONTINUE; - case "const": return Token.CONST; - case "constructor": return Token.CONSTRUCTOR; - } + if (text == "case") return Token.CASE; + if (text == "catch") return Token.CATCH; + if (text == "class") return Token.CLASS; + if (text == "continue") return Token.CONTINUE; + if (text == "const") return Token.CONST; + if (text == "constructor") return Token.CONSTRUCTOR; break; } case CharCode.d: { - switch (text) { - case "debugger": return Token.DEBUGGER; - case "declare": return Token.DECLARE; - case "default": return Token.DEFAULT; - case "delete": return Token.DELETE; - case "do": return Token.DO; - } + if (text == "debugger") return Token.DEBUGGER; + if (text == "declare") return Token.DECLARE; + if (text == "default") return Token.DEFAULT; + if (text == "delete") return Token.DELETE; + if (text == "do") return Token.DO; break; } case CharCode.e: { - switch (text) { - case "else": return Token.ELSE; - case "enum": return Token.ENUM; - case "export": return Token.EXPORT; - case "extends": return Token.EXTENDS; - } + if (text == "else") return Token.ELSE; + if (text == "enum") return Token.ENUM; + if (text == "export") return Token.EXPORT; + if (text == "extends") return Token.EXTENDS; break; } case CharCode.f: { - switch (text) { - case "false": return Token.FALSE; - case "finally": return Token.FINALLY; - case "for": return Token.FOR; - case "from": return Token.FROM; - case "function": return Token.FUNCTION; - } + if (text == "false") return Token.FALSE; + if (text == "finally") return Token.FINALLY; + if (text == "for") return Token.FOR; + if (text == "from") return Token.FROM; + if (text == "function") return Token.FUNCTION; break; } case CharCode.g: { - switch (text) { - case "get": return Token.GET; - } + if (text == "get") return Token.GET; break; } case CharCode.i: { - switch (text) { - case "if": return Token.IF; - case "implements": return Token.IMPLEMENTS; - case "import": return Token.IMPORT; - case "in": return Token.IN; - case "instanceof": return Token.INSTANCEOF; - case "interface": return Token.INTERFACE; - case "is": return Token.IS; - } + if (text == "if") return Token.IF; + if (text == "implements") return Token.IMPLEMENTS; + if (text == "import") return Token.IMPORT; + if (text == "in") return Token.IN; + if (text == "instanceof") return Token.INSTANCEOF; + if (text == "interface") return Token.INTERFACE; + if (text == "is") return Token.IS; break; } case CharCode.k: { - switch (text) { - case "keyof": return Token.KEYOF; - } + if (text == "keyof") return Token.KEYOF; break; } case CharCode.l: { - switch (text) { - case "let": return Token.LET; - } + if (text == "let") return Token.LET; break; } case CharCode.m: { - switch (text) { - case "module": return Token.MODULE; - } + if (text == "module") return Token.MODULE; break; } case CharCode.n: { - switch (text) { - case "namespace": return Token.NAMESPACE; - case "new": return Token.NEW; - case "null": return Token.NULL; - } + if (text == "namespace") return Token.NAMESPACE; + if (text == "new") return Token.NEW; + if (text == "null") return Token.NULL; break; } case CharCode.o: { - switch (text) { - case "of": return Token.OF; - } + if (text == "of") return Token.OF; break; } case CharCode.p: { - switch (text) { - case "package": return Token.PACKAGE; - case "private": return Token.PRIVATE; - case "protected": return Token.PROTECTED; - case "public": return Token.PUBLIC; - } + if (text == "package") return Token.PACKAGE; + if (text == "private") return Token.PRIVATE; + if (text == "protected") return Token.PROTECTED; + if (text == "public") return Token.PUBLIC; break; } case CharCode.r: { - switch (text) { - case "readonly": return Token.READONLY; - case "return": return Token.RETURN; - } + if (text == "readonly") return Token.READONLY; + if (text == "return") return Token.RETURN; break; } case CharCode.s: { - switch (text) { - case "set": return Token.SET; - case "static": return Token.STATIC; - case "super": return Token.SUPER; - case "switch": return Token.SWITCH; - } + if (text == "set") return Token.SET; + if (text == "static") return Token.STATIC; + if (text == "super") return Token.SUPER; + if (text == "switch") return Token.SWITCH; break; } case CharCode.t: { - switch (text) { - case "this": return Token.THIS; - case "throw": return Token.THROW; - case "true": return Token.TRUE; - case "try": return Token.TRY; - case "type": return Token.TYPE; - case "typeof": return Token.TYPEOF; - } + if (text == "this") return Token.THIS; + if (text == "throw") return Token.THROW; + if (text == "true") return Token.TRUE; + if (text == "try") return Token.TRY; + if (text == "type") return Token.TYPE; + if (text == "typeof") return Token.TYPEOF; break; } case CharCode.v: { - switch (text) { - case "var": return Token.VAR; - case "void": return Token.VOID; - } + if (text == "var") return Token.VAR; + if (text == "void") return Token.VOID; break; } case CharCode.w: { - switch (text) { - case "while": return Token.WHILE; - case "with": return Token.WITH; - } + if (text == "while") return Token.WHILE; + if (text == "with") return Token.WITH; break; } case CharCode.y: { - switch (text) { - case "yield": return Token.YIELD; - } + if (text == "yield") return Token.YIELD; break; } } @@ -491,8 +451,6 @@ export class Range { debugInfoRef: usize = 0; } -declare function parseFloat(str: string): f64; - /** Handler for intercepting comments while tokenizing. */ export type CommentHandler = (kind: CommentKind, text: string, range: Range) => void; @@ -519,7 +477,8 @@ export class Tokenizer extends DiagnosticEmitter { this.source = source; this.pos = 0; this.end = source.text.length; - this.diagnostics = diagnostics || new Array(); + if (!diagnostics) diagnostics = []; + this.diagnostics = diagnostics; var end = this.end; var text = source.text; @@ -1044,13 +1003,9 @@ export class Tokenizer extends DiagnosticEmitter { } mark(): State { - var state: State; - if (reusableState) { - state = reusableState; - reusableState = null; - } else { - state = new State(); - } + var state = reusableState; + if (state) reusableState = null; + else state = new State(); state.pos = this.pos; state.token = this.token; state.tokenPos = this.tokenPos; @@ -1272,7 +1227,7 @@ export class Tokenizer extends DiagnosticEmitter { return true; } - readInteger(): I64 { + readInteger(): i64 { var text = this.source.text; if (this.pos + 2 < this.end && text.charCodeAt(this.pos) == CharCode._0) { switch (text.charCodeAt(this.pos + 1) | 32) { @@ -1303,7 +1258,7 @@ export class Tokenizer extends DiagnosticEmitter { return this.readDecimalInteger(); } - readHexInteger(): I64 { + readHexInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); @@ -1360,7 +1315,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readDecimalInteger(): I64 { + readDecimalInteger(): i64 { var text = this.source.text; var start = this.pos; var end = this.end; @@ -1405,7 +1360,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readOctalInteger(): I64 { + readOctalInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); @@ -1450,7 +1405,7 @@ export class Tokenizer extends DiagnosticEmitter { return value; } - readBinaryInteger(): I64 { + readBinaryInteger(): i64 { var text = this.source.text; var start = this.pos; var value = i64_new(0); diff --git a/src/types.ts b/src/types.ts index a200cae828..4afc65cee1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -108,7 +108,7 @@ export class Type { /** Type flags. */ flags: TypeFlags; /** Size in bits. */ - size: u32; + size: i32; /** Size in bytes. */ byteSize: i32; /** Underlying class reference, if a class type. */ @@ -133,6 +133,7 @@ export class Type { /** Returns the closest int type representing this type. */ get intType(): Type { + if (this == Type.auto) return this; // keep auto as a hint switch (this.kind) { case TypeKind.I8: return Type.i8; case TypeKind.I16: return Type.i16; @@ -179,12 +180,12 @@ export class Type { } /** Computes the sign-extending shift in the target type. */ - computeSmallIntegerShift(targetType: Type): u32 { + computeSmallIntegerShift(targetType: Type): i32 { return targetType.size - this.size; } /** Computes the truncating mask in the target type. */ - computeSmallIntegerMask(targetType: Type): u32 { + computeSmallIntegerMask(targetType: Type): i32 { var size = this.is(TypeFlags.UNSIGNED) ? this.size : this.size - 1; return ~0 >>> (targetType.size - size); } @@ -213,14 +214,15 @@ export class Type { /** Composes the respective nullable type of this type. */ asNullable(): Type { assert(this.is(TypeFlags.REFERENCE)); - if (!this.cachedNullableType) { + var cachedNullableType = this.cachedNullableType; + if (!cachedNullableType) { assert(!this.is(TypeFlags.NULLABLE)); - this.cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size); - this.cachedNullableType.nonNullableType = this; - this.cachedNullableType.classReference = this.classReference; // either a class reference - this.cachedNullableType.signatureReference = this.signatureReference; // or a function reference + this.cachedNullableType = cachedNullableType = new Type(this.kind, this.flags | TypeFlags.NULLABLE, this.size); + cachedNullableType.nonNullableType = this; + cachedNullableType.classReference = this.classReference; // either a class reference + cachedNullableType.signatureReference = this.signatureReference; // or a function reference } - return this.cachedNullableType; + return cachedNullableType; } /** Tests if a value of this type is assignable to the target type incl. implicit conversion. */ @@ -608,7 +610,7 @@ export class Signature { /** Gets the known or, alternatively, generic parameter name at the specified index. */ getParameterName(index: i32): string { var parameterNames = this.parameterNames; - return parameterNames && parameterNames.length > index + return parameterNames !== null && parameterNames.length > index ? parameterNames[index] : getDefaultParameterName(index); } @@ -625,8 +627,8 @@ export class Signature { // check `this` type var thisThisType = this.thisType; var targetThisType = value.thisType; - if (thisThisType) { - if (!(targetThisType && thisThisType.isAssignableTo(targetThisType))) return false; + if (thisThisType !== null) { + if (targetThisType === null || !thisThisType.isAssignableTo(targetThisType)) return false; } else if (targetThisType) { return false; } @@ -689,13 +691,12 @@ export class Signature { // helpers // Cached default parameter names used where names are unknown. -var cachedDefaultParameterNames: string[] | null = null; +var cachedDefaultParameterNames: string[] = []; /** Gets the cached default parameter name for the specified index. */ export function getDefaultParameterName(index: i32): string { - if (!cachedDefaultParameterNames) cachedDefaultParameterNames = []; for (let i = cachedDefaultParameterNames.length; i <= index; ++i) { - cachedDefaultParameterNames.push("arg$" + i.toString(10)); + cachedDefaultParameterNames.push("arg$" + i.toString()); } return cachedDefaultParameterNames[index - 1]; } diff --git a/src/util/binary.ts b/src/util/binary.ts index 83e0aff0d3..887759d7fd 100644 --- a/src/util/binary.ts +++ b/src/util/binary.ts @@ -39,14 +39,14 @@ export function writeI32(value: i32, buffer: Uint8Array, offset: i32): void { } /** Reads a 64-bit integer from the specified buffer. */ -export function readI64(buffer: Uint8Array, offset: i32): I64 { +export function readI64(buffer: Uint8Array, offset: i32): i64 { var lo = readI32(buffer, offset); var hi = readI32(buffer, offset + 4); return i64_new(lo, hi); } /** Writes a 64-bit integer to the specified buffer. */ -export function writeI64(value: I64, buffer: Uint8Array, offset: i32): void { +export function writeI64(value: i64, buffer: Uint8Array, offset: i32): void { writeI32(i64_low(value), buffer, offset); writeI32(i64_high(value), buffer, offset + 4); } diff --git a/src/util/bitset.ts b/src/util/bitset.ts index 764d964d13..df36ca293f 100644 --- a/src/util/bitset.ts +++ b/src/util/bitset.ts @@ -1,7 +1,7 @@ /** @module util *//***/ /** Tests if the bit at the specified index is set within a 64-bit map. */ -export function bitsetIs(map: I64, index: i32): bool { +export function bitsetIs(map: i64, index: i32): bool { assert(index >= 0 && index < 64); return i64_ne( i64_and( @@ -16,7 +16,7 @@ export function bitsetIs(map: I64, index: i32): bool { } /** Sets or unsets the bit at the specified index within a 64-bit map and returns the new map. */ -export function bitsetSet(map: I64, index: i32, isSet: bool): I64 { +export function bitsetSet(map: i64, index: i32, isSet: bool): i64 { assert(index >= 0 && index < 64); return isSet ? i64_or( diff --git a/src/util/collections.ts b/src/util/collections.ts index db47579cf5..f1ea2461fb 100644 --- a/src/util/collections.ts +++ b/src/util/collections.ts @@ -11,7 +11,11 @@ export function makeArray(original: Array | null = null): Array { export function makeSet(original: Set | null = null): Set { if (original) { let cloned = new Set(); - for (let v of original) cloned.add(v); + // TODO: for (let v of original) { + for (let _values = Set_values(original), i = 0, k = _values.length; i < k; ++i) { + let v = unchecked(_values[i]); + cloned.add(v); + } return cloned; } return new Set(); @@ -20,10 +24,20 @@ export function makeSet(original: Set | null = null): Set { export function makeMap(original: Map | null = null, overrides: Map | null = null): Map { var cloned = new Map(); if (original) { - for (let [k, v] of original) cloned.set(k, v); - if (overrides) for (let [k, v] of overrides) cloned.set(k, v); - } else if (overrides) { - for (let [k, v] of overrides) cloned.set(k, v); + // TODO: for (let [k, v] of original) { + for (let _keys = Map_keys(original), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = assert(original.get(k)); + cloned.set(k, v); + } + } + if (overrides) { + // TODO: for (let [k, v] of overrides) { + for (let _keys = Map_keys(overrides), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = assert(overrides.get(k)); + cloned.set(k, v); + } } return cloned; } diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index 02af3d2ee7..fc30fdc545 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -171,7 +171,7 @@ declare function isManaged(value?: any): bool; /** Tests if the specified type is void. Compiles to a constant. */ declare function isVoid(): bool; /** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */ -declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? +declare function assert(isTrueish: T, message?: string): T & (object | string | number); // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; /** Parses a string to a 64-bit float. */ diff --git a/std/assembly/map.ts b/std/assembly/map.ts index 51fdf243af..0e82f9f96c 100644 --- a/std/assembly/map.ts +++ b/std/assembly/map.ts @@ -137,7 +137,7 @@ export class Map { } // append new entry let entries = this.entries; - entry = changetype>(changetype(entries) + this.entriesOffset++ * ENTRY_SIZE()); + entry = changetype>(changetype(entries) + (this.entriesOffset++) * ENTRY_SIZE()); // link with the map entry.key = isManaged() ? changetype(__retain(changetype(key))) diff --git a/std/assembly/rt/common.ts b/std/assembly/rt/common.ts index 0c046c770f..58ffd86eed 100644 --- a/std/assembly/rt/common.ts +++ b/std/assembly/rt/common.ts @@ -37,7 +37,7 @@ } // @ts-ignore: decorator -@inline export const BLOCK_OVERHEAD = (offsetof() + AL_MASK) & ~AL_MASK; +@inline export const BLOCK_OVERHEAD: usize = (offsetof() + AL_MASK) & ~AL_MASK; // @ts-ignore: decorator @inline export const BLOCK_MAXSIZE: usize = (1 << 30) - BLOCK_OVERHEAD; diff --git a/std/assembly/rt/stub.ts b/std/assembly/rt/stub.ts index 04867d60f3..53ad191389 100644 --- a/std/assembly/rt/stub.ts +++ b/std/assembly/rt/stub.ts @@ -13,7 +13,7 @@ function maybeGrowMemory(newOffset: usize): void { var pagesBefore = memory.size(); var maxOffset = pagesBefore << 16; if (newOffset > maxOffset) { - let pagesNeeded = ((newOffset - maxOffset + 0xffff) & ~0xffff) >>> 16; + let pagesNeeded = (((newOffset - maxOffset + 0xffff) & ~0xffff) >>> 16); let pagesWanted = max(pagesBefore, pagesNeeded); // double memory if (memory.grow(pagesWanted) < 0) { if (memory.grow(pagesNeeded) < 0) unreachable(); // out of memory @@ -33,7 +33,7 @@ export function __alloc(size: usize, id: u32): usize { block.mmInfo = actualSize; if (DEBUG) block.gcInfo = 1; block.rtId = id; - block.rtSize = size; + block.rtSize = size; return ptr; } @@ -60,7 +60,7 @@ export function __realloc(ptr: usize, size: usize): usize { offset = ptr + alignedSize; block.mmInfo = alignedSize; } - block.rtSize = size; + block.rtSize = size; return ptr; } diff --git a/std/assembly/rt/tlsf.ts b/std/assembly/rt/tlsf.ts index c797f21794..486e860de7 100644 --- a/std/assembly/rt/tlsf.ts +++ b/std/assembly/rt/tlsf.ts @@ -19,12 +19,12 @@ import { REFCOUNT_MASK } from "./pure"; // @ts-ignore: decorator @inline const SL_BITS: u32 = 4; // @ts-ignore: decorator -@inline const SL_SIZE: usize = 1 << SL_BITS; +@inline const SL_SIZE: u32 = 1 << SL_BITS; // @ts-ignore: decorator -@inline const SB_BITS: usize = (SL_BITS + AL_BITS); +@inline const SB_BITS: u32 = SL_BITS + AL_BITS; // @ts-ignore: decorator -@inline const SB_SIZE: usize = 1 << SB_BITS; +@inline const SB_SIZE: u32 = 1 << SB_BITS; // @ts-ignore: decorator @inline const FL_BITS: u32 = 31 - SB_BITS; @@ -130,15 +130,15 @@ import { REFCOUNT_MASK } from "./pure"; // Root constants. Where stuff is stored inside of the root structure. // @ts-ignore: decorator -@inline const SL_START = sizeof(); +@inline const SL_START: usize = sizeof(); // @ts-ignore: decorator -@inline const SL_END = SL_START + (FL_BITS << alignof()); +@inline const SL_END: usize = SL_START + (FL_BITS << alignof()); // @ts-ignore: decorator -@inline const HL_START = (SL_END + AL_MASK) & ~AL_MASK; +@inline const HL_START: usize = (SL_END + AL_MASK) & ~AL_MASK; // @ts-ignore: decorator -@inline const HL_END = HL_START + FL_BITS * SL_SIZE * sizeof(); +@inline const HL_END: usize = HL_START + FL_BITS * SL_SIZE * sizeof(); // @ts-ignore: decorator -@inline const ROOT_SIZE = HL_END + sizeof(); +@inline const ROOT_SIZE: usize = HL_END + sizeof(); // @ts-ignore: decorator @lazy export var ROOT: Root; @@ -510,7 +510,7 @@ export function allocateBlock(root: Root, size: usize, id: u32): Block { if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit block.gcInfo = 0; // RC=0 block.rtId = id; - block.rtSize = size; + block.rtSize = size; removeBlock(root, block); prepareBlock(root, block, payloadSize); if (isDefined(ASC_RTRACE)) onalloc(block); @@ -525,7 +525,7 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block { // possibly split and update runtime size if it still fits if (payloadSize <= (blockInfo & ~TAGS_MASK)) { prepareBlock(root, block, payloadSize); - block.rtSize = size; + block.rtSize = size; return block; } @@ -539,7 +539,7 @@ export function reallocateBlock(root: Root, block: Block, size: usize): Block { // TODO: this can yield an intermediate block larger than BLOCK_MAXSIZE, which // is immediately split though. does this trigger any assertions / issues? block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize; - block.rtSize = size; + block.rtSize = size; prepareBlock(root, block, payloadSize); return block; } diff --git a/std/assembly/set.ts b/std/assembly/set.ts index 76a7b66ed3..ca2a1ca299 100644 --- a/std/assembly/set.ts +++ b/std/assembly/set.ts @@ -114,7 +114,7 @@ export class Set { ); } // append new entry - entry = changetype>(changetype(this.entries) + this.entriesOffset++ * ENTRY_SIZE()); + entry = changetype>(changetype(this.entries) + (this.entriesOffset++) * ENTRY_SIZE()); entry.key = isManaged() ? changetype(__retain(changetype(key))) : key; diff --git a/std/assembly/string.ts b/std/assembly/string.ts index 4d0b89eef1..078476911f 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -4,10 +4,12 @@ import { BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./rt/common"; import { compareImpl, strtol, strtod, isSpace, isAscii, isFinalSigma, toLower8, toUpper8 } from "./util/string"; import { SPECIALS_UPPER, casemap, bsearch } from "./util/casemap"; import { E_INVALIDLENGTH } from "./util/error"; +import { idof } from "./builtins"; +import { Array } from "./array"; @sealed export abstract class String { - @lazy static readonly MAX_LENGTH: i32 = BLOCK_MAXSIZE >>> alignof(); + @lazy static readonly MAX_LENGTH: i32 = (BLOCK_MAXSIZE >>> alignof()); static fromCharCode(unit: i32, surr: i32 = -1): String { var hasSur = surr > 0; @@ -17,6 +19,16 @@ import { E_INVALIDLENGTH } from "./util/error"; return changetype(out); // retains } + static fromCharCodes(units: Array): String { + var length = units.length; + var out = __alloc(length << 1, idof()); + var ptr = units.dataStart; + for (let i = 0; i < length; ++i) { + store(out + (i << 1), load(ptr + (i << 2))); + } + return changetype(out); + } + static fromCodePoint(code: i32): String { assert(code <= 0x10FFFF); var hasSur = code > 0xFFFF; @@ -445,13 +457,13 @@ import { E_INVALIDLENGTH } from "./util/error"; if (!limit) return changetype>(__allocArray(0, alignof(), idof>())); // retains if (separator === null) return [this]; var length: isize = this.length; - var sepLen: isize = separator.length; + var sepLen = separator.length; if (limit < 0) limit = i32.MAX_VALUE; if (!sepLen) { if (!length) return changetype>(__allocArray(0, alignof(), idof>())); // retains // split by chars length = min(length, limit); - let result = changetype>(__allocArray(length, alignof(), idof>())); // retains + let result = changetype>(__allocArray(length, alignof(), idof>())); // retains // @ts-ignore: cast let resultStart = result.dataStart as usize; for (let i: isize = 0; i < length; ++i) { @@ -585,7 +597,7 @@ import { E_INVALIDLENGTH } from "./util/error"; // monkey patch store(codes + (j << 1), c - 26); } else { - let index = -1 as usize; + let index: usize = -1; // Fast range check. See first and last rows in specialsUpper table if (c - 0x00DF <= 0xFB17 - 0x00DF) { index = bsearch(c, specialsPtr, specialsLen); diff --git a/std/assembly/symbol.ts b/std/assembly/symbol.ts index 97baef4d58..b503b50705 100644 --- a/std/assembly/symbol.ts +++ b/std/assembly/symbol.ts @@ -85,7 +85,7 @@ var nextId: usize = 12; // Symbol.unscopables + 1 toString(): string { var id = changetype(this); var str = ""; - switch (id) { + switch (id) { case 1: { str = "hasInstance"; break; } case 2: { str = "isConcatSpreadable"; break; } case 3: { str = "isRegExp"; break; } diff --git a/std/assembly/typedarray.ts b/std/assembly/typedarray.ts index e96e4c7655..947fbf917c 100644 --- a/std/assembly/typedarray.ts +++ b/std/assembly/typedarray.ts @@ -9,7 +9,7 @@ export class Int8Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -137,7 +137,7 @@ export class Uint8Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -265,7 +265,7 @@ export class Uint8ClampedArray extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -393,7 +393,7 @@ export class Int16Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -521,7 +521,7 @@ export class Uint16Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -649,7 +649,7 @@ export class Int32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -777,7 +777,7 @@ export class Uint32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -905,7 +905,7 @@ export class Int64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1033,7 +1033,7 @@ export class Uint64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1161,7 +1161,7 @@ export class Float32Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1289,7 +1289,7 @@ export class Float64Array extends ArrayBufferView { // @ts-ignore: decorator @lazy - static readonly BYTES_PER_ELEMENT: usize = sizeof(); + static readonly BYTES_PER_ELEMENT: i32 = sizeof(); constructor(length: i32) { super(length, alignof()); @@ -1736,7 +1736,7 @@ function REVERSE(array: TArray): TArray { function WRAP(buffer: ArrayBuffer, byteOffset: i32 = 0, length: i32 = -1): TArray { var byteLength: i32; var bufferByteLength = buffer.byteLength; - const mask = sizeof() - 1; + const mask: u32 = sizeof() - 1; if (i32(byteOffset > bufferByteLength) | (byteOffset & mask)) { throw new RangeError(E_INDEXOUTOFRANGE); } diff --git a/std/assembly/util/memory.ts b/std/assembly/util/memory.ts index 26d42b883b..e960254e8f 100644 --- a/std/assembly/util/memory.ts +++ b/std/assembly/util/memory.ts @@ -38,7 +38,7 @@ export function memcpy(dest: usize, src: usize, n: usize): void { // see: musl/s // if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each // doing shifts if faster when copying enough bytes (here: 32 or more) if (n >= 32) { - switch (dest & 3) { + switch (dest & 3) { // known to be != 0 case 1: { w = load(src); diff --git a/std/assembly/util/number.ts b/std/assembly/util/number.ts index ecbe1efcbc..6e57aaa5ca 100644 --- a/std/assembly/util/number.ts +++ b/std/assembly/util/number.ts @@ -499,7 +499,7 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i } } - while (1) { + while (true) { p2 *= 10; delta *= 10; @@ -515,8 +515,6 @@ function genDigits(buffer: usize, w_frc: u64, w_exp: i32, mp_frc: u64, mp_exp: i return len; } } - - return len; } // @ts-ignore: decorator diff --git a/std/assembly/util/sort.ts b/std/assembly/util/sort.ts index 0bd18f0a52..3ab895b259 100644 --- a/std/assembly/util/sort.ts +++ b/std/assembly/util/sort.ts @@ -86,7 +86,7 @@ function weakHeapSort( ): void { const shift32 = alignof(); - var bitsetSize = (length + 31) >> 5 << shift32; + var bitsetSize = (length + 31) >> 5 << shift32; var bitset = __alloc(bitsetSize, 0); // indexed in 32-bit chunks below memory.fill(bitset, 0, bitsetSize); @@ -94,15 +94,15 @@ function weakHeapSort( for (let i = length - 1; i > 0; i--) { let j = i; - while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; + while ((j & 1) == (load(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1; let p = j >> 1; let a: T = load(dataStart + (p << alignof())); // a = arr[p] let b: T = load(dataStart + (i << alignof())); // b = arr[i] if (comparator(a, b) < 0) { store( - bitset + (i >> 5 << shift32), - load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) + bitset + (i >> 5 << shift32), + load(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31)) ); store(dataStart + (i << alignof()), a); // arr[i] = a store(dataStart + (p << alignof()), b); // arr[p] = b @@ -115,7 +115,7 @@ function weakHeapSort( store(dataStart + (i << alignof()), a); // arr[i] = a let x = 1, y: i32; - while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; + while ((y = (x << 1) + ((load(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y; while (x > 0) { a = load(dataStart); // a = arr[0] @@ -123,8 +123,8 @@ function weakHeapSort( if (comparator(a, b) < 0) { store( - bitset + (x >> 5 << shift32), - load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) + bitset + (x >> 5 << shift32), + load(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31)) ); store(dataStart + (x << alignof()), a); // arr[x] = a store(dataStart, b); // arr[0] = b diff --git a/std/portable/index.d.ts b/std/portable/index.d.ts index d6f41fdef0..df78e5ac25 100644 --- a/std/portable/index.d.ts +++ b/std/portable/index.d.ts @@ -108,7 +108,7 @@ declare function isDefined(expression: any): bool; /** Tests if the specified expression evaluates to a constant value. */ declare function isConstant(expression: any): bool; /** Traps if the specified value is not true-ish, otherwise returns the value. */ -declare function assert(isTrueish: T | null, message?: string): T; +declare function assert(isTrueish: T, message?: string): T & (object | string | number); // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; /** Parses a floating point string to a 64-bit float. */ diff --git a/tests/bootstrap/index.ts b/tests/bootstrap/index.ts new file mode 100644 index 0000000000..673bc0a358 --- /dev/null +++ b/tests/bootstrap/index.ts @@ -0,0 +1,24 @@ +import * as fs from "fs"; +import * as binaryen from "binaryen"; +import * as loader from "../../lib/loader"; +import AssemblyScript from "../../out/assemblyscript"; + +async function test(build: string): Promise { + await binaryen.ready; + const assemblyscript = await loader.instantiate(fs.promises.readFile(__dirname + "/../../out/assemblyscript." + build + ".wasm"), { binaryen }); + console.log(assemblyscript); + const optionsPtr = assemblyscript.newOptions(); + const programPtr = assemblyscript.newProgram(optionsPtr); + const textPtr = assemblyscript.__allocString("export function add(a: i32, b: i32): i32 { return a + b; }\n"); + const pathPtr = assemblyscript.__allocString("index.ts"); + assemblyscript.parse(programPtr, textPtr, pathPtr, true); + var nextFilePtr = assemblyscript.nextFile(programPtr); + while (nextFilePtr) { + console.log("nextFile: " + assemblyscript.__getString(nextFilePtr)); + nextFilePtr = assemblyscript.nextFile(programPtr); + } + // assemblyscript.compile(programPtr); + // ^ abort: missing ArrayBuffer at src/program.ts:1015:18 + console.log("So far, so good."); +} +test("untouched"); diff --git a/tests/compiler/do.optimized.wat b/tests/compiler/do.optimized.wat index 679f0a64c1..0a93f4ce92 100644 --- a/tests/compiler/do.optimized.wat +++ b/tests/compiler/do.optimized.wat @@ -214,7 +214,7 @@ if i32.const 0 i32.const 32 - i32.const 107 + i32.const 116 i32.const 2 call $~lib/builtins/abort unreachable @@ -251,7 +251,7 @@ if i32.const 0 i32.const 32 - i32.const 125 + i32.const 134 i32.const 2 call $~lib/builtins/abort unreachable @@ -262,7 +262,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -1265,7 +1265,7 @@ if i32.const 0 i32.const 32 - i32.const 141 + i32.const 150 i32.const 2 call $~lib/builtins/abort unreachable @@ -1274,7 +1274,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1323,7 +1323,7 @@ if i32.const 0 i32.const 32 - i32.const 161 + i32.const 170 i32.const 2 call $~lib/builtins/abort unreachable @@ -1332,7 +1332,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -1343,6 +1343,7 @@ call $~lib/rt/pure/__release ) (func $start:do (; 24 ;) + (local $0 i32) i32.const 0 global.set $do/ran call $do/testSimple @@ -1395,6 +1396,26 @@ call $~lib/builtins/abort unreachable end + loop $do-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.ne + br_if $do-continue|0 + end + local.get $0 + i32.const 10 + i32.ne + if + i32.const 0 + i32.const 32 + i32.const 70 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $do/ran i32.const 1 @@ -1415,7 +1436,7 @@ if i32.const 0 i32.const 32 - i32.const 112 + i32.const 121 i32.const 0 call $~lib/builtins/abort unreachable @@ -1428,7 +1449,7 @@ if i32.const 0 i32.const 32 - i32.const 131 + i32.const 140 i32.const 0 call $~lib/builtins/abort unreachable @@ -1441,7 +1462,7 @@ if i32.const 0 i32.const 32 - i32.const 147 + i32.const 156 i32.const 0 call $~lib/builtins/abort unreachable @@ -1454,7 +1475,7 @@ if i32.const 0 i32.const 32 - i32.const 167 + i32.const 176 i32.const 0 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/do.ts b/tests/compiler/do.ts index 82cdbc8f4e..c7de4222eb 100644 --- a/tests/compiler/do.ts +++ b/tests/compiler/do.ts @@ -60,6 +60,15 @@ ran = false; testAlwaysTrue(); assert(ran); +function testAlwaysTrueNeverBreaks(): i32 { + var i = 0; + do { + if (++i == 10) return i; + } while (true); + // no return required +} +assert(testAlwaysTrueNeverBreaks() == 10); + function testAlwaysFalse(): void { var i = 0; do { diff --git a/tests/compiler/do.untouched.wat b/tests/compiler/do.untouched.wat index 8f7f07a553..2a12469761 100644 --- a/tests/compiler/do.untouched.wat +++ b/tests/compiler/do.untouched.wat @@ -2,8 +2,8 @@ (type $none_=>_none (func)) (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_none (func (param i32 i32))) - (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) @@ -247,7 +247,26 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysFalse (; 9 ;) + (func $do/testAlwaysTrueNeverBreaks (; 9 ;) (result i32) + (local $0 i32) + i32.const 0 + local.set $0 + loop $do-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.eq + if + local.get $0 + return + end + br $do-continue|0 + end + unreachable + ) + (func $do/testAlwaysFalse (; 10 ;) (local $0 i32) i32.const 0 local.set $0 @@ -264,7 +283,7 @@ if i32.const 0 i32.const 32 - i32.const 68 + i32.const 77 i32.const 2 call $~lib/builtins/abort unreachable @@ -272,7 +291,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysBreaks (; 10 ;) + (func $do/testAlwaysBreaks (; 11 ;) (local $0 i32) i32.const 0 local.set $0 @@ -293,7 +312,7 @@ if i32.const 0 i32.const 32 - i32.const 81 + i32.const 90 i32.const 2 call $~lib/builtins/abort unreachable @@ -301,7 +320,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testAlwaysReturns (; 11 ;) + (func $do/testAlwaysReturns (; 12 ;) (local $0 i32) i32.const 0 local.set $0 @@ -316,7 +335,7 @@ end unreachable ) - (func $do/testContinue (; 12 ;) + (func $do/testContinue (; 13 ;) (local $0 i32) i32.const 0 local.set $0 @@ -342,7 +361,7 @@ if i32.const 0 i32.const 32 - i32.const 107 + i32.const 116 i32.const 2 call $~lib/builtins/abort unreachable @@ -350,7 +369,7 @@ i32.const 1 global.set $do/ran ) - (func $do/testNestedContinue (; 13 ;) + (func $do/testNestedContinue (; 14 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -396,7 +415,7 @@ if i32.const 0 i32.const 32 - i32.const 125 + i32.const 134 i32.const 2 call $~lib/builtins/abort unreachable @@ -408,7 +427,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -416,7 +435,7 @@ i32.const 1 global.set $do/ran ) - (func $~lib/rt/tlsf/removeBlock (; 14 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/removeBlock (; 15 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -626,7 +645,7 @@ end end ) - (func $~lib/rt/tlsf/insertBlock (; 15 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/insertBlock (; 16 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -976,7 +995,7 @@ local.get $7 i32.store offset=4 ) - (func $~lib/rt/tlsf/addMemory (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/addMemory (; 17 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1124,7 +1143,7 @@ call $~lib/rt/tlsf/insertBlock i32.const 1 ) - (func $~lib/rt/tlsf/maybeInitialize (; 17 ;) (result i32) + (func $~lib/rt/tlsf/maybeInitialize (; 18 ;) (result i32) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1274,7 +1293,7 @@ end local.get $0 ) - (func $~lib/rt/tlsf/prepareSize (; 18 ;) (param $0 i32) (result i32) + (func $~lib/rt/tlsf/prepareSize (; 19 ;) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) local.get $0 @@ -1303,7 +1322,7 @@ i32.gt_u select ) - (func $~lib/rt/tlsf/searchBlock (; 19 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/searchBlock (; 20 ;) (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1486,7 +1505,7 @@ end local.get $7 ) - (func $~lib/rt/tlsf/growMemory (; 20 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/growMemory (; 21 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1570,7 +1589,7 @@ call $~lib/rt/tlsf/addMemory drop ) - (func $~lib/rt/tlsf/prepareBlock (; 21 ;) (param $0 i32) (param $1 i32) (param $2 i32) + (func $~lib/rt/tlsf/prepareBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1665,7 +1684,7 @@ i32.store end ) - (func $~lib/rt/tlsf/allocateBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/allocateBlock (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) global.get $~lib/rt/tlsf/collectLock @@ -1776,7 +1795,7 @@ call $~lib/rt/rtrace/onalloc local.get $4 ) - (func $~lib/rt/tlsf/__alloc (; 23 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/__alloc (; 24 ;) (param $0 i32) (param $1 i32) (result i32) call $~lib/rt/tlsf/maybeInitialize local.get $0 local.get $1 @@ -1784,7 +1803,7 @@ i32.const 16 i32.add ) - (func $~lib/rt/pure/increment (; 24 ;) (param $0 i32) + (func $~lib/rt/pure/increment (; 25 ;) (param $0 i32) (local $1 i32) local.get $0 i32.load offset=4 @@ -1829,7 +1848,7 @@ unreachable end ) - (func $~lib/rt/pure/__retain (; 25 ;) (param $0 i32) (result i32) + (func $~lib/rt/pure/__retain (; 26 ;) (param $0 i32) (result i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1841,7 +1860,7 @@ end local.get $0 ) - (func $do/Ref#constructor (; 26 ;) (param $0 i32) (result i32) + (func $do/Ref#constructor (; 27 ;) (param $0 i32) (result i32) local.get $0 i32.eqz if @@ -1853,7 +1872,7 @@ end local.get $0 ) - (func $~lib/rt/pure/__release (; 27 ;) (param $0 i32) + (func $~lib/rt/pure/__release (; 28 ;) (param $0 i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1864,7 +1883,7 @@ call $~lib/rt/pure/decrement end ) - (func $do/testRef (; 28 ;) + (func $do/testRef (; 29 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1917,7 +1936,7 @@ if i32.const 0 i32.const 32 - i32.const 141 + i32.const 150 i32.const 2 call $~lib/builtins/abort unreachable @@ -1928,7 +1947,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1938,11 +1957,11 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $do/getRef (; 29 ;) (result i32) + (func $do/getRef (; 30 ;) (result i32) i32.const 0 call $do/Ref#constructor ) - (func $do/testRefAutorelease (; 30 ;) + (func $do/testRefAutorelease (; 31 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1993,7 +2012,7 @@ if i32.const 0 i32.const 32 - i32.const 161 + i32.const 170 i32.const 2 call $~lib/builtins/abort unreachable @@ -2004,7 +2023,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -2014,7 +2033,7 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $start:do (; 31 ;) + (func $start:do (; 32 ;) i32.const 0 global.set $do/ran call $do/testSimple @@ -2067,6 +2086,18 @@ call $~lib/builtins/abort unreachable end + call $do/testAlwaysTrueNeverBreaks + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 70 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $do/ran call $do/testAlwaysFalse @@ -2075,7 +2106,7 @@ if i32.const 0 i32.const 32 - i32.const 73 + i32.const 82 i32.const 0 call $~lib/builtins/abort unreachable @@ -2088,7 +2119,7 @@ if i32.const 0 i32.const 32 - i32.const 86 + i32.const 95 i32.const 0 call $~lib/builtins/abort unreachable @@ -2101,7 +2132,7 @@ if i32.const 0 i32.const 32 - i32.const 99 + i32.const 108 i32.const 0 call $~lib/builtins/abort unreachable @@ -2114,7 +2145,7 @@ if i32.const 0 i32.const 32 - i32.const 112 + i32.const 121 i32.const 0 call $~lib/builtins/abort unreachable @@ -2127,7 +2158,7 @@ if i32.const 0 i32.const 32 - i32.const 131 + i32.const 140 i32.const 0 call $~lib/builtins/abort unreachable @@ -2140,7 +2171,7 @@ if i32.const 0 i32.const 32 - i32.const 147 + i32.const 156 i32.const 0 call $~lib/builtins/abort unreachable @@ -2153,13 +2184,13 @@ if i32.const 0 i32.const 32 - i32.const 167 + i32.const 176 i32.const 0 call $~lib/builtins/abort unreachable end ) - (func $~start (; 32 ;) + (func $~start (; 33 ;) global.get $~started if return @@ -2169,10 +2200,10 @@ end call $start:do ) - (func $~lib/rt/pure/__collect (; 33 ;) + (func $~lib/rt/pure/__collect (; 34 ;) return ) - (func $~lib/rt/tlsf/freeBlock (; 34 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/freeBlock (; 35 ;) (param $0 i32) (param $1 i32) (local $2 i32) local.get $1 i32.load @@ -2188,7 +2219,7 @@ local.get $1 call $~lib/rt/rtrace/onfree ) - (func $~lib/rt/pure/decrement (; 35 ;) (param $0 i32) + (func $~lib/rt/pure/decrement (; 36 ;) (param $0 i32) (local $1 i32) (local $2 i32) local.get $0 @@ -2265,7 +2296,7 @@ i32.store offset=4 end ) - (func $~lib/rt/pure/__visit (; 36 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/pure/__visit (; 37 ;) (param $0 i32) (param $1 i32) local.get $0 global.get $~lib/heap/__heap_base i32.lt_u @@ -2289,7 +2320,7 @@ i32.sub call $~lib/rt/pure/decrement ) - (func $~lib/rt/__visit_members (; 37 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/__visit_members (; 38 ;) (param $0 i32) (param $1 i32) (local $2 i32) block $switch$1$default block $switch$1$case$4 diff --git a/tests/compiler/exportstar.json b/tests/compiler/exportstar.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/exportstar.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/exportstar.optimized.wat b/tests/compiler/exportstar.optimized.wat new file mode 100644 index 0000000000..78eb99e6e5 --- /dev/null +++ b/tests/compiler/exportstar.optimized.wat @@ -0,0 +1,35 @@ +(module + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (type $none_=>_none (func)) + (memory $0 0) + (global $export/a i32 (i32.const 1)) + (global $export/b i32 (i32.const 2)) + (global $export/c i32 (i32.const 3)) + (export "memory" (memory $0)) + (export "add" (func $export/add)) + (export "sub" (func $export/sub)) + (export "renamed_mul" (func $export/mul)) + (export "a" (global $export/a)) + (export "b" (global $export/b)) + (export "renamed_c" (global $export/c)) + (export "ns.two" (func $export/ns.one)) + (export "default.two" (func $export/ns.one)) + (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.add + ) + (func $export/sub (; 1 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.sub + ) + (func $export/mul (; 2 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.mul + ) + (func $export/ns.one (; 3 ;) + nop + ) +) diff --git a/tests/compiler/exportstar.ts b/tests/compiler/exportstar.ts new file mode 100644 index 0000000000..ffea9c3cfe --- /dev/null +++ b/tests/compiler/exportstar.ts @@ -0,0 +1 @@ +export * from "./export"; diff --git a/tests/compiler/exportstar.untouched.wat b/tests/compiler/exportstar.untouched.wat new file mode 100644 index 0000000000..76fd31cf3f --- /dev/null +++ b/tests/compiler/exportstar.untouched.wat @@ -0,0 +1,39 @@ +(module + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (type $none_=>_none (func)) + (memory $0 0) + (table $0 1 funcref) + (global $export/a i32 (i32.const 1)) + (global $export/b i32 (i32.const 2)) + (global $export/c i32 (i32.const 3)) + (export "memory" (memory $0)) + (export "add" (func $export/add)) + (export "sub" (func $export/sub)) + (export "renamed_mul" (func $export/mul)) + (export "a" (global $export/a)) + (export "b" (global $export/b)) + (export "renamed_c" (global $export/c)) + (export "ns.two" (func $export/ns.two)) + (export "default.two" (func $export/ns.two)) + (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.add + ) + (func $export/sub (; 1 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.sub + ) + (func $export/mul (; 2 ;) (param $0 i32) (param $1 i32) (result i32) + local.get $0 + local.get $1 + i32.mul + ) + (func $export/ns.one (; 3 ;) + nop + ) + (func $export/ns.two (; 4 ;) + nop + ) +) diff --git a/tests/compiler/loop-wrap.optimized.wat b/tests/compiler/loop-wrap.optimized.wat index be239915d9..0e348c49ae 100644 --- a/tests/compiler/loop-wrap.optimized.wat +++ b/tests/compiler/loop-wrap.optimized.wat @@ -25,21 +25,21 @@ ) (func $loop-wrap/testFirstWrapped (; 1 ;) (local $0 i32) - loop $while-continue|1 - local.get $0 - i32.const 1 - i32.add - local.tee $0 - i32.const 255 - i32.and - i32.const 0 + loop $do-continue|1 local.get $0 i32.const 255 i32.and i32.const 10 i32.ne - select - br_if $while-continue|1 + if + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 255 + i32.and + br_if $do-continue|1 + end end ) (func $loop-wrap/testSubsequentWrapped (; 2 ;) (param $0 i32) diff --git a/tests/compiler/loop-wrap.untouched.wat b/tests/compiler/loop-wrap.untouched.wat index e77f401ce4..5ef0e1dae7 100644 --- a/tests/compiler/loop-wrap.untouched.wat +++ b/tests/compiler/loop-wrap.untouched.wat @@ -37,8 +37,16 @@ (local $1 i32) i32.const 0 local.set $0 - block $while-break|1 - loop $while-continue|1 + block $do-break|1 + loop $do-continue|1 + local.get $0 + i32.const 255 + i32.and + i32.const 10 + i32.eq + if + br $do-break|1 + end local.get $0 i32.const 1 i32.add @@ -47,17 +55,7 @@ i32.and local.set $1 local.get $1 - if - local.get $0 - i32.const 255 - i32.and - i32.const 10 - i32.eq - if - br $while-break|1 - end - br $while-continue|1 - end + br_if $do-continue|1 end end ) diff --git a/tests/compiler/memcpy.ts b/tests/compiler/memcpy.ts index 88879a3aa0..3c7a13774b 100644 --- a/tests/compiler/memcpy.ts +++ b/tests/compiler/memcpy.ts @@ -39,7 +39,7 @@ export function memcpy(dest: usize, src: usize, n: usize): usize { // if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each // doing shifts if faster when copying enough bytes (here: 32 or more) if (n >= 32) { - switch (dest % 4) { + switch (dest % 4) { // known to be != 0 case 1: w = load(src); diff --git a/tests/compiler/number.untouched.wat b/tests/compiler/number.untouched.wat index 09c098a4ff..ac383e96e8 100644 --- a/tests/compiler/number.untouched.wat +++ b/tests/compiler/number.untouched.wat @@ -1142,7 +1142,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 14 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/reexport.optimized.wat b/tests/compiler/reexport.optimized.wat index 2aa38298ec..ca01c6d093 100644 --- a/tests/compiler/reexport.optimized.wat +++ b/tests/compiler/reexport.optimized.wat @@ -17,6 +17,14 @@ (export "renamed_add" (func $export/add)) (export "rerenamed_sub" (func $export/mul)) (export "renamed_ns.two" (func $export/ns.one)) + (export "exportstar.add" (func $export/add)) + (export "exportstar.sub" (func $export/sub)) + (export "exportstar.renamed_mul" (func $export/mul)) + (export "exportstar.a" (global $export/a)) + (export "exportstar.b" (global $export/b)) + (export "exportstar.renamed_c" (global $export/c)) + (export "exportstar.ns.two" (func $export/ns.one)) + (export "exportstar.default.two" (func $export/ns.one)) (start $~start) (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) local.get $0 diff --git a/tests/compiler/reexport.ts b/tests/compiler/reexport.ts index c48dbf71ea..7b4f8172e4 100644 --- a/tests/compiler/reexport.ts +++ b/tests/compiler/reexport.ts @@ -24,3 +24,6 @@ export { imported_add(1, 2) + imported_sub(3, 4); export { ns as renamed_ns } from "./export"; + +import * as exportstar from "./exportstar"; +export { exportstar }; diff --git a/tests/compiler/reexport.untouched.wat b/tests/compiler/reexport.untouched.wat index 8c84f16753..19735a0f92 100644 --- a/tests/compiler/reexport.untouched.wat +++ b/tests/compiler/reexport.untouched.wat @@ -18,6 +18,14 @@ (export "renamed_add" (func $export/add)) (export "rerenamed_sub" (func $export/mul)) (export "renamed_ns.two" (func $export/ns.two)) + (export "exportstar.add" (func $export/add)) + (export "exportstar.sub" (func $export/sub)) + (export "exportstar.renamed_mul" (func $export/mul)) + (export "exportstar.a" (global $export/a)) + (export "exportstar.b" (global $export/b)) + (export "exportstar.renamed_c" (global $export/c)) + (export "exportstar.ns.two" (func $export/ns.two)) + (export "exportstar.default.two" (func $export/ns.two)) (start $~start) (func $export/add (; 0 ;) (param $0 i32) (param $1 i32) (result i32) local.get $0 diff --git a/tests/compiler/resolve-binary.untouched.wat b/tests/compiler/resolve-binary.untouched.wat index dd2e953b7f..3e2365707a 100644 --- a/tests/compiler/resolve-binary.untouched.wat +++ b/tests/compiler/resolve-binary.untouched.wat @@ -2122,7 +2122,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/resolve-elementaccess.untouched.wat b/tests/compiler/resolve-elementaccess.untouched.wat index 3fc1cec58b..037c081a55 100644 --- a/tests/compiler/resolve-elementaccess.untouched.wat +++ b/tests/compiler/resolve-elementaccess.untouched.wat @@ -1126,7 +1126,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 12 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/resolve-ternary.untouched.wat b/tests/compiler/resolve-ternary.untouched.wat index 9fe36fff07..986b55803c 100644 --- a/tests/compiler/resolve-ternary.untouched.wat +++ b/tests/compiler/resolve-ternary.untouched.wat @@ -2463,7 +2463,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/memory/memcpy (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) diff --git a/tests/compiler/std/array.optimized.wat b/tests/compiler/std/array.optimized.wat index 83a49f35dc..798aea0dba 100644 --- a/tests/compiler/std/array.optimized.wat +++ b/tests/compiler/std/array.optimized.wat @@ -4325,7 +4325,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -4353,7 +4353,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4403,7 +4403,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4469,7 +4469,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4519,7 +4519,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4816,7 +4816,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -4844,7 +4844,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4894,7 +4894,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -4960,7 +4960,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5010,7 +5010,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5329,7 +5329,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $3 @@ -5357,7 +5357,7 @@ local.get $5 local.get $3 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5408,7 +5408,7 @@ local.get $5 local.get $4 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5474,7 +5474,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -5525,7 +5525,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add diff --git a/tests/compiler/std/array.untouched.wat b/tests/compiler/std/array.untouched.wat index a25ffb50b5..3ed0943687 100644 --- a/tests/compiler/std/array.untouched.wat +++ b/tests/compiler/std/array.untouched.wat @@ -7121,7 +7121,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -7153,7 +7153,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7207,14 +7207,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7286,7 +7286,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7338,14 +7338,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7734,7 +7734,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -7766,7 +7766,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7820,14 +7820,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7899,7 +7899,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -7951,14 +7951,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8380,7 +8380,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -8412,7 +8412,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8466,14 +8466,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8545,7 +8545,7 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8597,14 +8597,14 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8856,7 +8856,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -8888,7 +8888,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -8942,14 +8942,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -9021,7 +9021,7 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -9073,14 +9073,14 @@ local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $9 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -13442,7 +13442,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 251 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/std/libm.untouched.wat b/tests/compiler/std/libm.untouched.wat index 6dae2603fd..8fa199dea0 100644 --- a/tests/compiler/std/libm.untouched.wat +++ b/tests/compiler/std/libm.untouched.wat @@ -1731,8 +1731,7 @@ if (result f64) global.get $~lib/math/NativeMath.PI else - i32.const 0 - f64.convert_i32_s + f64.const 0 end local.set $9 local.get $7 diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 1d3bfff00f..baa0a69ddd 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -3427,8 +3427,7 @@ if (result f64) global.get $~lib/math/NativeMath.PI else - i32.const 0 - f64.convert_i32_s + f64.const 0 end local.set $9 local.get $7 diff --git a/tests/compiler/std/string-casemapping.optimized.wat b/tests/compiler/std/string-casemapping.optimized.wat index f01464cab0..c9a96230af 100644 --- a/tests/compiler/std/string-casemapping.optimized.wat +++ b/tests/compiler/std/string-casemapping.optimized.wat @@ -2825,7 +2825,7 @@ if i32.const 0 i32.const 13984 - i32.const 21 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string-casemapping.untouched.wat b/tests/compiler/std/string-casemapping.untouched.wat index dfcbac6ce7..f1c5db3563 100644 --- a/tests/compiler/std/string-casemapping.untouched.wat +++ b/tests/compiler/std/string-casemapping.untouched.wat @@ -4401,7 +4401,7 @@ if i32.const 0 i32.const 14272 - i32.const 21 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string-encoding.optimized.wat b/tests/compiler/std/string-encoding.optimized.wat index 63da50a5de..34d0e0700c 100644 --- a/tests/compiler/std/string-encoding.optimized.wat +++ b/tests/compiler/std/string-encoding.optimized.wat @@ -2111,7 +2111,7 @@ if i32.const 0 i32.const 432 - i32.const 707 + i32.const 719 i32.const 6 call $~lib/builtins/abort unreachable @@ -2592,7 +2592,7 @@ if i32.const 0 i32.const 432 - i32.const 723 + i32.const 735 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string-encoding.untouched.wat b/tests/compiler/std/string-encoding.untouched.wat index af7f14d76c..d2c27948bd 100644 --- a/tests/compiler/std/string-encoding.untouched.wat +++ b/tests/compiler/std/string-encoding.untouched.wat @@ -3745,7 +3745,7 @@ if i32.const 0 i32.const 432 - i32.const 707 + i32.const 719 i32.const 6 call $~lib/builtins/abort unreachable @@ -4300,7 +4300,7 @@ if i32.const 0 i32.const 432 - i32.const 723 + i32.const 735 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string.optimized.wat b/tests/compiler/std/string.optimized.wat index 11f55bcdbe..96d16046e2 100644 --- a/tests/compiler/std/string.optimized.wat +++ b/tests/compiler/std/string.optimized.wat @@ -1671,7 +1671,7 @@ if i32.const 0 i32.const 528 - i32.const 21 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable @@ -4283,7 +4283,7 @@ if i32.const 10896 i32.const 528 - i32.const 310 + i32.const 322 i32.const 6 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/std/string.untouched.wat b/tests/compiler/std/string.untouched.wat index 063763e76a..ea9a9bf04a 100644 --- a/tests/compiler/std/string.untouched.wat +++ b/tests/compiler/std/string.untouched.wat @@ -2140,7 +2140,7 @@ if i32.const 0 i32.const 528 - i32.const 21 + i32.const 33 i32.const 4 call $~lib/builtins/abort unreachable @@ -6907,7 +6907,7 @@ if i32.const 10896 i32.const 528 - i32.const 310 + i32.const 322 i32.const 6 call $~lib/builtins/abort unreachable @@ -9817,7 +9817,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 88 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/std/typedarray.optimized.wat b/tests/compiler/std/typedarray.optimized.wat index 012bd33244..0865f15820 100644 --- a/tests/compiler/std/typedarray.optimized.wat +++ b/tests/compiler/std/typedarray.optimized.wat @@ -2560,7 +2560,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.tee $2 @@ -2588,7 +2588,7 @@ local.get $5 local.get $2 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2638,7 +2638,7 @@ local.get $5 local.get $3 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2704,7 +2704,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -2754,7 +2754,7 @@ local.get $5 local.get $1 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add diff --git a/tests/compiler/std/typedarray.untouched.wat b/tests/compiler/std/typedarray.untouched.wat index 5a9464760c..2f995e4d76 100644 --- a/tests/compiler/std/typedarray.untouched.wat +++ b/tests/compiler/std/typedarray.untouched.wat @@ -3231,7 +3231,7 @@ i32.const 31 i32.add i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl local.set $3 @@ -3263,7 +3263,7 @@ local.get $4 local.get $7 i32.const 6 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3317,14 +3317,14 @@ local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $5 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3396,7 +3396,7 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -3448,14 +3448,14 @@ local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add local.get $4 local.get $8 i32.const 5 - i32.shr_s + i32.shr_u i32.const 2 i32.shl i32.add @@ -35621,7 +35621,7 @@ br $while-continue|4 end end - local.get $15 + unreachable ) (func $~lib/util/number/prettify (; 537 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) diff --git a/tests/compiler/wasi-snapshot-preview1.ts b/tests/compiler/wasi-snapshot-preview1.ts index bc5ea71f7d..271f784475 100644 --- a/tests/compiler/wasi-snapshot-preview1.ts +++ b/tests/compiler/wasi-snapshot-preview1.ts @@ -8,7 +8,7 @@ import { subscription_fd_readwrite, signal, prestat_dir -} from "bindings/wasi_snapshot_preview1"; +} from "bindings/wasi"; import { Target } from "shared/target"; diff --git a/tests/compiler/while.optimized.wat b/tests/compiler/while.optimized.wat index 8c300ec39a..af8e967f10 100644 --- a/tests/compiler/while.optimized.wat +++ b/tests/compiler/while.optimized.wat @@ -243,7 +243,7 @@ if i32.const 0 i32.const 32 - i32.const 108 + i32.const 117 i32.const 2 call $~lib/builtins/abort unreachable @@ -282,7 +282,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -291,7 +291,7 @@ if i32.const 0 i32.const 32 - i32.const 127 + i32.const 136 i32.const 2 call $~lib/builtins/abort unreachable @@ -1297,7 +1297,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1306,7 +1306,7 @@ if i32.const 0 i32.const 32 - i32.const 143 + i32.const 152 i32.const 2 call $~lib/builtins/abort unreachable @@ -1357,7 +1357,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -1366,7 +1366,7 @@ if i32.const 0 i32.const 32 - i32.const 163 + i32.const 172 i32.const 2 call $~lib/builtins/abort unreachable @@ -1377,6 +1377,7 @@ call $~lib/rt/pure/__release ) (func $start:while (; 24 ;) + (local $0 i32) i32.const 0 global.set $while/ran call $while/testSimple @@ -1429,6 +1430,26 @@ call $~lib/builtins/abort unreachable end + loop $while-continue|0 + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.ne + br_if $while-continue|0 + end + local.get $0 + i32.const 10 + i32.ne + if + i32.const 0 + i32.const 32 + i32.const 72 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $while/ran i32.const 1 @@ -1449,7 +1470,7 @@ if i32.const 0 i32.const 32 - i32.const 113 + i32.const 122 i32.const 0 call $~lib/builtins/abort unreachable @@ -1462,7 +1483,7 @@ if i32.const 0 i32.const 32 - i32.const 132 + i32.const 141 i32.const 0 call $~lib/builtins/abort unreachable @@ -1475,7 +1496,7 @@ if i32.const 0 i32.const 32 - i32.const 148 + i32.const 157 i32.const 0 call $~lib/builtins/abort unreachable @@ -1488,7 +1509,7 @@ if i32.const 0 i32.const 32 - i32.const 168 + i32.const 177 i32.const 0 call $~lib/builtins/abort unreachable diff --git a/tests/compiler/while.ts b/tests/compiler/while.ts index 1a8e98548c..43e5e768f7 100644 --- a/tests/compiler/while.ts +++ b/tests/compiler/while.ts @@ -62,6 +62,15 @@ ran = false; testAlwaysTrue(); assert(ran); +function testAlwaysTrueNeverBreaks(): i32 { + var i = 0; + while (true) { + if (++i == 10) return i; + } + // no return required +} +assert(testAlwaysTrueNeverBreaks() == 10); + function testAlwaysFalse(): void { var i = 0; while (false) { diff --git a/tests/compiler/while.untouched.wat b/tests/compiler/while.untouched.wat index 08894a2c67..da51f635c6 100644 --- a/tests/compiler/while.untouched.wat +++ b/tests/compiler/while.untouched.wat @@ -2,8 +2,8 @@ (type $none_=>_none (func)) (type $i32_=>_none (func (param i32))) (type $i32_i32_=>_none (func (param i32 i32))) - (type $i32_=>_i32 (func (param i32) (result i32))) (type $none_=>_i32 (func (result i32))) + (type $i32_=>_i32 (func (param i32) (result i32))) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $i32_i32_i32_=>_i32 (func (param i32 i32 i32) (result i32))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) @@ -281,7 +281,32 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysFalse (; 9 ;) + (func $while/testAlwaysTrueNeverBreaks (; 9 ;) (result i32) + (local $0 i32) + (local $1 i32) + i32.const 0 + local.set $0 + loop $while-continue|0 + i32.const 1 + local.set $1 + local.get $1 + if + local.get $0 + i32.const 1 + i32.add + local.tee $0 + i32.const 10 + i32.eq + if + local.get $0 + return + end + br $while-continue|0 + end + end + unreachable + ) + (func $while/testAlwaysFalse (; 10 ;) (local $0 i32) i32.const 0 local.set $0 @@ -292,7 +317,7 @@ if i32.const 0 i32.const 32 - i32.const 71 + i32.const 80 i32.const 2 call $~lib/builtins/abort unreachable @@ -300,7 +325,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysBreaks (; 10 ;) + (func $while/testAlwaysBreaks (; 11 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -325,7 +350,7 @@ if i32.const 0 i32.const 32 - i32.const 83 + i32.const 92 i32.const 2 call $~lib/builtins/abort unreachable @@ -333,7 +358,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testAlwaysReturns (; 11 ;) + (func $while/testAlwaysReturns (; 12 ;) (local $0 i32) (local $1 i32) i32.const 0 @@ -356,13 +381,13 @@ if i32.const 0 i32.const 32 - i32.const 96 + i32.const 105 i32.const 2 call $~lib/builtins/abort unreachable end ) - (func $while/testContinue (; 12 ;) + (func $while/testContinue (; 13 ;) (local $0 i32) (local $1 i32) i32.const 10 @@ -386,7 +411,7 @@ if i32.const 0 i32.const 32 - i32.const 108 + i32.const 117 i32.const 2 call $~lib/builtins/abort unreachable @@ -394,7 +419,7 @@ i32.const 1 global.set $while/ran ) - (func $while/testNestedContinue (; 13 ;) + (func $while/testNestedContinue (; 14 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -434,7 +459,7 @@ if i32.const 0 i32.const 32 - i32.const 126 + i32.const 135 i32.const 2 call $~lib/builtins/abort unreachable @@ -446,7 +471,7 @@ if i32.const 0 i32.const 32 - i32.const 127 + i32.const 136 i32.const 2 call $~lib/builtins/abort unreachable @@ -454,7 +479,7 @@ i32.const 1 global.set $while/ran ) - (func $~lib/rt/tlsf/removeBlock (; 14 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/removeBlock (; 15 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -664,7 +689,7 @@ end end ) - (func $~lib/rt/tlsf/insertBlock (; 15 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/insertBlock (; 16 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1014,7 +1039,7 @@ local.get $7 i32.store offset=4 ) - (func $~lib/rt/tlsf/addMemory (; 16 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/addMemory (; 17 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1162,7 +1187,7 @@ call $~lib/rt/tlsf/insertBlock i32.const 1 ) - (func $~lib/rt/tlsf/maybeInitialize (; 17 ;) (result i32) + (func $~lib/rt/tlsf/maybeInitialize (; 18 ;) (result i32) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1312,7 +1337,7 @@ end local.get $0 ) - (func $~lib/rt/tlsf/prepareSize (; 18 ;) (param $0 i32) (result i32) + (func $~lib/rt/tlsf/prepareSize (; 19 ;) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) local.get $0 @@ -1341,7 +1366,7 @@ i32.gt_u select ) - (func $~lib/rt/tlsf/searchBlock (; 19 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/searchBlock (; 20 ;) (param $0 i32) (param $1 i32) (result i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1524,7 +1549,7 @@ end local.get $7 ) - (func $~lib/rt/tlsf/growMemory (; 20 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/growMemory (; 21 ;) (param $0 i32) (param $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) @@ -1608,7 +1633,7 @@ call $~lib/rt/tlsf/addMemory drop ) - (func $~lib/rt/tlsf/prepareBlock (; 21 ;) (param $0 i32) (param $1 i32) (param $2 i32) + (func $~lib/rt/tlsf/prepareBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (local $3 i32) (local $4 i32) (local $5 i32) @@ -1703,7 +1728,7 @@ i32.store end ) - (func $~lib/rt/tlsf/allocateBlock (; 22 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) + (func $~lib/rt/tlsf/allocateBlock (; 23 ;) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (local $3 i32) (local $4 i32) global.get $~lib/rt/tlsf/collectLock @@ -1814,7 +1839,7 @@ call $~lib/rt/rtrace/onalloc local.get $4 ) - (func $~lib/rt/tlsf/__alloc (; 23 ;) (param $0 i32) (param $1 i32) (result i32) + (func $~lib/rt/tlsf/__alloc (; 24 ;) (param $0 i32) (param $1 i32) (result i32) call $~lib/rt/tlsf/maybeInitialize local.get $0 local.get $1 @@ -1822,7 +1847,7 @@ i32.const 16 i32.add ) - (func $~lib/rt/pure/increment (; 24 ;) (param $0 i32) + (func $~lib/rt/pure/increment (; 25 ;) (param $0 i32) (local $1 i32) local.get $0 i32.load offset=4 @@ -1867,7 +1892,7 @@ unreachable end ) - (func $~lib/rt/pure/__retain (; 25 ;) (param $0 i32) (result i32) + (func $~lib/rt/pure/__retain (; 26 ;) (param $0 i32) (result i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1879,7 +1904,7 @@ end local.get $0 ) - (func $while/Ref#constructor (; 26 ;) (param $0 i32) (result i32) + (func $while/Ref#constructor (; 27 ;) (param $0 i32) (result i32) local.get $0 i32.eqz if @@ -1891,7 +1916,7 @@ end local.get $0 ) - (func $~lib/rt/pure/__release (; 27 ;) (param $0 i32) + (func $~lib/rt/pure/__release (; 28 ;) (param $0 i32) local.get $0 global.get $~lib/heap/__heap_base i32.gt_u @@ -1902,7 +1927,7 @@ call $~lib/rt/pure/decrement end ) - (func $while/testRef (; 28 ;) + (func $while/testRef (; 29 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -1958,7 +1983,7 @@ if i32.const 0 i32.const 32 - i32.const 142 + i32.const 151 i32.const 2 call $~lib/builtins/abort unreachable @@ -1969,7 +1994,7 @@ if i32.const 0 i32.const 32 - i32.const 143 + i32.const 152 i32.const 2 call $~lib/builtins/abort unreachable @@ -1979,11 +2004,11 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $while/getRef (; 29 ;) (result i32) + (func $while/getRef (; 30 ;) (result i32) i32.const 0 call $while/Ref#constructor ) - (func $while/testRefAutorelease (; 30 ;) + (func $while/testRefAutorelease (; 31 ;) (local $0 i32) (local $1 i32) (local $2 i32) @@ -2037,7 +2062,7 @@ if i32.const 0 i32.const 32 - i32.const 162 + i32.const 171 i32.const 2 call $~lib/builtins/abort unreachable @@ -2048,7 +2073,7 @@ if i32.const 0 i32.const 32 - i32.const 163 + i32.const 172 i32.const 2 call $~lib/builtins/abort unreachable @@ -2058,7 +2083,7 @@ local.get $1 call $~lib/rt/pure/__release ) - (func $start:while (; 31 ;) + (func $start:while (; 32 ;) i32.const 0 global.set $while/ran call $while/testSimple @@ -2111,6 +2136,18 @@ call $~lib/builtins/abort unreachable end + call $while/testAlwaysTrueNeverBreaks + i32.const 10 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 72 + i32.const 0 + call $~lib/builtins/abort + unreachable + end i32.const 0 global.set $while/ran call $while/testAlwaysFalse @@ -2119,7 +2156,7 @@ if i32.const 0 i32.const 32 - i32.const 76 + i32.const 85 i32.const 0 call $~lib/builtins/abort unreachable @@ -2132,7 +2169,7 @@ if i32.const 0 i32.const 32 - i32.const 88 + i32.const 97 i32.const 0 call $~lib/builtins/abort unreachable @@ -2145,7 +2182,7 @@ if i32.const 0 i32.const 32 - i32.const 100 + i32.const 109 i32.const 0 call $~lib/builtins/abort unreachable @@ -2158,7 +2195,7 @@ if i32.const 0 i32.const 32 - i32.const 113 + i32.const 122 i32.const 0 call $~lib/builtins/abort unreachable @@ -2171,7 +2208,7 @@ if i32.const 0 i32.const 32 - i32.const 132 + i32.const 141 i32.const 0 call $~lib/builtins/abort unreachable @@ -2184,7 +2221,7 @@ if i32.const 0 i32.const 32 - i32.const 148 + i32.const 157 i32.const 0 call $~lib/builtins/abort unreachable @@ -2197,13 +2234,13 @@ if i32.const 0 i32.const 32 - i32.const 168 + i32.const 177 i32.const 0 call $~lib/builtins/abort unreachable end ) - (func $~start (; 32 ;) + (func $~start (; 33 ;) global.get $~started if return @@ -2213,10 +2250,10 @@ end call $start:while ) - (func $~lib/rt/pure/__collect (; 33 ;) + (func $~lib/rt/pure/__collect (; 34 ;) return ) - (func $~lib/rt/tlsf/freeBlock (; 34 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/tlsf/freeBlock (; 35 ;) (param $0 i32) (param $1 i32) (local $2 i32) local.get $1 i32.load @@ -2232,7 +2269,7 @@ local.get $1 call $~lib/rt/rtrace/onfree ) - (func $~lib/rt/pure/decrement (; 35 ;) (param $0 i32) + (func $~lib/rt/pure/decrement (; 36 ;) (param $0 i32) (local $1 i32) (local $2 i32) local.get $0 @@ -2309,7 +2346,7 @@ i32.store offset=4 end ) - (func $~lib/rt/pure/__visit (; 36 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/pure/__visit (; 37 ;) (param $0 i32) (param $1 i32) local.get $0 global.get $~lib/heap/__heap_base i32.lt_u @@ -2333,7 +2370,7 @@ i32.sub call $~lib/rt/pure/decrement ) - (func $~lib/rt/__visit_members (; 37 ;) (param $0 i32) (param $1 i32) + (func $~lib/rt/__visit_members (; 38 ;) (param $0 i32) (param $1 i32) (local $2 i32) block $switch$1$default block $switch$1$case$4 diff --git a/tests/packages/packages/g/test.js b/tests/packages/packages/g/test.js index 880f92d597..ba9c641541 100644 --- a/tests/packages/packages/g/test.js +++ b/tests/packages/packages/g/test.js @@ -10,7 +10,7 @@ let argv = [ ]; asc.main(argv, error => { - if (/Import file .*lib\/a.ts.* not found/g.test(error.message)) { + if (/Import .*lib\/a.* not found/g.test(error.message)) { process.exit(0); } console.error("Failed!\n" + error); diff --git a/tests/parser/forof.ts b/tests/parser/forof.ts new file mode 100644 index 0000000000..3cab01d38c --- /dev/null +++ b/tests/parser/forof.ts @@ -0,0 +1,16 @@ +for (foo of bar) { + ; +} +for (var foo of bar) { + ; +} +for (let foo of bar) { + ; +} +for (const foo of bar) { + ; +} +for (foo of bar) ; +for (var foo of bar) ; +for (let foo of bar) ; +for (const foo of bar) ; diff --git a/tests/parser/forof.ts.fixture.ts b/tests/parser/forof.ts.fixture.ts new file mode 100644 index 0000000000..3cab01d38c --- /dev/null +++ b/tests/parser/forof.ts.fixture.ts @@ -0,0 +1,16 @@ +for (foo of bar) { + ; +} +for (var foo of bar) { + ; +} +for (let foo of bar) { + ; +} +for (const foo of bar) { + ; +} +for (foo of bar) ; +for (var foo of bar) ; +for (let foo of bar) ; +for (const foo of bar) ;