1 // Written in the D programming language.
4 This is a submodule of $(MREF std, math).
6 It contains hardware support for floating point numbers.
8 Copyright: Copyright The D Language Foundation 2000 - 2011.
9 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
10 Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston,
11 Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger
12 Source: $(PHOBOSSRC std/math/hardware.d)
15 /* NOTE: This file has been patched from the original DMD distribution to
16 * work with the GDC compiler.
18 module std
.math
.hardware
;
20 static import core
.stdc
.fenv
;
22 version (X86
) version = X86_Any
;
23 version (X86_64
) version = X86_Any
;
24 version (PPC
) version = PPC_Any
;
25 version (PPC64
) version = PPC_Any
;
26 version (MIPS32
) version = MIPS_Any
;
27 version (MIPS64
) version = MIPS_Any
;
28 version (AArch64
) version = ARM_Any
;
29 version (ARM
) version = ARM_Any
;
30 version (S390
) version = IBMZ_Any
;
31 version (SPARC
) version = SPARC_Any
;
32 version (SPARC64
) version = SPARC_Any
;
33 version (SystemZ
) version = IBMZ_Any
;
34 version (RISCV32
) version = RISCV_Any
;
35 version (RISCV64
) version = RISCV_Any
;
36 version (LoongArch64
) version = LoongArch_Any
;
38 version (D_InlineAsm_X86
) version = InlineAsm_X86_Any
;
39 version (D_InlineAsm_X86_64
) version = InlineAsm_X86_Any
;
41 version (X86_64
) version = StaticallyHaveSSE
;
42 version (X86
) version (OSX
) version = StaticallyHaveSSE
;
44 version (StaticallyHaveSSE
)
46 private enum bool haveSSE
= true;
50 static import core
.cpuid;
51 private alias haveSSE
= core
.cpuid.sse
;
56 // Some soft float implementations may support IEEE floating flags.
57 // The implementation here supports hardware flags only and is so currently
58 // only available for supported targets.
60 else version (X86_Any
) version = IeeeFlagsSupport
;
61 else version (PPC_Any
) version = IeeeFlagsSupport
;
62 else version (RISCV_Any
) version = IeeeFlagsSupport
;
63 else version (MIPS_Any
) version = IeeeFlagsSupport
;
64 else version (LoongArch_Any
) version = IeeeFlagsSupport
;
65 else version (ARM_Any
) version = IeeeFlagsSupport
;
67 // Struct FloatingPointControl is only available if hardware FP units are available.
70 // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport
71 version (IeeeFlagsSupport
) version = FloatingPointControlSupport
;
74 version (IeeeFlagsSupport
)
77 /** IEEE exception status flags ('sticky bits')
79 These flags indicate that an exceptional floating-point condition has occurred.
80 They indicate that a NaN or an infinity has been generated, that a result
81 is inexact, or that a signalling NaN has been encountered. If floating-point
82 exceptions are enabled (unmasked), a hardware exception will be generated
83 instead of setting these flags.
90 // The x87 FPU status register is 16 bits.
91 // The Pentium SSE2 status register is 32 bits.
92 // The ARM and PowerPC FPSCR is a 32-bit register.
93 // The SPARC FSR is a 32bit register (64 bits for SPARC 7 & 8, but high bits are uninteresting).
94 // The RISC-V (32 & 64 bit) fcsr is 32-bit register.
95 // THe LoongArch fcsr (fcsr0) is a 32-bit register.
98 version (CRuntime_Microsoft
)
100 // Microsoft uses hardware-incompatible custom constants in fenv.h (core.stdc.fenv).
101 // Applies to both x87 status word (16 bits) and SSE2 status word(32 bits).
105 UNDERFLOW_MASK
= 0x10,
106 OVERFLOW_MASK
= 0x08,
107 DIVBYZERO_MASK
= 0x04,
110 EXCEPTIONS_MASK
= 0b11_1111
112 // Don't bother about subnormals, they are not supported on most CPUs.
113 // SUBNORMAL_MASK = 0x02;
119 INEXACT_MASK
= core
.stdc
.fenv
.FE_INEXACT
,
120 UNDERFLOW_MASK
= core
.stdc
.fenv
.FE_UNDERFLOW
,
121 OVERFLOW_MASK
= core
.stdc
.fenv
.FE_OVERFLOW
,
122 DIVBYZERO_MASK
= core
.stdc
.fenv
.FE_DIVBYZERO
,
123 INVALID_MASK
= core
.stdc
.fenv
.FE_INVALID
,
124 EXCEPTIONS_MASK
= core
.stdc
.fenv
.FE_ALL_EXCEPT
,
128 static uint getIeeeFlags() @trusted pure
135 asm pure nothrow @nogc
137 "fstsw %0" : "=a" (sw
);
139 // OR the result with the SSE2 status register (MXCSR).
143 asm pure nothrow @nogc
145 "stmxcsr %0" : "=m" (mxcsr
);
147 return (sw | mxcsr
) & EXCEPTIONS_MASK
;
150 return sw
& EXCEPTIONS_MASK
;
154 version (ARM_SoftFloat
)
159 asm pure nothrow @nogc
161 "vmrs %0, FPSCR; and %0, %0, #0x1F;" : "=r" (result
);
166 else version (RISCV_Any
)
168 version (D_SoftFloat
)
173 asm pure nothrow @nogc
175 "frflags %0" : "=r" (result
);
181 assert(0, "Not yet supported");
184 version (InlineAsm_X86_Any
)
187 asm pure nothrow @nogc { fstsw sw
; }
189 // OR the result with the SSE2 status register (MXCSR).
193 asm pure nothrow @nogc { stmxcsr mxcsr
; }
194 return (sw | mxcsr
) & EXCEPTIONS_MASK
;
196 else return sw
& EXCEPTIONS_MASK
;
202 asm pure nothrow @nogc { st %fsr, retval; }
205 assert(0, "Not yet supported");
209 assert(false, "Not yet supported.");
211 else version (RISCV_Any
)
215 asm pure nothrow @nogc
217 "frflags %0" : "=r" (result);
222 else version (LoongArch_Any
)
225 asm pure nothrow @nogc
227 "movfcsr2gr %0,$r2" : "=r" (result
);
229 return result
& EXCEPTIONS_MASK
;
232 assert(0, "Not yet supported");
235 static void resetIeeeFlags() @trusted
246 // Also clear exception flags in MXCSR, SSE's control register.
252 "stmxcsr %0" : "=m" (mxcsr
);
254 mxcsr
&= ~EXCEPTIONS_MASK
;
257 "ldmxcsr %0" : : "m" (mxcsr
);
263 version (ARM_SoftFloat
)
267 uint old
= FloatingPointControl
.getControlState();
268 old
&= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html
271 "vmsr FPSCR, %0" : : "r" (old
);
275 else version (RISCV_Any
)
277 version (D_SoftFloat
)
281 uint newValues
= 0x0;
284 "fsflags %0" : : "r" (newValues
);
289 assert(0, "Not yet supported");
292 version (InlineAsm_X86_Any
)
299 // Also clear exception flags in MXCSR, SSE's control register.
303 asm nothrow @nogc { stmxcsr mxcsr
; }
304 mxcsr
&= ~EXCEPTIONS_MASK
;
305 asm nothrow @nogc { ldmxcsr mxcsr
; }
308 else version (RISCV_Any
)
311 uint newValues = 0x0;
312 asm pure nothrow @nogc
314 "fsflags %0" : : "r" (newValues);
318 else version (LoongArch_Any
)
322 "movgr2fcsr $r2,$r0";
329 asm pure nothrow @nogc { st %fsr, tmpval; }
330 tmpval &=0xFFFF_FC00;
331 asm pure nothrow @nogc { ld tmpval, %fsr; }
333 assert(0, "Not yet supported");
339 * The result cannot be represented exactly, so rounding occurred.
340 * Example: `x = sin(0.1);`
342 @property bool inexact() @safe const { return (flags
& INEXACT_MASK
) != 0; }
345 * A zero was generated by underflow
346 * Example: `x = real.min*real.epsilon/2;`
348 @property bool underflow() @safe const { return (flags
& UNDERFLOW_MASK
) != 0; }
351 * An infinity was generated by overflow
352 * Example: `x = real.max*2;`
354 @property bool overflow() @safe const { return (flags
& OVERFLOW_MASK
) != 0; }
357 * An infinity was generated by division by zero
358 * Example: `x = 3/0.0;`
360 @property bool divByZero() @safe const { return (flags
& DIVBYZERO_MASK
) != 0; }
363 * A machine NaN was generated.
364 * Example: `x = real.infinity * 0.0;`
366 @property bool invalid() @safe const { return (flags
& INVALID_MASK
) != 0; }
373 import std
.math
.traits
: isNaN
;
379 // Set all the flags to zero
381 assert(!ieeeFlags
.divByZero
);
382 // Perform a division by zero.
384 assert(a
== real.infinity
);
385 assert(ieeeFlags
.divByZero
);
388 assert(ieeeFlags
.invalid
);
391 // Check that calling func() has no effect on the
393 IeeeFlags f
= ieeeFlags
;
395 assert(ieeeFlags
== f
);
400 import std
.math
.traits
: isNaN
;
406 // Set all the flags to zero
408 assert(!ieeeFlags
.divByZero
);
409 // Perform a division by zero.
410 a
= forceDivOp(a
, 0.0L);
411 assert(a
== real.infinity
);
412 assert(ieeeFlags
.divByZero
);
414 a
= forceMulOp(a
, 0.0L);
415 assert(ieeeFlags
.invalid
);
418 // Check that calling func() has no effect on the
420 IeeeFlags f
= ieeeFlags
;
422 assert(ieeeFlags
== f
);
427 import std
.meta
: AliasSeq
;
431 void delegate() @trusted action
;
432 bool function() @trusted ieeeCheck
;
435 static foreach (T
; AliasSeq
!(float, double, real))
437 T x
; // Needs to be here to avoid `call without side effects` warning.
440 () { x
= forceAddOp
!T(1, 0.1L); },
441 () => ieeeFlags
.inexact
444 () { x
= forceDivOp
!T(T
.min_normal
, T
.max
); },
445 () => ieeeFlags
.underflow
448 () { x
= forceAddOp
!T(T
.max
, T
.max
); },
449 () => ieeeFlags
.overflow
452 () { x
= forceDivOp
!T(1, 0); },
453 () => ieeeFlags
.divByZero
456 () { x
= forceDivOp
!T(0, 0); },
457 () => ieeeFlags
.invalid
460 foreach (test; tests
)
463 assert(!test.ieeeCheck());
465 assert(test.ieeeCheck());
470 /// Set all of the floating-point status flags to false.
471 void resetIeeeFlags() @trusted nothrow @nogc
473 IeeeFlags
.resetIeeeFlags();
483 assert(a
== real.infinity
);
484 assert(ieeeFlags
.divByZero
);
487 assert(!ieeeFlags
.divByZero
);
494 a
= forceDivOp(a
, 0.0L);
495 assert(a
== real.infinity
);
496 assert(ieeeFlags
.divByZero
);
499 assert(!ieeeFlags
.divByZero
);
502 /// Returns: snapshot of the current state of the floating-point status flags
503 @property IeeeFlags
ieeeFlags() @trusted pure nothrow @nogc
505 return IeeeFlags(IeeeFlags
.getIeeeFlags());
510 @safe nothrow unittest
512 import std
.math
.traits
: isNaN
;
518 assert(a
== real.infinity
);
519 assert(ieeeFlags
.divByZero
);
523 assert(ieeeFlags
.invalid
);
526 @safe nothrow unittest
528 import std
.math
.traits
: isNaN
;
533 a
= forceDivOp(a
, 0.0L);
534 assert(a
== real.infinity
);
535 assert(ieeeFlags
.divByZero
);
537 a
= forceMulOp(a
, 0.0L);
539 assert(ieeeFlags
.invalid
);
542 } // IeeeFlagsSupport
545 version (FloatingPointControlSupport
)
548 /** Control the Floating point hardware
550 Change the IEEE754 floating-point rounding mode and the floating-point
553 By default, the rounding mode is roundToNearest and all hardware exceptions
554 are disabled. For most applications, debugging is easier if the $(I division
555 by zero), $(I overflow), and $(I invalid operation) exceptions are enabled.
556 These three are combined into a $(I severeExceptions) value for convenience.
557 Note in particular that if $(I invalidException) is enabled, a hardware trap
558 will be generated whenever an uninitialized floating-point variable is used.
560 All changes are temporary. The previous state is restored at the
567 FloatingPointControl fpctrl;
569 // Enable hardware exceptions for division by zero, overflow to infinity,
570 // invalid operations, and uninitialized floating-point variables.
571 fpctrl.enableExceptions(FloatingPointControl.severeExceptions);
573 // This will generate a hardware exception, if x is a
574 // default-initialized floating point variable:
575 real x; // Add `= 0` or even `= real.nan` to not throw the exception.
578 // The exception is only thrown for default-uninitialized NaN-s.
579 // NaN-s with other payload are valid:
580 real z = y * real.nan; // ok
582 // The set hardware exceptions and rounding modes will be disabled when
583 // leaving this scope.
588 struct FloatingPointControl
592 alias RoundingMode
= uint; ///
598 /** IEEE rounding modes.
599 * The default mode is roundToNearest.
601 * roundingMask = A mask of all rounding modes.
606 roundToZero
, /// ditto
607 roundingMask
, /// ditto
610 else version (CRuntime_Microsoft
)
612 // Microsoft uses hardware-incompatible custom constants in fenv.h (core.stdc.fenv).
615 roundToNearest
= 0x0000,
618 roundToZero
= 0x0C00,
619 roundingMask
= roundToNearest | roundDown
620 | roundUp | roundToZero
,
627 roundToNearest
= core
.stdc
.fenv
.FE_TONEAREST
,
628 roundDown
= core
.stdc
.fenv
.FE_DOWNWARD
,
629 roundUp
= core
.stdc
.fenv
.FE_UPWARD
,
630 roundToZero
= core
.stdc
.fenv
.FE_TOWARDZERO
,
631 roundingMask
= roundToNearest | roundDown
632 | roundUp | roundToZero
,
637 * Change the floating-point hardware rounding mode
639 * Changing the rounding mode in the middle of a function can interfere
640 * with optimizations of floating point expressions, as the optimizer assumes
641 * that the rounding mode does not change.
642 * It is best to change the rounding mode only at the
643 * beginning of the function, and keep it until the function returns.
644 * It is also best to add the line:
646 * pragma(inline, false);
648 * as the first line of the function so it will not get inlined.
650 * newMode = the new rounding mode
652 @property void rounding(RoundingMode newMode
) @trusted
655 setControlState((getControlState() & (-1 - roundingMask
)) |
(newMode
& roundingMask
));
658 /// Returns: the currently active rounding mode
659 @property static RoundingMode
rounding() @trusted pure
661 return cast(RoundingMode
)(getControlState() & roundingMask
);
664 alias ExceptionMask
= uint; ///
670 /** IEEE hardware exceptions.
671 * By default, all exceptions are masked (disabled).
673 * severeExceptions = The overflow, division by zero, and invalid
677 inexactException
, /// ditto
678 underflowException
, /// ditto
679 overflowException
, /// ditto
680 divByZeroException
, /// ditto
681 invalidException
, /// ditto
682 severeExceptions
, /// ditto
683 allExceptions
, /// ditto
686 else version (ARM_Any
)
690 subnormalException
= 0x8000,
691 inexactException
= 0x1000,
692 underflowException
= 0x0800,
693 overflowException
= 0x0400,
694 divByZeroException
= 0x0200,
695 invalidException
= 0x0100,
696 severeExceptions
= overflowException | divByZeroException
698 allExceptions
= severeExceptions | underflowException
699 | inexactException | subnormalException
,
702 else version (PPC_Any
)
706 inexactException
= 0x0008,
707 divByZeroException
= 0x0010,
708 underflowException
= 0x0020,
709 overflowException
= 0x0040,
710 invalidException
= 0x0080,
711 severeExceptions
= overflowException | divByZeroException
713 allExceptions
= severeExceptions | underflowException
717 else version (RISCV_Any
)
721 inexactException
= 0x01,
722 divByZeroException
= 0x08,
723 underflowException
= 0x02,
724 overflowException
= 0x04,
725 invalidException
= 0x10,
726 severeExceptions
= overflowException | divByZeroException
728 allExceptions
= severeExceptions | underflowException
736 inexactException
= 0x01,
737 underflowException
= 0x02,
738 overflowException
= 0x04,
739 divByZeroException
= 0x08,
740 invalidException
= 0x10,
741 severeExceptions
= overflowException | divByZeroException
743 allExceptions
= severeExceptions | underflowException
747 else version (LoongArch_Any
)
751 inexactException
= 0x00,
752 divByZeroException
= 0x01,
753 overflowException
= 0x02,
754 underflowException
= 0x04,
755 invalidException
= 0x08,
756 severeExceptions
= overflowException | divByZeroException
758 allExceptions
= severeExceptions | underflowException
762 else version (MIPS_Any
)
766 inexactException
= 0x0080,
767 divByZeroException
= 0x0400,
768 overflowException
= 0x0200,
769 underflowException
= 0x0100,
770 invalidException
= 0x0800,
771 severeExceptions
= overflowException | divByZeroException
773 allExceptions
= severeExceptions | underflowException
777 else version (SPARC_Any
)
781 inexactException
= 0x0800000,
782 divByZeroException
= 0x1000000,
783 overflowException
= 0x4000000,
784 underflowException
= 0x2000000,
785 invalidException
= 0x8000000,
786 severeExceptions
= overflowException | divByZeroException
788 allExceptions
= severeExceptions | underflowException
792 else version (IBMZ_Any
)
796 inexactException
= 0x08000000,
797 divByZeroException
= 0x40000000,
798 overflowException
= 0x20000000,
799 underflowException
= 0x10000000,
800 invalidException
= 0x80000000,
801 severeExceptions
= overflowException | divByZeroException
803 allExceptions
= severeExceptions | underflowException
807 else version (X86_Any
)
811 inexactException
= 0x20,
812 underflowException
= 0x10,
813 overflowException
= 0x08,
814 divByZeroException
= 0x04,
815 subnormalException
= 0x02,
816 invalidException
= 0x01,
817 severeExceptions
= overflowException | divByZeroException
819 allExceptions
= severeExceptions | underflowException
820 | inexactException | subnormalException
,
824 static assert(false, "Not implemented for this architecture");
828 static bool hasExceptionTraps_impl() @safe
830 auto oldState
= getControlState();
831 // If exceptions are not supported, we set the bit but read it back as zero
832 // https://sourceware.org/ml/libc-ports/2012-06/msg00091.html
833 setControlState(oldState | divByZeroException
);
834 immutable result
= (getControlState() & allExceptions
) != 0;
835 setControlState(oldState
);
840 /// Returns: true if the current FPU supports exception trapping
841 @property static bool hasExceptionTraps() @safe pure
845 else version (PPC_Any
)
847 else version (MIPS_Any
)
849 else version (LoongArch_Any
)
851 else version (ARM_Any
)
853 // The hasExceptionTraps_impl function is basically pure,
854 // as it restores all global state
855 auto fptr
= ( () @trusted => cast(bool function() @safe
856 pure nothrow @nogc)&hasExceptionTraps_impl
)();
860 assert(0, "Not yet supported");
863 /// Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together.
864 void enableExceptions(ExceptionMask exceptions
) @trusted
866 assert(hasExceptionTraps
);
869 setControlState(getControlState() & ~(exceptions
& allExceptions
));
871 setControlState(getControlState() |
(exceptions
& allExceptions
));
874 /// Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together.
875 void disableExceptions(ExceptionMask exceptions
) @trusted
877 assert(hasExceptionTraps
);
880 setControlState(getControlState() |
(exceptions
& allExceptions
));
882 setControlState(getControlState() & ~(exceptions
& allExceptions
));
885 /// Returns: the exceptions which are currently enabled (unmasked)
886 @property static ExceptionMask
enabledExceptions() @trusted pure
888 assert(hasExceptionTraps
);
890 return (getControlState() & allExceptions
) ^ allExceptions
;
892 return (getControlState() & allExceptions
);
895 /// Clear all pending exceptions, then restore the original exception state and rounding mode.
900 setControlState(savedState
);
904 ControlState savedState
;
906 bool initialized
= false;
910 alias ControlState
= uint;
914 alias ControlState
= uint;
916 else version (PPC_Any
)
918 alias ControlState
= uint;
920 else version (RISCV_Any
)
922 alias ControlState
= uint;
924 else version (LoongArch_Any
)
926 alias ControlState
= uint;
928 else version (MIPS_Any
)
930 alias ControlState
= uint;
932 else version (SPARC_Any
)
934 alias ControlState
= ulong;
936 else version (IBMZ_Any
)
938 alias ControlState
= uint;
940 else version (X86_Any
)
942 alias ControlState
= ushort;
945 static assert(false, "Not implemented for this architecture");
947 void initialize() @safe
949 // BUG: This works around the absence of this() constructors.
950 if (initialized
) return;
952 savedState
= getControlState();
956 // Clear all pending exceptions
957 static void clearExceptions() @safe
959 version (IeeeFlagsSupport
)
962 static assert(false, "Not implemented for this architecture");
965 // Read from the control register
966 package(std
.math
) static ControlState
getControlState() @trusted pure
973 asm pure nothrow @nogc
975 "fstcw %0" : "=m" (cont
);
979 else version (AArch64
)
982 asm pure nothrow @nogc
984 "mrs %0, FPCR;" : "=r" (cont
);
991 version (ARM_SoftFloat
)
995 asm pure nothrow @nogc
997 "vmrs %0, FPSCR" : "=r" (cont
);
1002 else version (RISCV_Any
)
1004 version (D_SoftFloat
)
1009 asm pure nothrow @nogc
1011 "frcsr %0" : "=r" (cont
);
1017 assert(0, "Not yet supported");
1020 version (D_InlineAsm_X86
)
1023 asm pure nothrow @nogc
1030 else version (D_InlineAsm_X86_64
)
1033 asm pure nothrow @nogc
1040 else version (RISCV_Any
)
1044 asm pure nothrow @nogc
1046 "frcsr %0" : "=r" (cont);
1051 else version (LoongArch_Any
)
1054 asm pure nothrow @nogc
1056 "movfcsr2gr %0,$r0" : "=r" (cont
);
1058 cont
&= (roundingMask | allExceptions
);
1062 assert(0, "Not yet supported");
1065 // Set the control register
1066 package(std
.math
) static void setControlState(ControlState newState
) @trusted
1074 "fclex; fldcw %0" : : "m" (newState
);
1077 // Also update MXCSR, SSE's control register.
1083 "stmxcsr %0" : "=m" (mxcsr
);
1086 /* In the FPU control register, rounding mode is in bits 10 and
1087 11. In MXCSR it's in bits 13 and 14. */
1088 mxcsr
&= ~(roundingMask
<< 3); // delete old rounding mode
1089 mxcsr |
= (newState
& roundingMask
) << 3; // write new rounding mode
1091 /* In the FPU control register, masks are bits 0 through 5.
1092 In MXCSR they're 7 through 12. */
1093 mxcsr
&= ~(allExceptions
<< 7); // delete old masks
1094 mxcsr |
= (newState
& allExceptions
) << 7; // write new exception masks
1098 "ldmxcsr %0" : : "m" (mxcsr
);
1102 else version (AArch64
)
1106 "msr FPCR, %0;" : : "r" (newState
);
1111 version (ARM_SoftFloat
)
1117 "vmsr FPSCR, %0" : : "r" (newState
);
1121 else version (RISCV_Any
)
1123 version (D_SoftFloat
)
1129 "fscsr %0" : : "r" (newState
);
1134 assert(0, "Not yet supported");
1137 version (InlineAsm_X86_Any
)
1145 // Also update MXCSR, SSE's control register.
1149 asm nothrow @nogc { stmxcsr mxcsr
; }
1151 /* In the FPU control register, rounding mode is in bits 10 and
1152 11. In MXCSR it's in bits 13 and 14. */
1153 mxcsr
&= ~(roundingMask
<< 3); // delete old rounding mode
1154 mxcsr |
= (newState
& roundingMask
) << 3; // write new rounding mode
1156 /* In the FPU control register, masks are bits 0 through 5.
1157 In MXCSR they're 7 through 12. */
1158 mxcsr
&= ~(allExceptions
<< 7); // delete old masks
1159 mxcsr |
= (newState
& allExceptions
) << 7; // write new exception masks
1161 asm nothrow @nogc { ldmxcsr mxcsr
; }
1164 else version (RISCV_Any
)
1167 asm pure nothrow @nogc
1169 "fscsr %0" : : "r" (newState);
1173 else version (LoongArch_Any
)
1177 "movgr2fcsr $r0,%0" :
1178 : "r" (newState
& (roundingMask | allExceptions
));
1182 assert(0, "Not yet supported");
1189 import std
.math
.rounding
: lrint
;
1191 FloatingPointControl fpctrl
;
1193 fpctrl
.rounding
= FloatingPointControl
.roundDown
;
1194 assert(lrint(1.5) == 1.0);
1196 fpctrl
.rounding
= FloatingPointControl
.roundUp
;
1197 assert(lrint(1.4) == 2.0);
1199 fpctrl
.rounding
= FloatingPointControl
.roundToNearest
;
1200 assert(lrint(1.5) == 2.0);
1205 void ensureDefaults()
1207 assert(FloatingPointControl
.rounding
1208 == FloatingPointControl
.roundToNearest
);
1209 if (FloatingPointControl
.hasExceptionTraps
)
1210 assert(FloatingPointControl
.enabledExceptions
== 0);
1214 FloatingPointControl ctrl
;
1219 FloatingPointControl ctrl
;
1220 ctrl
.rounding
= FloatingPointControl
.roundDown
;
1221 assert(FloatingPointControl
.rounding
== FloatingPointControl
.roundDown
);
1225 if (FloatingPointControl
.hasExceptionTraps
)
1227 FloatingPointControl ctrl
;
1228 ctrl
.enableExceptions(FloatingPointControl
.divByZeroException
1229 | FloatingPointControl
.overflowException
);
1230 assert(ctrl
.enabledExceptions
==
1231 (FloatingPointControl
.divByZeroException
1232 | FloatingPointControl
.overflowException
));
1234 ctrl
.rounding
= FloatingPointControl
.roundUp
;
1235 assert(FloatingPointControl
.rounding
== FloatingPointControl
.roundUp
);
1240 @safe unittest // rounding
1242 import std
.meta
: AliasSeq
;
1244 static T
addRound(T
)(uint rm
)
1246 pragma(inline
, false);
1247 FloatingPointControl fpctrl
;
1248 fpctrl
.rounding
= rm
;
1250 x
= forceAddOp(x
, 0.1L);
1254 static T
subRound(T
)(uint rm
)
1256 pragma(inline
, false);
1257 FloatingPointControl fpctrl
;
1258 fpctrl
.rounding
= rm
;
1260 x
= forceSubOp(x
, 0.1L);
1264 static foreach (T
; AliasSeq
!(float, double, real))
1266 /* Be careful with changing the rounding mode, it interferes
1267 * with common subexpressions. Changing rounding modes should
1268 * be done with separate functions that are not inlined.
1272 T u
= addRound
!(T
)(FloatingPointControl
.roundUp
);
1273 T d
= addRound
!(T
)(FloatingPointControl
.roundDown
);
1274 T z
= addRound
!(T
)(FloatingPointControl
.roundToZero
);
1281 T u
= subRound
!(T
)(FloatingPointControl
.roundUp
);
1282 T d
= subRound
!(T
)(FloatingPointControl
.roundDown
);
1283 T z
= subRound
!(T
)(FloatingPointControl
.roundToZero
);
1291 } // FloatingPointControlSupport
1293 version (StdUnittest
)
1295 // These helpers are intended to avoid constant propagation by the optimizer.
1296 pragma(inline
, false) private @safe
1298 T
forceAddOp(T
)(T x
, T y
) { return x
+ y
; }
1299 T
forceSubOp(T
)(T x
, T y
) { return x
- y
; }
1300 T
forceMulOp(T
)(T x
, T y
) { return x
* y
; }
1301 T
forceDivOp(T
)(T x
, T y
) { return x
/ y
; }