Repository navigation
Expand file tree
/
Copy pathFloatingPoint.cpp
More file actions
137 lines (114 loc) · 4.54 KB
/
Copy pathFloatingPoint.cpp
File metadata and controls
137 lines (114 loc) · 4.54 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "prx/libc/include/general/VabiMacros.hpp"
#include <array>
#include <cstdint>
#include <stdexcept>
#include <xmmintrin.h>
namespace {
constexpr unsigned Exceptions = 0x3f;
constexpr unsigned Rounding = 0xc00;
void ReplaceFlags(unsigned mask, unsigned flags) {
std::array<std::uint32_t, 7> environment;
asm volatile("fnstenv %0" : "=m"(environment));
environment[1] = (environment[1] & ~mask) | (flags & mask);
asm volatile("fldenv %0" : : "m"(environment));
_mm_setcsr((_mm_getcsr() & ~mask) | (flags & mask));
}
int ChangeTraps(int exceptions, bool enable) {
const auto mask = static_cast<unsigned>(exceptions) & Exceptions;
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
const unsigned csr = _mm_getcsr();
const auto changed = static_cast<std::uint16_t>(enable ? (control & ~mask) : (control | mask));
asm volatile("fldcw %0" : : "m"(changed));
_mm_setcsr(enable ? (csr & ~(mask << 7)) : (csr | (mask << 7)));
return static_cast<int>(~((csr >> 7) | control) | ~Exceptions);
}
}
extern "C" {
int APS5_VABI fegetround_nid_postfix() {
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
return control & Rounding;
}
int APS5_VABI fesetround_nid_postfix(int rounding) {
const auto mode = static_cast<unsigned>(rounding);
if ((mode & ~Rounding) != 0) return -1;
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
control = static_cast<std::uint16_t>((control & ~Rounding) | mode);
asm volatile("fldcw %0" : : "m"(control));
_mm_setcsr((_mm_getcsr() & ~(Rounding << 3)) | (mode << 3));
return 0;
}
int APS5_VABI fetestexcept_nid_postfix(int exceptions) {
std::uint16_t status;
asm volatile("fnstsw %0" : "=am"(status));
return (status | _mm_getcsr()) & static_cast<unsigned>(exceptions) & Exceptions;
}
int APS5_VABI fegetexceptflag_nid_postfix(std::uint16_t* flags, int exceptions) {
if (flags == nullptr) throw std::invalid_argument("fegetexceptflag: null flags");
*flags = static_cast<std::uint16_t>(fetestexcept_nid_postfix(exceptions));
return 0;
}
int* APS5_VABI __error_nid_postfix();
void APS5_VABI _Feraise_nid_postfix(int exceptions) {
constexpr unsigned Invalid = 0x01, Ranges = 0x1c, Overflows = 0x18, Inexact = 0x20;
constexpr int GuestEdom = 33, GuestErange = 34;
auto raised = static_cast<unsigned>(exceptions);
if ((raised & Overflows) != 0) raised |= Inexact;
*__error_nid_postfix() = GuestEdom;
std::array<std::uint32_t, 7> environment;
asm volatile("fnstenv %0" : "=m"(environment));
environment[1] = (environment[1] & ~raised) | (raised & 0xffff);
asm volatile("fldenv %0" : : "m"(environment));
_mm_setcsr((_mm_getcsr() & ~raised) | (raised & 0xffff));
asm volatile("fwait");
if ((raised & Invalid) != 0) *__error_nid_postfix() = GuestEdom;
else if ((raised & Ranges) != 0) *__error_nid_postfix() = GuestErange;
}
int APS5_VABI fesetexceptflag_nid_postfix(const std::uint16_t* flags, int exceptions) {
if (flags == nullptr) throw std::invalid_argument("fesetexceptflag: null flags");
ReplaceFlags(static_cast<unsigned>(exceptions) & Exceptions, *flags);
return 0;
}
int APS5_VABI feclearexcept_nid_postfix(int exceptions) {
const auto mask = static_cast<unsigned>(exceptions) & Exceptions;
if (mask == Exceptions) {
asm volatile("fnclex");
_mm_setcsr(_mm_getcsr() & ~Exceptions);
} else if (mask != 0) {
ReplaceFlags(mask, 0);
}
return 0;
}
int APS5_VABI feenableexcept_nid_postfix(int exceptions) {
return ChangeTraps(exceptions, true);
}
int APS5_VABI fedisableexcept_nid_postfix(int exceptions) {
return ChangeTraps(exceptions, false);
}
int APS5_VABI __feenableexcept_nid_postfix(int exceptions) {
return ChangeTraps(exceptions, true);
}
int APS5_VABI __fedisableexcept_nid_postfix(int exceptions) {
return ChangeTraps(exceptions, false);
}
int APS5_VABI fegettrapenable_nid_postfix() {
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
return ~control & Exceptions;
}
int APS5_VABI fegetexcept_nid_postfix() {
return fegettrapenable_nid_postfix();
}
int APS5_VABI fesettrapenable_nid_postfix(int exceptions) {
const auto mask = static_cast<std::uint16_t>(exceptions);
if (mask > Exceptions) return 1;
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
control = static_cast<std::uint16_t>(control & ~mask);
asm volatile("fldcw %0" : : "m"(control));
_mm_setcsr(_mm_getcsr() & ~(static_cast<unsigned>(mask) << 7));
return 0;
}
}