History

Add support for floating point flags - Setting exception flag traps is not properly supported - no C++ support

arr committed 9 years ago

Commit b3354b21 parent b1b22c23 files · +203 −13Browse files

Showing the changes to src (2 of 3 files). Show all

Unified · Split

2 files
  1. src/include/vm_memory.h +1 −1
  2. src/vm/math/Mathmod.cpp +150 −10
src/include/vm_memory.h+1−1
@@ -57,7 +57,7 @@ namespace disvm · 56 unmodified lines
57 template<typename CB>57 template<typename CB>
58 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, CB callback)58 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, CB callback)
59 {59 {
60 assert(data != nullptr && callback != nullptr);60 assert(data != nullptr);
61 61
62 auto memory = reinterpret_cast<word_t *>(data);62 auto memory = reinterpret_cast<word_t *>(data);
63 for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)63 for (auto i = word_t{ 0 }; i < type_desc.map_in_bytes; ++i, memory += 8)
src/vm/math/Mathmod.cpp+150−10
@@ -4,6 +4,16 @@ · 3 unmodified lines
4// Author: arr4// Author: arr
5//5//
6 6
7#ifdef _MSC_VER
8// Pragma for floating point support - https://msdn.microsoft.com/en-us/library/bfwa91s0.aspx
9#pragma fenv_access (on)
10#else
11// Pragma for floating point support - http://en.cppreference.com/w/cpp/numeric/fenv
12#pragma STDC FENV_ACCESS ON
13#endif
14
15#include <cfenv>
16
7#include <debug.h>17#include <debug.h>
8#include "Mathmod.h"18#include "Mathmod.h"
9 19
@@ -96,30 +106,160 @@ namespace · 86 unmodified lines
96 };106 };
97 107
98 const word_t Mathmodlen = 68;108 const word_t Mathmodlen = 68;
109
110 // Convert from std floating point round to limbo
111 word_t convert_to_limbo_fp_round(int r)
112 {
113 switch (r & FE_ROUND_MASK)
114 {
115 default:
116 assert(false && "Invalid floating point rounding flag");
117 case FE_TONEAREST:
118 return Math_RND_NR;
119 case FE_DOWNWARD:
120 return Math_RND_NINF;
121 case FE_UPWARD:
122 return Math_RND_PINF;
123 case FE_TOWARDZERO:
124 return Math_RND_Z;
125 }
126 }
127
128 // Convert from std floating point exception to limbo
129 word_t convert_to_limbo_fp_exception(std::fexcept_t e)
130 {
131 word_t e_flags{};
132 if (e & FE_INEXACT) e_flags |= Math_INEX;
133 if (e & FE_UNDERFLOW) e_flags |= Math_UNFL;
134 if (e & FE_OVERFLOW) e_flags |= Math_OVFL;
135 if (e & FE_DIVBYZERO) e_flags |= Math_ZDIV;
136 if (e & FE_INVALID) e_flags |= Math_INVAL;
137
138 return e_flags;
139 }
140
141 // Convert from limbo floating point round to std
142 int convert_to_std_fp_round(word_t r)
143 {
144 switch (r & Math_RND_MASK)
145 {
146 default:
147 assert(false && "Invalid floating point rounding flag");
148 case Math_RND_NR:
149 return FE_TONEAREST;
150 case Math_RND_NINF:
151 return FE_DOWNWARD;
152 case Math_RND_PINF:
153 return FE_UPWARD;
154 case Math_RND_Z:
155 return FE_TOWARDZERO;
156 }
157 }
158
159 // Convert from limbo floating point exception to std
160 std::fexcept_t convert_to_std_fp_exception(word_t e)
161 {
162 std::fexcept_t e_flags{};
163 if (e & Math_INEX) e_flags |= FE_INEXACT;
164 if (e & Math_UNFL) e_flags |= FE_UNDERFLOW;
165 if (e & Math_OVFL) e_flags |= FE_OVERFLOW;
166 if (e & Math_ZDIV) e_flags |= FE_DIVBYZERO;
167 if (e & Math_INVAL) e_flags |= FE_INVALID;
168
169 return e_flags;
170 }
171
172 // Get floating point exception flags
173 word_t get_fp_exception_flags()
174 {
175 std::fexcept_t e_flags;
176 int ec = std::fegetexceptflag(&e_flags, FE_ALL_EXCEPT);
177 if (ec != 0)
178 {
179 assert(false && "Failed to get except flag");
180 return 0;
181 }
182
183 return convert_to_limbo_fp_exception(e_flags);
184 }
185
186 // Get all floating point flags
187 word_t get_all_fp_flags()
188 {
189 const auto rnd_flag = std::fegetround();
190 const auto e_flags = get_fp_exception_flags();
191 return (convert_to_limbo_fp_round(rnd_flag) | e_flags);
192 }
193
194 // Set floating point control flags
195 void set_fp_control_flags(std::fexcept_t e_flags, std::fexcept_t e_mask, int rnd_flag, int rnd_mask)
196 {
197 int ec;
198
199 // [SPEC] No current mechanism to set floating point exception control flags
200
201 if (rnd_mask != 0)
202 {
203 ec = std::fesetround(rnd_flag & rnd_mask);
204 assert(ec == 0);
205 (void)ec;
206 }
207 }
99}208}
100 209
101void210void
102Mathmodinit(void)211Mathmodinit(void)
103{212{
104 disvm::runtime::builtin::register_module_exports(Math_PATH, Mathmodlen, Mathmodtab);213 disvm::runtime::builtin::register_module_exports(Math_PATH, Mathmodlen, Mathmodtab);
214
215 // Inferno floating point flags (http://www.vitanuova.com/inferno/man/2/math-fp.html)
216 set_fp_control_flags(
217 FE_INEXACT, // Inexact is fatal
218 FE_ALL_EXCEPT,
219 FE_TONEAREST, // Round to nearest even
220 FE_ROUND_MASK);
105}221}
106 222
107void223void
108Math_FPcontrol(vm_registers_t &r, vm_t &vm)224Math_FPcontrol(vm_registers_t &r, vm_t &)
109{225{
110 auto &fp = r.stack.peek_frame()->base<F_Math_FPcontrol>();226 auto &fp = r.stack.peek_frame()->base<F_Math_FPcontrol>();
111 227
112 // [PAL] Properly implement floating point control228 const auto prev_fp_flags = get_all_fp_flags();
113 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::warning, "FPControl is not properly implemented");229
230 const auto e_flags = convert_to_std_fp_exception(fp.r & fp.mask);
231 const auto rnd_flag = convert_to_std_fp_round(fp.r & fp.mask);
114 232
115 *fp.ret = fp.mask;233 set_fp_control_flags(
234 e_flags,
235 fp.mask & FE_ALL_EXCEPT,
236 rnd_flag,
237 fp.mask & FE_ROUND_MASK);
238
239 *fp.ret = (prev_fp_flags & fp.mask);
116}240}
117 241
118void242void
119Math_FPstatus(vm_registers_t &r, vm_t &vm)243Math_FPstatus(vm_registers_t &r, vm_t &)
120{244{
121 auto &fp = r.stack.peek_frame()->base<F_Math_FPstatus>();245 auto &fp = r.stack.peek_frame()->base<F_Math_FPstatus>();
122 throw vm_system_exception{ "Function not implemented" };246
247 const auto prev_e_flags = get_fp_exception_flags();
248
249 // Clear all exceptions
250 int ec = std::feclearexcept(FE_ALL_EXCEPT);
251 assert(ec == 0);
252 (void)ec;
253
254 const auto e_flags = convert_to_std_fp_exception(fp.r);
255 const auto e_mask = convert_to_std_fp_exception(fp.mask);
256
257 // Set exception flags
258 ec = std::fesetexceptflag(&e_flags, static_cast<const int>(e_mask));
259 assert(ec == 0);
260 (void)ec;
261
262 *fp.ret = (prev_e_flags & e_mask);
123}263}
124 264
125void265void
@@ -392,17 +532,17 @@ Math_gemm(vm_registers_t &r, vm_t &vm) · 266 unmodified lines
392}532}
393 533
394void534void
395Math_getFPcontrol(vm_registers_t &r, vm_t &vm)535Math_getFPcontrol(vm_registers_t &r, vm_t &)
396{536{
397 auto &fp = r.stack.peek_frame()->base<F_Math_getFPcontrol>();537 auto &fp = r.stack.peek_frame()->base<F_Math_getFPcontrol>();
398 throw vm_system_exception{ "Function not implemented" };538 *fp.ret = get_all_fp_flags();
399}539}
400 540
401void541void
402Math_getFPstatus(vm_registers_t &r, vm_t &vm)542Math_getFPstatus(vm_registers_t &r, vm_t &)
403{543{
404 auto &fp = r.stack.peek_frame()->base<F_Math_getFPstatus>();544 auto &fp = r.stack.peek_frame()->base<F_Math_getFPstatus>();
405 throw vm_system_exception{ "Function not implemented" };545 *fp.ret = get_fp_exception_flags();
406}546}
407 547
408void548void