From dd596b015db6e120f309fe23db64992e89848a7c Mon Sep 17 00:00:00 2001
From: dcodeIO <dcode@dcode.io>
Date: Sat, 13 Jan 2018 01:15:09 +0100
Subject: [PATCH] Simplify reinterpret to require one type argument only, fixes
 #9

---
 src/builtins.ts            | 86 +++++++++++++++-----------------------
 std/assembly.d.ts          |  4 +-
 tests/compiler/builtins.ts | 16 +++----
 tests/compiler/fmod.ts     | 12 +++---
 4 files changed, 49 insertions(+), 69 deletions(-)

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<T1?,T2?>(value: T1) -> T2
+    case "reinterpret": // reinterpret<T!>(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<T?>(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<T = f32 | f64>(x: T, y: T): T;
 declare function floor<T = f32 | f64>(value: T): T;
 /** Rounds to the nearest integer tied to even of a 32-bit or 64-bit float. */
 declare function nearest<T = f32 | f64>(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<T1 = i32 | i64 | f32 | f64, T2 = i32 | i64 | f32 | f64>(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<T = i32 | i64 | f32 | f64>(value: number): T;
 /** Selects one of two pre-evaluated values depending on the condition. */
 declare function select<T>(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<f64>(8, load<f64>(8));
 
 // reinterpretation
 
-reinterpret<f32,i32>(1.25);
-reinterpret<i32,f32>(25);
-reinterpret<f64,i64>(1.25);
-reinterpret<i64,f64>(25);
+reinterpret<i32>(1.25);
+reinterpret<f32>(25);
+reinterpret<i64>(1.25);
+reinterpret<f64>(25);
 
-i = reinterpret<f32,i32>(1.25);
-f = reinterpret<i32,f32>(25);
-I = reinterpret<f64,i64>(1.25);
-F = reinterpret<i64,f64>(25);
+i = reinterpret<i32>(1.25);
+f = reinterpret<f32>(25);
+I = reinterpret<i64>(1.25);
+F = reinterpret<f64>(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<f64,u64>(x);
-  var uy = reinterpret<f64,u64>(y);
+  var ux = reinterpret<u64>(x);
+  var uy = reinterpret<u64>(y);
   var ex = <i32>(ux >> 52 & 0x7ff);
   var ey = <i32>(uy >> 52 & 0x7ff);
   var sx = <i32>(ux >> 63);
@@ -59,7 +59,7 @@ export function fmod(x: f64, y: f64): f64 {
     ux >>= -ex + 1;
   }
   ux |= <u64>sx << 63;
-  return reinterpret<u64,f64>(ux);
+  return reinterpret<f64>(ux);
 }
 
 assert(isNaN<f64>(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<f32,u32>(x);
-  var uy = reinterpret<f32,u32>(y);
+  var ux = reinterpret<u32>(x);
+  var uy = reinterpret<u32>(y);
   var ex = <i32>(ux >> 23 & 0xff);
   var ey = <i32>(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<i32,f32>(ux);
+  return reinterpret<f32>(ux);
 }
 
 assert(isNaN<f32>(fmodf(1, NaN)));