Serenity Operating System
at master 124 lines 3.0 kB view raw
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}