shithub: mc

Download patch

ref: 7cd4f442cf238c5de486b54deb0bfd3a3f7a0516
parent: f52ac3cb5ada4ec50019cf8a09c981c040f56e4d
author: Ori Bernstein <ori@eigenstate.org>
date: Sat May 12 21:15:17 EDT 2018

Add float trapping controls.

	This both allows us to error earlier when math goes wonky,
	and allows us to test all our code on 9front.

--- a/lib/math/bld.sub
+++ b/lib/math/bld.sub
@@ -31,6 +31,8 @@
 
 	# util
 	util.myr
+	ftrap.myr
+	ftrap-impl+plan9-x64.s
 
 	lib ../std:std
 ;;
--- /dev/null
+++ b/lib/math/ftrap-impl+plan9-x64.s
@@ -1,0 +1,14 @@
+TEXT	math$fptrap(SB),$0
+	SUBQ	$4,SP
+	WAIT
+	STMXCSR	(SP)
+	MOVL	(SP),AX
+	ANDL	$~0x1f80,AX
+	TESTB	DI,DI
+	JNZ	.apply
+	ORL	$0x1f80,AX
+.apply:
+	MOVL	AX,(SP)
+	LDMXCSR	(SP)
+	ADDQ	$4,SP
+	RET
--- /dev/null
+++ b/lib/math/ftrap-impl+posixy-x64.s
@@ -1,0 +1,17 @@
+.globl _math$fptrap
+.globl math$fptrap
+_math$fptrap:
+math$fptrap
+	subq	$4,%rsp
+	wait
+	stmxcsr	(%rsp)
+	movl	(%rsp),%rax
+	andl	$~0x1f80,%rax
+	testb	%rdi,%rdi
+	jnz	.apply
+	orl	$0x1f80,%rax
+.apply:
+	movl	%rax,(rsp)
+	ldmxcsr	(%rsp)
+	addq	$4,%rsp
+	ret
--- /dev/null
+++ b/lib/math/ftrap.myr
@@ -1,0 +1,3 @@
+pkg math =
+	extern const fptrap	: (f : bool -> void)
+;;
--- a/lib/math/test/exp-impl.myr
+++ b/lib/math/test/exp-impl.myr
@@ -7,6 +7,7 @@
    are tested extensively in expm101 and expm102.
  */
 const main = {
+	math.fptrap(false)
 	testr.run([
 		[.name="exp-01", .fn = exp01],
 		[.name="exp-02", .fn = exp02],
--- a/lib/math/test/fma-impl.myr
+++ b/lib/math/test/fma-impl.myr
@@ -3,6 +3,7 @@
 use testr
 
 const main = {
+	math.fptrap(false)
 	testr.run([
 		[.name="fma-01", .fn = fma01],
 		[.name="fma-02", .fn = fma02],
--- a/lib/math/test/sqrt-impl.myr
+++ b/lib/math/test/sqrt-impl.myr
@@ -3,6 +3,7 @@
 use testr
 
 const main = {
+	math.fptrap(false)
 	testr.run([
 		[.name="sqrt-01", .fn = sqrt01],
 		[.name="sqrt-02", .fn = sqrt02],
--- a/lib/math/test/trunc-impl.myr
+++ b/lib/math/test/trunc-impl.myr
@@ -3,6 +3,7 @@
 use testr
 
 const main = {
+	math.fptrap(false)
 	testr.run([
 		[.name = "trunc-01",    .fn = trunc01],
 		[.name = "trunc-02",    .fn = trunc02],
--- a/lib/std/blat.myr
+++ b/lib/std/blat.myr
@@ -8,8 +8,12 @@
 
 const blat = {path, buf, perm
 	match openmode(path, Ocreat|Owrite, perm)
-	| `Ok fd:	-> fblat(fd, buf)
-	| `Err e:	-> false
+	| `Ok fd:
+		var r = fblat(fd, buf)
+		close(fd)
+		-> r
+	| `Err e:
+		-> false
 	;;
 }
 
--- a/lib/std/test/fltbits.myr
+++ b/lib/std/test/fltbits.myr
@@ -1,18 +1,9 @@
 use std
 use testr
+use math
 
-var testnan
-
 const main = {
-	var si
-
-	/* Floating point mode traps on 9front. */
-	std.getsysinfo(&si)
-	match si.system
-	| "Plan9":	testnan = false
-	| _:		testnan = true
-	;;
-
+	math.fptrap(false)
 	testr.run([
 		[.name = "isnan", .fn = isnan01],
 		[.name = "bits-roundtrip-32", .fn = bitsround32],
@@ -25,26 +16,24 @@
 }
 
 const isnan01 = {c
-	if testnan
-		testr.check(c, std.isnan(std.flt64nan()), "std.flt64nan() should give a NaN")
-		testr.check(c, std.isnan(std.flt32nan()), "std.flt32nan() should give a NaN")
-	
-		/*
-		   a NaN should be {any sign bit}, then {8 or 11 exponent
-		   bits, all 1}, then {any non-zero sequence of 23 or 52
-		   bits}
-		 */
-		testr.check(c, std.isnan(std.flt64frombits(0xfff0000500000000ul)), "0xfff0000500000000 should be a NaN")
-		testr.check(c, std.isnan(std.flt64frombits(0x7ff0000500000000ul)), "0x7ff0000500000000 should be a NaN")
-		testr.check(c, std.isnan(std.flt32frombits(0xff800090)), "0xff800090 should be a NaN")
-		testr.check(c, std.isnan(std.flt32frombits(0x7f800090)), "0x7f800090 should be a NaN")
-	
-		/* if the significand bits are all 0, it's an infinity instead */
-		testr.check(c, !std.isnan(std.flt64frombits(0x7ff0000000000000ul)), "Infinities[1] should not be NaNs")
-		testr.check(c, !std.isnan(std.flt64frombits(0xfff0000000000000ul)), "Infinities[2] should not be NaNs")
-		testr.check(c, !std.isnan(std.flt32frombits(0xff800000)), "Infinities[3] should not be NaNs")
-		testr.check(c, !std.isnan(std.flt32frombits(0x7f800000)), "Infinities[4] should not be NaNs")
-	;;
+	testr.check(c, std.isnan(std.flt64nan()), "std.flt64nan() should give a NaN")
+	testr.check(c, std.isnan(std.flt32nan()), "std.flt32nan() should give a NaN")
+
+	/*
+	   a NaN should be {any sign bit}, then {8 or 11 exponent
+	   bits, all 1}, then {any non-zero sequence of 23 or 52
+	   bits}
+	 */
+	testr.check(c, std.isnan(std.flt64frombits(0xfff0000500000000ul)), "0xfff0000500000000 should be a NaN")
+	testr.check(c, std.isnan(std.flt64frombits(0x7ff0000500000000ul)), "0x7ff0000500000000 should be a NaN")
+	testr.check(c, std.isnan(std.flt32frombits(0xff800090)), "0xff800090 should be a NaN")
+	testr.check(c, std.isnan(std.flt32frombits(0x7f800090)), "0x7f800090 should be a NaN")
+
+	/* if the significand bits are all 0, it's an infinity instead */
+	testr.check(c, !std.isnan(std.flt64frombits(0x7ff0000000000000ul)), "Infinities[1] should not be NaNs")
+	testr.check(c, !std.isnan(std.flt64frombits(0xfff0000000000000ul)), "Infinities[2] should not be NaNs")
+	testr.check(c, !std.isnan(std.flt32frombits(0xff800000)), "Infinities[3] should not be NaNs")
+	testr.check(c, !std.isnan(std.flt32frombits(0x7f800000)), "Infinities[4] should not be NaNs")
 }
 
 const bitsround32 = {c
@@ -58,11 +47,9 @@
 		testr.check(c, u == v, "bits -> flt -> bits non-identity: {} != {}", u, v)
 	;;
 
-	if testnan
-		var nan_f = std.flt32frombits(0xff800090)
-		var nan_g = std.flt32frombits(std.flt32bits(nan_f))
-		testr.check(c, nan_f == nan_g, "flt -> bits -> flt non-identity for nan")
-	;;
+	var nan_f = std.flt32frombits(0xff800090)
+	var nan_g = std.flt32frombits(std.flt32bits(nan_f))
+	testr.check(c, nan_f == nan_g, "flt -> bits -> flt non-identity for nan")
 
 	var inf_f = std.flt32frombits(0x7f800000)
 	var inf_g = std.flt32frombits(std.flt32bits(inf_f))
@@ -80,11 +67,9 @@
 		testr.check(c, u == v, "bits -> flt -> bits non-identity: {} != {}", u, v)
 	;;
 
-	if testnan
-		var nan_f = std.flt64frombits(0x7ff000000000a000ul)
-		var nan_g = std.flt64frombits(std.flt64bits(nan_f))
-		testr.check(c, nan_f == nan_g, "flt -> bits -> flt non-identity for nan")
-	;;
+	var nan_f = std.flt64frombits(0x7ff000000000a000ul)
+	var nan_g = std.flt64frombits(std.flt64bits(nan_f))
+	testr.check(c, nan_f == nan_g, "flt -> bits -> flt non-identity for nan")
 
 	var inf_f = std.flt64frombits(0xfff0000000000000ul)
 	var inf_g = std.flt64frombits(std.flt64bits(inf_f))
@@ -117,7 +102,10 @@
 }
 
 const exploderound32 = {c
-	for f : [1.0, 0.00001, 123.45, 1111111111111111.2, -1.9, -0.0001, 0.000000000000000000000000000000000000006054601, std.flt32nan()][:]
+	var vals
+	vals = [1.0, 0.00001, 123.45, 1111111111111111.2, -1.9, -0.0001, 0.000000000000000000000000000000000000006054601, std.flt32nan()][:]
+
+	for f : vals
 		var n, e, s
 		(n, e, s) = std.flt32explode(f)
 		var g = std.flt32assem(n, e, s)