Simplify reinterpret to require one type argument only, fixes #9

This commit is contained in:
dcodeIO 2018-01-13 01:15:09 +01:00
parent 2df318a7ec
commit dd596b015d
4 changed files with 49 additions and 69 deletions

View File

@ -1176,78 +1176,57 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
} }
return ret; return ret;
case "reinterpret": // reinterpret<T1?,T2?>(value: T1) -> T2 case "reinterpret": // reinterpret<T!>(value: *) -> T
if (operands.length != 1) { if (operands.length != 1) {
if (typeArguments) { if (!(typeArguments && typeArguments.length == 1)) {
if (typeArguments.length >= 2) if (typeArguments && typeArguments.length)
compiler.currentType = typeArguments[1]; compiler.currentType = typeArguments[0];
if (typeArguments.length != 2) compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0");
compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "2", typeArguments.length.toString(10));
} }
compiler.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, "1", operands.length.toString(10)); compiler.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, "1", operands.length.toString(10));
return module.createUnreachable(); return module.createUnreachable();
} }
if (typeArguments) { if (!(typeArguments && typeArguments.length == 1)) {
if (typeArguments.length != 2) { if (typeArguments && typeArguments.length)
if (typeArguments.length >= 2) compiler.currentType = typeArguments[0];
compiler.currentType = typeArguments[1]; compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0");
compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "2", typeArguments.length.toString(10)); return module.createUnreachable();
return module.createUnreachable(); }
}
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
} else
arg0 = compiler.compileExpression(operands[0], Type.f64, ConversionKind.NONE);
switch (compiler.currentType.kind) { switch (typeArguments[0].kind) {
case TypeKind.I32: case TypeKind.I32:
case TypeKind.U32: case TypeKind.U32:
if (typeArguments) { arg0 = compiler.compileExpression(operands[0], Type.f32);
if (typeArguments[1].kind != TypeKind.F32) { ret = module.createUnary(UnaryOp.ReinterpretF32, arg0);
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);
break; break;
case TypeKind.I64: case TypeKind.I64:
case TypeKind.U64: case TypeKind.U64:
if (typeArguments) { arg0 = compiler.compileExpression(operands[0], Type.f64);
if (typeArguments[1].kind != TypeKind.F64) { ret = module.createUnary(UnaryOp.ReinterpretF64, arg0);
compiler.error(DiagnosticCode.Type_0_cannot_be_reinterpreted_as_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString()); break;
return module.createUnreachable();
} case TypeKind.USIZE:
compiler.currentType = typeArguments[1]; if (typeArguments[0].isReference) {
} else compiler.error(DiagnosticCode.Operation_not_supported, reportNode.range);
compiler.currentType = Type.f64; compiler.currentType = typeArguments[0];
ret = module.createUnary(UnaryOp.ReinterpretI64, arg0); 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; break;
case TypeKind.F32: case TypeKind.F32:
if (typeArguments) { arg0 = compiler.compileExpression(operands[0], Type.u32);
if (!(typeArguments[1].is(TypeFlags.INTEGER) && typeArguments[1].size == 32)) { ret = module.createUnary(UnaryOp.ReinterpretI32, arg0);
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);
break; break;
case TypeKind.F64: case TypeKind.F64:
if (typeArguments) { arg0 = compiler.compileExpression(operands[0], Type.u64);
if (!(typeArguments[1].is(TypeFlags.LONG | TypeFlags.INTEGER) && !typeArguments[1].isReference)) { ret = module.createUnary(UnaryOp.ReinterpretI64, arg0);
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);
break; break;
default: // small integers and void default: // small integers and void
@ -1255,6 +1234,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
ret = module.createUnreachable(); ret = module.createUnreachable();
break; break;
} }
compiler.currentType = typeArguments[0];
return ret; return ret;
case "sqrt": // sqrt<T?>(value: T) -> T case "sqrt": // sqrt<T?>(value: T) -> T

4
std/assembly.d.ts vendored
View File

@ -146,8 +146,8 @@ declare function copysign<T = f32 | f64>(x: T, y: T): T;
declare function floor<T = f32 | f64>(value: 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. */ /** 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; 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. */ /** 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<T1 = i32 | i64 | f32 | f64, T2 = i32 | i64 | f32 | f64>(value: T1): T2; declare function reinterpret<T = i32 | i64 | f32 | f64>(value: number): T;
/** Selects one of two pre-evaluated values depending on the condition. */ /** Selects one of two pre-evaluated values depending on the condition. */
declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T; declare function select<T>(ifTrue: T, ifFalse: T, condition: bool): T;
/** Calculates the square root of a 32-bit or 64-bit float. */ /** Calculates the square root of a 32-bit or 64-bit float. */

View File

@ -117,15 +117,15 @@ store<f64>(8, load<f64>(8));
// reinterpretation // reinterpretation
reinterpret<f32,i32>(1.25); reinterpret<i32>(1.25);
reinterpret<i32,f32>(25); reinterpret<f32>(25);
reinterpret<f64,i64>(1.25); reinterpret<i64>(1.25);
reinterpret<i64,f64>(25); reinterpret<f64>(25);
i = reinterpret<f32,i32>(1.25); i = reinterpret<i32>(1.25);
f = reinterpret<i32,f32>(25); f = reinterpret<f32>(25);
I = reinterpret<f64,i64>(1.25); I = reinterpret<i64>(1.25);
F = reinterpret<i64,f64>(25); F = reinterpret<f64>(25);
// host // host

View File

@ -1,7 +1,7 @@
export function fmod(x: f64, y: f64): f64 { export function fmod(x: f64, y: f64): f64 {
// the following is based on musl's implementation of fmod // the following is based on musl's implementation of fmod
var ux = reinterpret<f64,u64>(x); var ux = reinterpret<u64>(x);
var uy = reinterpret<f64,u64>(y); var uy = reinterpret<u64>(y);
var ex = <i32>(ux >> 52 & 0x7ff); var ex = <i32>(ux >> 52 & 0x7ff);
var ey = <i32>(uy >> 52 & 0x7ff); var ey = <i32>(uy >> 52 & 0x7ff);
var sx = <i32>(ux >> 63); var sx = <i32>(ux >> 63);
@ -59,7 +59,7 @@ export function fmod(x: f64, y: f64): f64 {
ux >>= -ex + 1; ux >>= -ex + 1;
} }
ux |= <u64>sx << 63; ux |= <u64>sx << 63;
return reinterpret<u64,f64>(ux); return reinterpret<f64>(ux);
} }
assert(isNaN<f64>(fmod(1, NaN))); 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 { export function fmodf(x: f32, y: f32): f32 {
// the following is based on musl's implementation of fmodf // the following is based on musl's implementation of fmodf
var ux = reinterpret<f32,u32>(x); var ux = reinterpret<u32>(x);
var uy = reinterpret<f32,u32>(y); var uy = reinterpret<u32>(y);
var ex = <i32>(ux >> 23 & 0xff); var ex = <i32>(ux >> 23 & 0xff);
var ey = <i32>(uy >> 23 & 0xff); var ey = <i32>(uy >> 23 & 0xff);
var sx = ux & 0x80000000; var sx = ux & 0x80000000;
@ -128,7 +128,7 @@ export function fmodf(x: f32, y: f32): f32 {
ux >>= -ex + 1; ux >>= -ex + 1;
} }
ux |= sx; ux |= sx;
return reinterpret<i32,f32>(ux); return reinterpret<f32>(ux);
} }
assert(isNaN<f32>(fmodf(1, NaN))); assert(isNaN<f32>(fmodf(1, NaN)));