diff --git a/package.json b/package.json index 2ca904c..5940248 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ }, "lint-staged": { "*.ts": [ - "eslint --ignore-path .eslintignore --config .eslintrc.json --fix '**/*.ts'", + "eslint --ignore-path .eslintignore --config .eslintrc.json --fix --quiet '**/*.ts'", "prettier --ignore-path .prettierignore --config .prettierrc.json --write '**/*.ts'" ] }, diff --git a/src/backend/binaryen/utils.ts b/src/backend/binaryen/utils.ts index 2f4d8b7..877a577 100644 --- a/src/backend/binaryen/utils.ts +++ b/src/backend/binaryen/utils.ts @@ -830,16 +830,26 @@ export namespace FunctionalFuncs { module: binaryen.Module, expression: binaryen.ExpressionRef, expressionType?: binaryen.Type, + isSigned = true, ): binaryen.ExpressionRef { const exprType = expressionType ? expressionType : binaryen.getExpressionType(expression); switch (exprType) { case binaryen.f64: { - return module.i32.trunc_s.f64(expression); + return module.i32.wrap( + convertTypeToI64( + module, + expression, + binaryen.f64, + isSigned, + ), + ); } case binaryen.f32: { - return module.i32.trunc_s.f32(expression); + return isSigned + ? module.i32.trunc_s.f32(expression) + : module.i32.trunc_u.f32(expression); } case binaryen.i64: { return module.i32.wrap(expression); @@ -856,22 +866,29 @@ export namespace FunctionalFuncs { module: binaryen.Module, expression: binaryen.ExpressionRef, expressionType?: binaryen.Type, + isSigned = true, ): binaryen.ExpressionRef { const exprType = expressionType ? expressionType : binaryen.getExpressionType(expression); switch (exprType) { case binaryen.f64: { - return module.i64.trunc_s.f64(expression); + return isSigned + ? module.i64.trunc_s.f64(expression) + : module.i64.trunc_u.f64(expression); } case binaryen.f32: { - return module.i64.trunc_s.f32(expression); + return isSigned + ? module.i64.trunc_s.f32(expression) + : module.i64.trunc_u.f32(expression); } case binaryen.i64: { return expression; } case binaryen.i32: { - return module.i64.extend_s(expression); + return isSigned + ? module.i64.extend_s(expression) + : module.i64.extend_u(expression); } } return binaryen.none; @@ -881,6 +898,7 @@ export namespace FunctionalFuncs { module: binaryen.Module, expression: binaryen.ExpressionRef, expressionType?: binaryen.Type, + isSigned = true, ): binaryen.ExpressionRef { const exprType = expressionType ? expressionType @@ -893,10 +911,14 @@ export namespace FunctionalFuncs { return expression; } case binaryen.i64: { - return module.f32.convert_s.i64(expression); + return isSigned + ? module.f32.convert_s.i64(expression) + : module.f32.convert_u.i64(expression); } case binaryen.i32: { - return module.f32.convert_s.i32(expression); + return isSigned + ? module.f32.convert_s.i32(expression) + : module.f32.convert_u.i32(expression); } } @@ -907,6 +929,7 @@ export namespace FunctionalFuncs { module: binaryen.Module, expression: binaryen.ExpressionRef, expressionType?: binaryen.Type, + isSigned = true, ): binaryen.ExpressionRef { const exprType = expressionType ? expressionType @@ -919,10 +942,14 @@ export namespace FunctionalFuncs { return module.f64.promote(expression); } case binaryen.i64: { - return module.f64.convert_s.i64(expression); + return isSigned + ? module.f64.convert_s.i64(expression) + : module.f64.convert_u.i64(expression); } case binaryen.i32: { - return module.f64.convert_s.i32(expression); + return isSigned + ? module.f64.convert_s.i32(expression) + : module.f64.convert_u.i32(expression); } } return binaryen.none; @@ -1136,24 +1163,8 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.shr_s( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), binaryen.i32, ); @@ -1162,26 +1173,11 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.shr_u( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), binaryen.i32, + false, ); } case ts.SyntaxKind.LessThanToken: { @@ -1194,24 +1190,8 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.shl( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), binaryen.i32, ); @@ -1244,24 +1224,8 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.and( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), binaryen.i32, ); @@ -1270,24 +1234,8 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.or( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), binaryen.i32, ); @@ -1305,24 +1253,8 @@ export namespace FunctionalFuncs { return convertTypeToF64( module, module.i32.xor( - convertTypeToI32( - module, - convertTypeToI64( - module, - leftValueRef, - binaryen.f64, - ), - binaryen.i64, - ), - convertTypeToI32( - module, - convertTypeToI64( - module, - rightValueRef, - binaryen.f64, - ), - binaryen.i64, - ), + convertTypeToI32(module, leftValueRef, binaryen.f64), + convertTypeToI32(module, rightValueRef, binaryen.f64), ), ); } @@ -1676,10 +1608,24 @@ export namespace FunctionalFuncs { return module.i64.ge_s(leftValueRef, rightValueRef); } case ts.SyntaxKind.GreaterThanGreaterThanToken: { - return module.i64.shr_s(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.shr_s( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: { - return module.i64.shr_u(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.shr_u( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } case ts.SyntaxKind.LessThanToken: { return module.i64.lt_s(leftValueRef, rightValueRef); @@ -1688,19 +1634,47 @@ export namespace FunctionalFuncs { return module.i64.le_s(leftValueRef, rightValueRef); } case ts.SyntaxKind.LessThanLessThanToken: { - return module.i64.shl(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.shl( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } case ts.SyntaxKind.AmpersandToken: { - return module.i64.and(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.and( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } case ts.SyntaxKind.BarToken: { - return module.i64.or(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.or( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } case ts.SyntaxKind.PercentToken: { return module.i64.rem_s(leftValueRef, rightValueRef); } case ts.SyntaxKind.CaretToken: { - return module.i64.xor(leftValueRef, rightValueRef); + return convertTypeToI64( + module, + module.i32.xor( + convertTypeToI32(module, leftValueRef, binaryen.i64), + convertTypeToI32(module, rightValueRef, binaryen.i64), + ), + binaryen.i32, + ); } default: throw new UnimplementError( diff --git a/src/backend/binaryen/wasm_expr_gen.ts b/src/backend/binaryen/wasm_expr_gen.ts index 1e45256..3bf8da5 100644 --- a/src/backend/binaryen/wasm_expr_gen.ts +++ b/src/backend/binaryen/wasm_expr_gen.ts @@ -1739,18 +1739,21 @@ export class WASMExpressionGen { this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_I64) { return FunctionalFuncs.convertTypeToI64( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_F32) { return FunctionalFuncs.convertTypeToF32( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } } else if (fromType.kind === ValueTypeKind.NUMBER) { @@ -1759,18 +1762,21 @@ export class WASMExpressionGen { this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_I64) { return FunctionalFuncs.convertTypeToI64( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_F32) { return FunctionalFuncs.convertTypeToF32( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } } else if (fromType.kind === ValueTypeKind.WASM_I64) { @@ -1785,12 +1791,14 @@ export class WASMExpressionGen { this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_F32) { return FunctionalFuncs.convertTypeToF32( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } } else if (fromType.kind === ValueTypeKind.WASM_F32) { @@ -1799,18 +1807,21 @@ export class WASMExpressionGen { this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.NUMBER) { return FunctionalFuncs.convertTypeToF64( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } else if (toType.kind === ValueTypeKind.WASM_I64) { return FunctionalFuncs.convertTypeToI64( this.module, fromValueRef, fromTypeRef, + value.isSigned, ); } } else if (fromType.kind === ValueTypeKind.BOOLEAN) { diff --git a/src/scope.ts b/src/scope.ts index ba97dea..e688a5b 100644 --- a/src/scope.ts +++ b/src/scope.ts @@ -13,6 +13,7 @@ import { FunctionKind, getMethodPrefix, TSContext, + builtinWasmTypes, } from './type.js'; import { ParserContext } from './frontend.js'; import { @@ -322,7 +323,12 @@ export class Scope { } public findType(typeName: string, nested = true): Type | undefined { - const res = builtinTypes.get(typeName); + let res = builtinTypes.get(typeName); + if (res) { + return res; + } + + res = builtinWasmTypes.get(typeName); if (res) { return res; } diff --git a/src/semantics/expression_builder.ts b/src/semantics/expression_builder.ts index 48752b7..0a359d2 100644 --- a/src/semantics/expression_builder.ts +++ b/src/semantics/expression_builder.ts @@ -1062,6 +1062,48 @@ function wrapObjToAny(value: SemanticsValue, type: ValueType) { return new CastValue(SemanticsValueKind.OBJECT_CAST_ANY, type, value); } +function checkSigned(tmpValue: BinaryExprValue): boolean { + if ( + tmpValue.opKind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken + ) { + return false; + } + if (tmpValue.left instanceof BinaryExprValue) { + tmpValue = tmpValue.left; + return checkSigned(tmpValue); + } + if (tmpValue.right instanceof BinaryExprValue) { + tmpValue = tmpValue.right; + return checkSigned(tmpValue); + } + return true; +} + +function judgeIsInt(value: number) { + if (value >= -2147483648 && value < 2147483647 && value % 1 === 0) { + return true; + } else { + return false; + } +} + +function judgeIsF32(value: number) { + if (value >= -8388607 && value < 8388607) { + return true; + } else { + return false; + } +} + +function checkOverflow(value: LiteralValue, type: ValueType) { + if (type.kind === ValueTypeKind.INT) { + return judgeIsInt(value.value as number); + } else if (type.kind === ValueTypeKind.WASM_F32) { + return judgeIsF32(value.value as number); + } + return true; +} + export function newCastValue( type: ValueType, value: SemanticsValue, @@ -1236,16 +1278,24 @@ export function newCastValue( ) if ( value instanceof LiteralValue && - value.type.kind === ValueTypeKind.NUMBER + value.type.kind === ValueTypeKind.NUMBER && + checkOverflow(value, type) ) { value.type = type; return value; } else { - return new CastValue( + let isSigned = true; + const tmpValue = value; + if (tmpValue instanceof BinaryExprValue) { + isSigned = checkSigned(tmpValue); + } + const castedValue = new CastValue( SemanticsValueKind.VALUE_CAST_VALUE, type, value, ); + castedValue.isSigned = isSigned; + return castedValue; } if (value_type.kind == ValueTypeKind.ANY) return new CastValue( @@ -1430,10 +1480,9 @@ function typeUp(upValue: SemanticsValue, downValue: SemanticsValue): boolean { } if ( downValue instanceof LiteralValue && - typeof downValue.value === 'number' && - (downValue.value as number) % 1 === 0 + typeof downValue.value === 'number' ) { - return true; + return judgeIsInt(downValue.value as number); } // TODO: check if upValue's value is integer, if true, return true } diff --git a/src/semantics/value.ts b/src/semantics/value.ts index 43d4bc4..fffe8be 100644 --- a/src/semantics/value.ts +++ b/src/semantics/value.ts @@ -690,6 +690,8 @@ type CastValueKind = | SemanticsValueKind.ANY_CAST_OBJECT | SemanticsValueKind.ANY_CAST_VALUE; export class CastValue extends SemanticsValue { + isSigned = true; + constructor( kind: CastValueKind, type: ValueType, @@ -1357,7 +1359,7 @@ export function operatorString(kind: ts.BinaryOperator): string { case ts.SyntaxKind.GreaterThanGreaterThanToken: return '>>'; case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: - return '<<<'; + return '>>>'; case ts.SyntaxKind.LessThanToken: return '<'; case ts.SyntaxKind.LessThanEqualsToken: diff --git a/tests/samples/unsigned_value.ts b/tests/samples/unsigned_value.ts new file mode 100644 index 0000000..417defc --- /dev/null +++ b/tests/samples/unsigned_value.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +export function random_f64() { + let m_w: f64 = 123456789; + let m_z: f64 = 987654321; + let mask: f64 = 0xffffffff; + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + let result: f64 = (((m_z << 16) + (m_w & 65535)) >>> 0) / 4294967296; + return result; +} + +export function random_i64() { + let m_w: i64 = 123456789; + let m_z: i64 = 987654321; + let mask: i64 = 0xffffffff; + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + let result: i64 = (((m_z << 16) + (m_w & 65535)) >>> 0) / 4294967296; + return result; +} + +export function random_i32() { + let m_w: i32 = 123456789; + let m_z: i32 = 987654321; + let mask: i32 = 0xffffffff; + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + let result: i32 = (((m_z << 16) + (m_w & 65535)) >>> 0) / 4294967296; + return result; +} + +export function random_f32() { + let m_w: f32 = 123456789; + let m_z: f32 = 987654321; + let mask: f32 = 0xffffffff; + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + let result: f32 = (((m_z << 16) + (m_w & 65535)) >>> 0) / 4294967296; + return result; +} diff --git a/tools/validate/wamr/validation.json b/tools/validate/wamr/validation.json index 4d66761..cfc481d 100644 --- a/tools/validate/wamr/validation.json +++ b/tools/validate/wamr/validation.json @@ -4493,6 +4493,31 @@ } ] }, + { + "module": "unsigned_value", + "entries": [ + { + "name": "random_f64", + "args": [], + "result": "0.7322977:f64" + }, + { + "name": "random_i64", + "args": [], + "result": "0:f64" + }, + { + "name": "random_i32", + "args": [], + "result": "0:f64" + }, + { + "name": "random_f32", + "args": [], + "result": "0:f64" + } + ] + }, { "module": "decimalization", "entries": [ @@ -4574,27 +4599,27 @@ { "name": "xor", "args": [], - "result": "4656\n4294967294\n4656" + "result": "4656\n-2\n4656" }, { "name": "and", "args": [], - "result": "4\n4294967295\n4" + "result": "4\n-1\n4" }, { "name": "or", "args": [], - "result": "4660\n4294967295\n4660" + "result": "4660\n-1\n4660" }, { "name": "shl", "args": [], - "result": "-2\n4294967294\n8" + "result": "-2\n-2\n8" }, { "name": "shr", "args": [], - "result": "1073741823\n1073741824\n34359738367\n34359738367\n2\n2147483648" + "result": "1073741823\n1073741824\n-1\n2147483647\n2\n2147483648" } ] },