diff --git a/src/builtins.ts b/src/builtins.ts index a26c04ac..760e7960 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -1176,78 +1176,57 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty } return ret; - case "reinterpret": // reinterpret(value: T1) -> T2 + case "reinterpret": // reinterpret(value: *) -> T if (operands.length != 1) { - if (typeArguments) { - if (typeArguments.length >= 2) - compiler.currentType = typeArguments[1]; - if (typeArguments.length != 2) - compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "2", typeArguments.length.toString(10)); + if (!(typeArguments && typeArguments.length == 1)) { + if (typeArguments && typeArguments.length) + compiler.currentType = typeArguments[0]; + compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"); } compiler.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, "1", operands.length.toString(10)); return module.createUnreachable(); } - if (typeArguments) { - if (typeArguments.length != 2) { - if (typeArguments.length >= 2) - compiler.currentType = typeArguments[1]; - compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "2", typeArguments.length.toString(10)); - return module.createUnreachable(); - } - arg0 = compiler.compileExpression(operands[0], typeArguments[0]); - } else - arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE); + if (!(typeArguments && typeArguments.length == 1)) { + if (typeArguments && typeArguments.length) + compiler.currentType = typeArguments[0]; + compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"); + return module.createUnreachable(); + } - switch (compiler.currentType.kind) { + switch (typeArguments[0].kind) { case TypeKind.I32: case TypeKind.U32: - if (typeArguments) { - if (typeArguments[1].kind != TypeKind.F32) { - compiler.error(DiagnosticCode.Type_0_cannot_be_reinterpreted_as_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString()); - return module.createUnreachable(); - } - compiler.currentType = typeArguments[1]; - } else - compiler.currentType = Type.f32; - ret = module.createUnary(UnaryOp.ReinterpretI32, arg0); + arg0 = compiler.compileExpression(operands[0], Type.f32); + ret = module.createUnary(UnaryOp.ReinterpretF32, arg0); break; case TypeKind.I64: case TypeKind.U64: - if (typeArguments) { - if (typeArguments[1].kind != TypeKind.F64) { - compiler.error(DiagnosticCode.Type_0_cannot_be_reinterpreted_as_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString()); - return module.createUnreachable(); - } - compiler.currentType = typeArguments[1]; - } else - compiler.currentType = Type.f64; - ret = module.createUnary(UnaryOp.ReinterpretI64, arg0); + arg0 = compiler.compileExpression(operands[0], Type.f64); + ret = module.createUnary(UnaryOp.ReinterpretF64, arg0); + break; + + case TypeKind.USIZE: + if (typeArguments[0].isReference) { + compiler.error(DiagnosticCode.Operation_not_supported, reportNode.range); + compiler.currentType = typeArguments[0]; + return module.createUnreachable(); + } + // fall-through + case TypeKind.ISIZE: + arg0 = compiler.compileExpression(operands[0], compiler.options.target == Target.WASM64 ? Type.f64 : Type.f32); + ret = module.createUnary(compiler.options.target == Target.WASM64 ? UnaryOp.ReinterpretF64 : UnaryOp.ReinterpretF32, arg0); break; case TypeKind.F32: - if (typeArguments) { - if (!(typeArguments[1].is(TypeFlags.INTEGER) && typeArguments[1].size == 32)) { - compiler.error(DiagnosticCode.Type_0_cannot_be_reinterpreted_as_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString()); - return module.createUnreachable(); - } - compiler.currentType = typeArguments[1]; - } else - compiler.currentType = Type.i32; - ret = module.createUnary(UnaryOp.ReinterpretF32, arg0); + arg0 = compiler.compileExpression(operands[0], Type.u32); + ret = module.createUnary(UnaryOp.ReinterpretI32, arg0); break; case TypeKind.F64: - if (typeArguments) { - if (!(typeArguments[1].is(TypeFlags.LONG | TypeFlags.INTEGER) && !typeArguments[1].isReference)) { - compiler.error(DiagnosticCode.Type_0_cannot_be_reinterpreted_as_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString()); - return module.createUnreachable(); - } - compiler.currentType = typeArguments[1]; - } else - compiler.currentType = Type.i64; - ret = module.createUnary(UnaryOp.ReinterpretF64, arg0); + arg0 = compiler.compileExpression(operands[0], Type.u64); + ret = module.createUnary(UnaryOp.ReinterpretI64, arg0); break; default: // small integers and void @@ -1255,6 +1234,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty ret = module.createUnreachable(); break; } + compiler.currentType = typeArguments[0]; return ret; case "sqrt": // sqrt(value: T) -> T diff --git a/std/assembly.d.ts b/std/assembly.d.ts index d5cb7a2e..0dbd48de 100644 --- a/std/assembly.d.ts +++ b/std/assembly.d.ts @@ -146,8 +146,8 @@ declare function copysign(x: T, y: T): T; declare function floor(value: T): T; /** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */ declare function nearest(value: T): T; -/** Reinterprets the bits of a value of type `T1` as type `T2`. Valid reinterpretations are i32 to/from f32 and i64 to/from f64. */ -declare function reinterpret(value: T1): T2; +/** Reinterprets the bits of the specified value as type `T`. Valid reinterpretations are u32/i32 to/from f32 and u64/i64 to/from f64. */ +declare function reinterpret(value: number): T; /** Selects one of two pre-evaluated values depending on the condition. */ declare function select(ifTrue: T, ifFalse: T, condition: bool): T; /** Calculates the square root of a 32-bit or 64-bit float. */ diff --git a/tests/compiler/builtins.ts b/tests/compiler/builtins.ts index 059ff5cc..23db9ced 100644 --- a/tests/compiler/builtins.ts +++ b/tests/compiler/builtins.ts @@ -117,15 +117,15 @@ store(8, load(8)); // reinterpretation -reinterpret(1.25); -reinterpret(25); -reinterpret(1.25); -reinterpret(25); +reinterpret(1.25); +reinterpret(25); +reinterpret(1.25); +reinterpret(25); -i = reinterpret(1.25); -f = reinterpret(25); -I = reinterpret(1.25); -F = reinterpret(25); +i = reinterpret(1.25); +f = reinterpret(25); +I = reinterpret(1.25); +F = reinterpret(25); // host diff --git a/tests/compiler/fmod.ts b/tests/compiler/fmod.ts index 76358eba..6fd0848a 100644 --- a/tests/compiler/fmod.ts +++ b/tests/compiler/fmod.ts @@ -1,7 +1,7 @@ export function fmod(x: f64, y: f64): f64 { // the following is based on musl's implementation of fmod - var ux = reinterpret(x); - var uy = reinterpret(y); + var ux = reinterpret(x); + var uy = reinterpret(y); var ex = (ux >> 52 & 0x7ff); var ey = (uy >> 52 & 0x7ff); var sx = (ux >> 63); @@ -59,7 +59,7 @@ export function fmod(x: f64, y: f64): f64 { ux >>= -ex + 1; } ux |= sx << 63; - return reinterpret(ux); + return reinterpret(ux); } assert(isNaN(fmod(1, NaN))); @@ -69,8 +69,8 @@ assert(fmod(9.2, 3.7) - 1.8 < f64.EPSILON); // not exactly 1.8 (as in C) export function fmodf(x: f32, y: f32): f32 { // the following is based on musl's implementation of fmodf - var ux = reinterpret(x); - var uy = reinterpret(y); + var ux = reinterpret(x); + var uy = reinterpret(y); var ex = (ux >> 23 & 0xff); var ey = (uy >> 23 & 0xff); var sx = ux & 0x80000000; @@ -128,7 +128,7 @@ export function fmodf(x: f32, y: f32): f32 { ux >>= -ex + 1; } ux |= sx; - return reinterpret(ux); + return reinterpret(ux); } assert(isNaN(fmodf(1, NaN)));