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