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
5757 template<typename CB>
5858 void enum_pointer_fields(const type_descriptor_t &type_desc, void *data, CB callback)
5959 {
60− assert(data != nullptr && callback != nullptr);
60+ assert(data != nullptr);
6161
6262 auto memory = reinterpret_cast<word_t *>(data);
6363 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
44 // Author: arr
55 //
66
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+
717 #include <debug.h>
818 #include "Mathmod.h"
919
@@ -96,30 +106,160 @@ namespace · 86 unmodified lines
96106 };
97107
98108 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+ }
99208 }
100209
101210 void
102211 Mathmodinit(void)
103212 {
104213 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);
105221 }
106222
107223 void
108−Math_FPcontrol(vm_registers_t &r, vm_t &vm)
224+Math_FPcontrol(vm_registers_t &r, vm_t &)
109225 {
110226 auto &fp = r.stack.peek_frame()->base<F_Math_FPcontrol>();
111227
112− // [PAL] Properly implement floating point control
113− disvm::debug::log_msg(component_trace_t::builtin, log_level_t::warning, "FPControl is not properly implemented");
228+ const auto prev_fp_flags = get_all_fp_flags();
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);
114232
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);
116240 }
117241
118242 void
119−Math_FPstatus(vm_registers_t &r, vm_t &vm)
243+Math_FPstatus(vm_registers_t &r, vm_t &)
120244 {
121245 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);
123263 }
124264
125265 void
@@ -392,17 +532,17 @@ Math_gemm(vm_registers_t &r, vm_t &vm) · 266 unmodified lines
392532 }
393533
394534 void
395−Math_getFPcontrol(vm_registers_t &r, vm_t &vm)
535+Math_getFPcontrol(vm_registers_t &r, vm_t &)
396536 {
397537 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();
399539 }
400540
401541 void
402−Math_getFPstatus(vm_registers_t &r, vm_t &vm)
542+Math_getFPstatus(vm_registers_t &r, vm_t &)
403543 {
404544 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();
406546 }
407547
408548 void