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
)
214 asm pure nothrow @nogc
216 "frflags %0" : "=r" (result
);
220 else version (LoongArch_Any
)
223 asm pure nothrow @nogc
225 "movfcsr2gr %0, $fcsr2" : "=r" (result
);
227 return result
& EXCEPTIONS_MASK
;
230 assert(0, "Not yet supported");
233 static void resetIeeeFlags() @trusted
244 // Also clear exception flags in MXCSR, SSE's control register.
250 "stmxcsr %0" : "=m" (mxcsr
);
252 mxcsr
&= ~EXCEPTIONS_MASK
;
255 "ldmxcsr %0" : : "m" (mxcsr
);
261 version (ARM_SoftFloat
)
265 uint old
= FloatingPointControl
.getControlState();
266 old
&= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html
269 "vmsr FPSCR, %0" : : "r" (old
);
273 else version (RISCV_Any
)
275 version (D_SoftFloat
)
279 uint newValues
= 0x0;
282 "fsflags %0" : : "r" (newValues
);
287 assert(0, "Not yet supported");
290 version (InlineAsm_X86_Any
)
297 // Also clear exception flags in MXCSR, SSE's control register.
301 asm nothrow @nogc { stmxcsr mxcsr
; }
302 mxcsr
&= ~EXCEPTIONS_MASK
;
303 asm nothrow @nogc { ldmxcsr mxcsr
; }
306 else version (RISCV_Any
)
308 uint newValues
= 0x0;
309 asm pure nothrow @nogc
311 "fsflags %0" : : "r" (newValues
);
314 else version (LoongArch_Any
)
318 "movgr2fcsr $fcsr2,$r0";
325 asm pure nothrow @nogc { st %fsr, tmpval; }
326 tmpval &=0xFFFF_FC00;
327 asm pure nothrow @nogc { ld tmpval, %fsr; }
329 assert(0, "Not yet supported");
335 * The result cannot be represented exactly, so rounding occurred.
336 * Example: `x = sin(0.1);`
338 @property bool inexact() @safe const { return (flags
& INEXACT_MASK
) != 0; }
341 * A zero was generated by underflow
342 * Example: `x = real.min*real.epsilon/2;`
344 @property bool underflow() @safe const { return (flags
& UNDERFLOW_MASK
) != 0; }
347 * An infinity was generated by overflow
348 * Example: `x = real.max*2;`
350 @property bool overflow() @safe const { return (flags
& OVERFLOW_MASK
) != 0; }
353 * An infinity was generated by division by zero
354 * Example: `x = 3/0.0;`
356 @property bool divByZero() @safe const { return (flags
& DIVBYZERO_MASK
) != 0; }
359 * A machine NaN was generated.
360 * Example: `x = real.infinity * 0.0;`
362 @property bool invalid() @safe const { return (flags
& INVALID_MASK
) != 0; }
369 import std
.math
.traits
: isNaN
;
375 // Set all the flags to zero
377 assert(!ieeeFlags
.divByZero
);
378 // Perform a division by zero.
380 assert(a
== real.infinity
);
381 assert(ieeeFlags
.divByZero
);
384 assert(ieeeFlags
.invalid
);
387 // Check that calling func() has no effect on the
389 IeeeFlags f
= ieeeFlags
;
391 assert(ieeeFlags
== f
);
396 import std
.math
.traits
: isNaN
;
402 // Set all the flags to zero
404 assert(!ieeeFlags
.divByZero
);
405 // Perform a division by zero.
406 a
= forceDivOp(a
, 0.0L);
407 assert(a
== real.infinity
);
408 assert(ieeeFlags
.divByZero
);
410 a
= forceMulOp(a
, 0.0L);
411 assert(ieeeFlags
.invalid
);
414 // Check that calling func() has no effect on the
416 IeeeFlags f
= ieeeFlags
;
418 assert(ieeeFlags
== f
);
423 import std
.meta
: AliasSeq
;
427 void delegate() @trusted action
;
428 bool function() @trusted ieeeCheck
;
431 static foreach (T
; AliasSeq
!(float, double, real))
433 T x
; // Needs to be here to avoid `call without side effects` warning.
436 () { x
= forceAddOp
!T(1, 0.1L); },
437 () => ieeeFlags
.inexact
440 () { x
= forceDivOp
!T(T
.min_normal
, T
.max
); },
441 () => ieeeFlags
.underflow
444 () { x
= forceAddOp
!T(T
.max
, T
.max
); },
445 () => ieeeFlags
.overflow
448 () { x
= forceDivOp
!T(1, 0); },
449 () => ieeeFlags
.divByZero
452 () { x
= forceDivOp
!T(0, 0); },
453 () => ieeeFlags
.invalid
456 foreach (test; tests
)
459 assert(!test.ieeeCheck());
461 assert(test.ieeeCheck());
466 /// Set all of the floating-point status flags to false.
467 void resetIeeeFlags() @trusted nothrow @nogc
469 IeeeFlags
.resetIeeeFlags();
479 assert(a
== real.infinity
);
480 assert(ieeeFlags
.divByZero
);
483 assert(!ieeeFlags
.divByZero
);
490 a
= forceDivOp(a
, 0.0L);
491 assert(a
== real.infinity
);
492 assert(ieeeFlags
.divByZero
);
495 assert(!ieeeFlags
.divByZero
);
498 /// Returns: snapshot of the current state of the floating-point status flags
499 @property IeeeFlags
ieeeFlags() @trusted pure nothrow @nogc
501 return IeeeFlags(IeeeFlags
.getIeeeFlags());
506 @safe nothrow unittest
508 import std
.math
.traits
: isNaN
;
514 assert(a
== real.infinity
);
515 assert(ieeeFlags
.divByZero
);
519 assert(ieeeFlags
.invalid
);
522 @safe nothrow unittest
524 import std
.math
.traits
: isNaN
;
529 a
= forceDivOp(a
, 0.0L);
530 assert(a
== real.infinity
);
531 assert(ieeeFlags
.divByZero
);
533 a
= forceMulOp(a
, 0.0L);
535 assert(ieeeFlags
.invalid
);
538 } // IeeeFlagsSupport
541 version (FloatingPointControlSupport
)
544 /** Control the Floating point hardware
546 Change the IEEE754 floating-point rounding mode and the floating-point
549 By default, the rounding mode is roundToNearest and all hardware exceptions
550 are disabled. For most applications, debugging is easier if the $(I division
551 by zero), $(I overflow), and $(I invalid operation) exceptions are enabled.
552 These three are combined into a $(I severeExceptions) value for convenience.
553 Note in particular that if $(I invalidException) is enabled, a hardware trap
554 will be generated whenever an uninitialized floating-point variable is used.
556 All changes are temporary. The previous state is restored at the
563 FloatingPointControl fpctrl;
565 // Enable hardware exceptions for division by zero, overflow to infinity,
566 // invalid operations, and uninitialized floating-point variables.
567 fpctrl.enableExceptions(FloatingPointControl.severeExceptions);
569 // This will generate a hardware exception, if x is a
570 // default-initialized floating point variable:
571 real x; // Add `= 0` or even `= real.nan` to not throw the exception.
574 // The exception is only thrown for default-uninitialized NaN-s.
575 // NaN-s with other payload are valid:
576 real z = y * real.nan; // ok
578 // The set hardware exceptions and rounding modes will be disabled when
579 // leaving this scope.
584 struct FloatingPointControl
588 alias RoundingMode
= uint; ///
594 /** IEEE rounding modes.
595 * The default mode is roundToNearest.
597 * roundingMask = A mask of all rounding modes.
602 roundToZero
, /// ditto
603 roundingMask
, /// ditto
606 else version (CRuntime_Microsoft
)
608 // Microsoft uses hardware-incompatible custom constants in fenv.h (core.stdc.fenv).
611 roundToNearest
= 0x0000,
614 roundToZero
= 0x0C00,
615 roundingMask
= roundToNearest | roundDown
616 | roundUp | roundToZero
,
623 roundToNearest
= core
.stdc
.fenv
.FE_TONEAREST
,
624 roundDown
= core
.stdc
.fenv
.FE_DOWNWARD
,
625 roundUp
= core
.stdc
.fenv
.FE_UPWARD
,
626 roundToZero
= core
.stdc
.fenv
.FE_TOWARDZERO
,
627 roundingMask
= roundToNearest | roundDown
628 | roundUp | roundToZero
,
633 * Change the floating-point hardware rounding mode
635 * Changing the rounding mode in the middle of a function can interfere
636 * with optimizations of floating point expressions, as the optimizer assumes
637 * that the rounding mode does not change.
638 * It is best to change the rounding mode only at the
639 * beginning of the function, and keep it until the function returns.
640 * It is also best to add the line:
642 * pragma(inline, false);
644 * as the first line of the function so it will not get inlined.
646 * newMode = the new rounding mode
648 @property void rounding(RoundingMode newMode
) @trusted
651 setControlState((getControlState() & (-1 - roundingMask
)) |
(newMode
& roundingMask
));
654 /// Returns: the currently active rounding mode
655 @property static RoundingMode
rounding() @trusted pure
657 return cast(RoundingMode
)(getControlState() & roundingMask
);
660 alias ExceptionMask
= uint; ///
666 /** IEEE hardware exceptions.
667 * By default, all exceptions are masked (disabled).
669 * severeExceptions = The overflow, division by zero, and invalid
673 inexactException
, /// ditto
674 underflowException
, /// ditto
675 overflowException
, /// ditto
676 divByZeroException
, /// ditto
677 invalidException
, /// ditto
678 severeExceptions
, /// ditto
679 allExceptions
, /// ditto
682 else version (ARM_Any
)
686 subnormalException
= 0x8000,
687 inexactException
= 0x1000,
688 underflowException
= 0x0800,
689 overflowException
= 0x0400,
690 divByZeroException
= 0x0200,
691 invalidException
= 0x0100,
692 severeExceptions
= overflowException | divByZeroException
694 allExceptions
= severeExceptions | underflowException
695 | inexactException | subnormalException
,
698 else version (PPC_Any
)
702 inexactException
= 0x0008,
703 divByZeroException
= 0x0010,
704 underflowException
= 0x0020,
705 overflowException
= 0x0040,
706 invalidException
= 0x0080,
707 severeExceptions
= overflowException | divByZeroException
709 allExceptions
= severeExceptions | underflowException
713 else version (RISCV_Any
)
717 inexactException
= 0x01,
718 divByZeroException
= 0x08,
719 underflowException
= 0x02,
720 overflowException
= 0x04,
721 invalidException
= 0x10,
722 severeExceptions
= overflowException | divByZeroException
724 allExceptions
= severeExceptions | underflowException
732 inexactException
= 0x01,
733 underflowException
= 0x02,
734 overflowException
= 0x04,
735 divByZeroException
= 0x08,
736 invalidException
= 0x10,
737 severeExceptions
= overflowException | divByZeroException
739 allExceptions
= severeExceptions | underflowException
743 else version (LoongArch_Any
)
747 inexactException
= 0x00,
748 divByZeroException
= 0x01,
749 overflowException
= 0x02,
750 underflowException
= 0x04,
751 invalidException
= 0x08,
752 severeExceptions
= overflowException | divByZeroException
754 allExceptions
= severeExceptions | underflowException
758 else version (MIPS_Any
)
762 inexactException
= 0x0080,
763 divByZeroException
= 0x0400,
764 overflowException
= 0x0200,
765 underflowException
= 0x0100,
766 invalidException
= 0x0800,
767 severeExceptions
= overflowException | divByZeroException
769 allExceptions
= severeExceptions | underflowException
773 else version (SPARC_Any
)
777 inexactException
= 0x0800000,
778 divByZeroException
= 0x1000000,
779 overflowException
= 0x4000000,
780 underflowException
= 0x2000000,
781 invalidException
= 0x8000000,
782 severeExceptions
= overflowException | divByZeroException
784 allExceptions
= severeExceptions | underflowException
788 else version (IBMZ_Any
)
792 inexactException
= 0x08000000,
793 divByZeroException
= 0x40000000,
794 overflowException
= 0x20000000,
795 underflowException
= 0x10000000,
796 invalidException
= 0x80000000,
797 severeExceptions
= overflowException | divByZeroException
799 allExceptions
= severeExceptions | underflowException
803 else version (X86_Any
)
807 inexactException
= 0x20,
808 underflowException
= 0x10,
809 overflowException
= 0x08,
810 divByZeroException
= 0x04,
811 subnormalException
= 0x02,
812 invalidException
= 0x01,
813 severeExceptions
= overflowException | divByZeroException
815 allExceptions
= severeExceptions | underflowException
816 | inexactException | subnormalException
,
820 static assert(false, "Not implemented for this architecture");
824 static bool hasExceptionTraps_impl() @safe
826 auto oldState
= getControlState();
827 // If exceptions are not supported, we set the bit but read it back as zero
828 // https://sourceware.org/ml/libc-ports/2012-06/msg00091.html
829 setControlState(oldState | divByZeroException
);
830 immutable result
= (getControlState() & allExceptions
) != 0;
831 setControlState(oldState
);
836 /// Returns: true if the current FPU supports exception trapping
837 @property static bool hasExceptionTraps() @safe pure
841 else version (PPC_Any
)
843 else version (MIPS_Any
)
845 else version (LoongArch_Any
)
847 else version (ARM_Any
)
849 // The hasExceptionTraps_impl function is basically pure,
850 // as it restores all global state
851 auto fptr
= ( () @trusted => cast(bool function() @safe
852 pure nothrow @nogc)&hasExceptionTraps_impl
)();
856 assert(0, "Not yet supported");
859 /// Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together.
860 void enableExceptions(ExceptionMask exceptions
) @trusted
862 assert(hasExceptionTraps
);
865 setControlState(getControlState() & ~(exceptions
& allExceptions
));
867 setControlState(getControlState() |
(exceptions
& allExceptions
));
870 /// Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together.
871 void disableExceptions(ExceptionMask exceptions
) @trusted
873 assert(hasExceptionTraps
);
876 setControlState(getControlState() |
(exceptions
& allExceptions
));
878 setControlState(getControlState() & ~(exceptions
& allExceptions
));
881 /// Returns: the exceptions which are currently enabled (unmasked)
882 @property static ExceptionMask
enabledExceptions() @trusted pure
884 assert(hasExceptionTraps
);
886 return (getControlState() & allExceptions
) ^ allExceptions
;
888 return (getControlState() & allExceptions
);
891 /// Clear all pending exceptions, then restore the original exception state and rounding mode.
896 setControlState(savedState
);
900 ControlState savedState
;
902 bool initialized
= false;
906 alias ControlState
= uint;
910 alias ControlState
= uint;
912 else version (PPC_Any
)
914 alias ControlState
= uint;
916 else version (RISCV_Any
)
918 alias ControlState
= uint;
920 else version (LoongArch_Any
)
922 alias ControlState
= uint;
924 else version (MIPS_Any
)
926 alias ControlState
= uint;
928 else version (SPARC_Any
)
930 alias ControlState
= ulong;
932 else version (IBMZ_Any
)
934 alias ControlState
= uint;
936 else version (X86_Any
)
938 alias ControlState
= ushort;
941 static assert(false, "Not implemented for this architecture");
943 void initialize() @safe
945 // BUG: This works around the absence of this() constructors.
946 if (initialized
) return;
948 savedState
= getControlState();
952 // Clear all pending exceptions
953 static void clearExceptions() @safe
955 version (IeeeFlagsSupport
)
958 static assert(false, "Not implemented for this architecture");
961 // Read from the control register
962 package(std
.math
) static ControlState
getControlState() @trusted pure
969 asm pure nothrow @nogc
971 "fstcw %0" : "=m" (cont
);
975 else version (AArch64
)
978 asm pure nothrow @nogc
980 "mrs %0, FPCR;" : "=r" (cont
);
987 version (ARM_SoftFloat
)
991 asm pure nothrow @nogc
993 "vmrs %0, FPSCR" : "=r" (cont
);
998 else version (RISCV_Any
)
1000 version (D_SoftFloat
)
1005 asm pure nothrow @nogc
1007 "frcsr %0" : "=r" (cont
);
1013 assert(0, "Not yet supported");
1016 version (D_InlineAsm_X86
)
1019 asm pure nothrow @nogc
1026 else version (D_InlineAsm_X86_64
)
1029 asm pure nothrow @nogc
1036 else version (RISCV_Any
)
1039 asm pure nothrow @nogc
1041 "frcsr %0" : "=r" (cont
);
1045 else version (LoongArch_Any
)
1048 asm pure nothrow @nogc
1050 "movfcsr2gr %0, $fcsr0" : "=r" (cont
);
1052 cont
&= (roundingMask | allExceptions
);
1056 assert(0, "Not yet supported");
1059 // Set the control register
1060 package(std
.math
) static void setControlState(ControlState newState
) @trusted
1068 "fclex; fldcw %0" : : "m" (newState
);
1071 // Also update MXCSR, SSE's control register.
1077 "stmxcsr %0" : "=m" (mxcsr
);
1080 /* In the FPU control register, rounding mode is in bits 10 and
1081 11. In MXCSR it's in bits 13 and 14. */
1082 mxcsr
&= ~(roundingMask
<< 3); // delete old rounding mode
1083 mxcsr |
= (newState
& roundingMask
) << 3; // write new rounding mode
1085 /* In the FPU control register, masks are bits 0 through 5.
1086 In MXCSR they're 7 through 12. */
1087 mxcsr
&= ~(allExceptions
<< 7); // delete old masks
1088 mxcsr |
= (newState
& allExceptions
) << 7; // write new exception masks
1092 "ldmxcsr %0" : : "m" (mxcsr
);
1096 else version (AArch64
)
1100 "msr FPCR, %0;" : : "r" (newState
);
1105 version (ARM_SoftFloat
)
1111 "vmsr FPSCR, %0" : : "r" (newState
);
1115 else version (RISCV_Any
)
1117 version (D_SoftFloat
)
1123 "fscsr %0" : : "r" (newState
);
1128 assert(0, "Not yet supported");
1131 version (InlineAsm_X86_Any
)
1139 // Also update MXCSR, SSE's control register.
1143 asm nothrow @nogc { stmxcsr mxcsr
; }
1145 /* In the FPU control register, rounding mode is in bits 10 and
1146 11. In MXCSR it's in bits 13 and 14. */
1147 mxcsr
&= ~(roundingMask
<< 3); // delete old rounding mode
1148 mxcsr |
= (newState
& roundingMask
) << 3; // write new rounding mode
1150 /* In the FPU control register, masks are bits 0 through 5.
1151 In MXCSR they're 7 through 12. */
1152 mxcsr
&= ~(allExceptions
<< 7); // delete old masks
1153 mxcsr |
= (newState
& allExceptions
) << 7; // write new exception masks
1155 asm nothrow @nogc { ldmxcsr mxcsr
; }
1158 else version (RISCV_Any
)
1160 asm pure nothrow @nogc
1162 "fscsr %0" : : "r" (newState
);
1165 else version (LoongArch_Any
)
1169 "movgr2fcsr $fcsr0,%0" :
1170 : "r" (newState
& (roundingMask | allExceptions
));
1174 assert(0, "Not yet supported");
1181 import std
.math
.rounding
: lrint
;
1183 FloatingPointControl fpctrl
;
1185 fpctrl
.rounding
= FloatingPointControl
.roundDown
;
1186 assert(lrint(1.5) == 1.0);
1188 fpctrl
.rounding
= FloatingPointControl
.roundUp
;
1189 assert(lrint(1.4) == 2.0);
1191 fpctrl
.rounding
= FloatingPointControl
.roundToNearest
;
1192 assert(lrint(1.5) == 2.0);
1197 void ensureDefaults()
1199 assert(FloatingPointControl
.rounding
1200 == FloatingPointControl
.roundToNearest
);
1201 if (FloatingPointControl
.hasExceptionTraps
)
1202 assert(FloatingPointControl
.enabledExceptions
== 0);
1206 FloatingPointControl ctrl
;
1211 FloatingPointControl ctrl
;
1212 ctrl
.rounding
= FloatingPointControl
.roundDown
;
1213 assert(FloatingPointControl
.rounding
== FloatingPointControl
.roundDown
);
1217 if (FloatingPointControl
.hasExceptionTraps
)
1219 FloatingPointControl ctrl
;
1220 ctrl
.enableExceptions(FloatingPointControl
.divByZeroException
1221 | FloatingPointControl
.overflowException
);
1222 assert(ctrl
.enabledExceptions
==
1223 (FloatingPointControl
.divByZeroException
1224 | FloatingPointControl
.overflowException
));
1226 ctrl
.rounding
= FloatingPointControl
.roundUp
;
1227 assert(FloatingPointControl
.rounding
== FloatingPointControl
.roundUp
);
1232 @safe unittest // rounding
1234 import std
.meta
: AliasSeq
;
1236 static T
addRound(T
)(uint rm
)
1238 pragma(inline
, false);
1239 FloatingPointControl fpctrl
;
1240 fpctrl
.rounding
= rm
;
1242 x
= forceAddOp(x
, 0.1L);
1246 static T
subRound(T
)(uint rm
)
1248 pragma(inline
, false);
1249 FloatingPointControl fpctrl
;
1250 fpctrl
.rounding
= rm
;
1252 x
= forceSubOp(x
, 0.1L);
1256 static foreach (T
; AliasSeq
!(float, double, real))
1258 /* Be careful with changing the rounding mode, it interferes
1259 * with common subexpressions. Changing rounding modes should
1260 * be done with separate functions that are not inlined.
1264 T u
= addRound
!(T
)(FloatingPointControl
.roundUp
);
1265 T d
= addRound
!(T
)(FloatingPointControl
.roundDown
);
1266 T z
= addRound
!(T
)(FloatingPointControl
.roundToZero
);
1273 T u
= subRound
!(T
)(FloatingPointControl
.roundUp
);
1274 T d
= subRound
!(T
)(FloatingPointControl
.roundDown
);
1275 T z
= subRound
!(T
)(FloatingPointControl
.roundToZero
);
1283 } // FloatingPointControlSupport
1285 version (StdUnittest
)
1287 // These helpers are intended to avoid constant propagation by the optimizer.
1288 pragma(inline
, false) private @safe
1290 T
forceAddOp(T
)(T x
, T y
) { return x
+ y
; }
1291 T
forceSubOp(T
)(T x
, T y
) { return x
- y
; }
1292 T
forceMulOp(T
)(T x
, T y
) { return x
* y
; }
1293 T
forceDivOp(T
)(T x
, T y
) { return x
/ y
; }