Serenity Operating System
1/*
2 * Copyright (c) 2022, Leon Albrecht <leon.a@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Types.h>
10
11// FIXME: Add equivalent datastructures for aarch64
12VALIDATE_IS_X86();
13
14namespace AK {
15
16enum class RoundingMode : u8 {
17 NEAREST = 0b00,
18 DOWN = 0b01,
19 UP = 0b10,
20 TRUNC = 0b11
21};
22
23union X87ControlWord {
24 u16 cw;
25 struct {
26 u16 mask_invalid : 1; // IM
27 u16 mask_denorm : 1; // DM
28 u16 mask_zero_div : 1; // ZM
29 u16 mask_overflow : 1; // OM
30 u16 mask_underflow : 1; // UM
31 u16 mask_precision : 1; // PM
32 u16 : 2; // unused
33 u16 precision : 2; // PC
34 RoundingMode rounding_control : 2; // RC
35 u16 infinity_control : 1; // X
36 u16 : 3; // unused
37 };
38};
39static_assert(sizeof(X87ControlWord) == sizeof(u16));
40
41union MXCSR {
42 u32 mxcsr;
43 struct {
44 u32 invalid_operation_flag : 1; // IE
45 u32 denormal_operation_flag : 1; // DE
46 u32 divide_by_zero_flag : 1; // ZE
47 u32 overflow_flag : 1; // OE
48 u32 underflow_flag : 1; // UE
49 u32 precision_flag : 1; // PE
50 u32 denormals_are_zero : 1; // DAZ
51 u32 invalid_operation_mask : 1; // IM
52 u32 denormal_operation_mask : 1; // DM
53 u32 divide_by_zero_mask : 1; // ZM
54 u32 overflow_mask : 1; // OM
55 u32 underflow_mask : 1; // UM
56 u32 precision_mask : 1; // PM
57 RoundingMode rounding_control : 2; // RC
58 u32 flush_to_zero : 1; // FTZ
59 u32 __reserved : 16;
60 };
61};
62static_assert(sizeof(MXCSR) == sizeof(u32));
63
64ALWAYS_INLINE X87ControlWord get_cw_x87()
65{
66 X87ControlWord control_word;
67 asm("fnstcw %0"
68 : "=m"(control_word));
69 return control_word;
70}
71ALWAYS_INLINE void set_cw_x87(X87ControlWord control_word)
72{
73 asm("fldcw %0" ::"m"(control_word));
74}
75
76ALWAYS_INLINE MXCSR get_mxcsr()
77{
78 MXCSR mxcsr;
79 asm("stmxcsr %0"
80 : "=m"(mxcsr));
81 return mxcsr;
82}
83ALWAYS_INLINE void set_mxcsr(MXCSR mxcsr)
84{
85 asm("ldmxcsr %0" ::"m"(mxcsr));
86}
87
88class X87RoundingModeScope {
89public:
90 X87RoundingModeScope(RoundingMode rounding_mode)
91 {
92 m_cw = get_cw_x87();
93 auto cw = m_cw;
94 cw.rounding_control = rounding_mode;
95 set_cw_x87(cw);
96 }
97 ~X87RoundingModeScope()
98 {
99 set_cw_x87(m_cw);
100 }
101
102private:
103 X87ControlWord m_cw;
104};
105
106class SSERoundingModeScope {
107public:
108 SSERoundingModeScope(RoundingMode rounding_mode)
109 {
110 m_mxcsr = get_mxcsr();
111 auto mxcsr = m_mxcsr;
112 mxcsr.rounding_control = rounding_mode;
113 set_mxcsr(mxcsr);
114 }
115 ~SSERoundingModeScope()
116 {
117 set_mxcsr(m_mxcsr);
118 }
119
120private:
121 MXCSR m_mxcsr;
122};
123
124}