Skip to content

Commit 443daf3

Browse files
committed
fix FRNDINT, ftst
Fix setting de flag; add tests
1 parent a52f370 commit 443daf3

File tree

4 files changed

+93
-33
lines changed

4 files changed

+93
-33
lines changed

include/remill/Arch/Runtime/Operators.h

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -566,21 +566,19 @@ MAKE_ATOMIC(XorFetch, xor_and_fetch, ^)
566566

567567
#if !defined(issignaling)
568568

569-
ALWAYS_INLINE uint8_t issignaling(float32_t x) {
569+
ALWAYS_INLINE bool issignaling(float32_t x) {
570570
const nan32_t x_nan = {x};
571571
return x_nan.exponent == 0xFFU && !x_nan.is_quiet_nan && x_nan.payload;
572572
}
573573

574-
ALWAYS_INLINE uint8_t issignaling(float64_t x) {
574+
ALWAYS_INLINE bool issignaling(float64_t x) {
575575
const nan64_t x_nan = {x};
576576
return x_nan.exponent == 0x7FFU && !x_nan.is_quiet_nan && x_nan.payload;
577577
}
578578

579-
ALWAYS_INLINE uint8_t issignaling(float80_t x) {
580-
// this casts to a float64_t on purpose -- since we know that
581-
// it is almost certainly an IEEE 754 double which we can decompose
582-
const nan64_t x_nan = {static_cast<float64_t>(x)};
583-
return x_nan.exponent == 0x7FFFU && !(x_nan.is_quiet_nan) && x_nan.payload;
579+
ALWAYS_INLINE bool issignaling(float80_t x) {
580+
const nan80_t x_nan = {x};
581+
return x_nan.exponent == 0x7FFFU && !x_nan.is_quiet_nan && x_nan.payload && x_nan.interger_bit;
584582
}
585583

586584
#endif // !defined(issignaling)
@@ -652,26 +650,31 @@ ALWAYS_INLINE static uint8_t IsNaN(float80_t x) {
652650
return static_cast<uint8_t>(FP_NAN == std::fpclassify(static_cast<native_float80_t>(x)));
653651
}
654652

655-
ALWAYS_INLINE static uint8_t IsSignalingNaN(float32_t x) {
653+
ALWAYS_INLINE static bool IsSignalingNaN(float32_t x) {
656654
const nan32_t x_nan = {x};
657655
return x_nan.exponent == 0xFFU && !x_nan.is_quiet_nan && x_nan.payload;
658656
}
659657

660-
ALWAYS_INLINE static uint8_t IsSignalingNaN(float64_t x) {
658+
ALWAYS_INLINE static bool IsSignalingNaN(float64_t x) {
661659
const nan64_t x_nan = {x};
662660
return x_nan.exponent == 0x7FFU && !x_nan.is_quiet_nan && x_nan.payload;
663661
}
664662

665-
ALWAYS_INLINE static uint8_t IsSignalingNaN(float80_t x) {
663+
ALWAYS_INLINE static bool IsSignalingNaN(float80_t x) {
666664
const nan80_t x_nan = {x};
667-
return x_nan.exponent == 0x7FFFU && !x_nan.is_quiet_nan && x_nan.payload;
665+
return x_nan.exponent == 0x7FFFU && !x_nan.is_quiet_nan && x_nan.payload && x_nan.interger_bit;
668666
}
669667

670668
template <typename T>
671669
ALWAYS_INLINE static uint8_t IsSignalingNaN(T) {
672670
return 0;
673671
}
674672

673+
template <typename T>
674+
ALWAYS_INLINE static uint8_t IsDenormal(T x) {
675+
return static_cast<uint8_t>(FP_SUBNORMAL == std::fpclassify(x));
676+
}
677+
675678
ALWAYS_INLINE static uint8_t IsDenormal(float32_t x) {
676679
return static_cast<uint8_t>(FP_SUBNORMAL == std::fpclassify(x));
677680
}
@@ -684,6 +687,10 @@ ALWAYS_INLINE static uint8_t IsDenormal(float80_t x) {
684687
return static_cast<uint8_t>(FP_SUBNORMAL == std::fpclassify(static_cast<native_float80_t>(x)));
685688
}
686689

690+
ALWAYS_INLINE static uint8_t IsDenormal(native_float80_t x) {
691+
return static_cast<uint8_t>(FP_SUBNORMAL == std::fpclassify(static_cast<native_float80_t>(x)));
692+
}
693+
687694
template <typename T>
688695
ALWAYS_INLINE static uint8_t IsZero(T val) {
689696
return static_cast<uint8_t>(!val);
@@ -699,11 +706,6 @@ ALWAYS_INLINE static uint8_t IsNaN(T) {
699706
return 0;
700707
}
701708

702-
template <typename T>
703-
ALWAYS_INLINE static uint8_t IsDenormal(T) {
704-
return 0;
705-
}
706-
707709
// Return the largest possible value assignable to `val`.
708710
template <typename T>
709711
ALWAYS_INLINE static T Maximize(T) {

lib/Arch/X86/Semantics/X87.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,16 @@ DEF_FPU_SEM(FILD, RF80W, T src1) {
118118
template <typename T>
119119
DEF_FPU_SEM(FLD, RF80W, T src1) {
120120
SetFPUIpOp();
121-
auto val = Float80(Read(src1));
121+
auto val = Read(src1);
122122
state.sw.ie |= IsSignalingNaN(val);
123-
state.sw.de = IsDenormal(val);
124-
auto res = val;
123+
state.sw.de |= IsDenormal(val);
124+
auto res = Float80(val);
125125

126126
// Quietize if signaling NaN.
127127
if (state.sw.ie) {
128-
nan64_t res_nan = {Float64(res)};
128+
nan80_t res_nan = {res};
129129
res_nan.is_quiet_nan = 1;
130-
res = Float80(res_nan.d);
130+
res = res_nan.d;
131131
}
132132

133133
PUSH_X87_STACK(res);
@@ -239,10 +239,10 @@ DEF_FPU_SEM(DoFCOS) {
239239
SetFPUIpOp();
240240
auto st0 = Read(X87_ST0);
241241
state.sw.ie |= IsSignalingNaN(st0) | IsInfinite(st0);
242-
state.sw.de = IsDenormal(st0);
242+
state.sw.de |= IsDenormal(st0);
243243
auto res = CheckedFloatUnaryOp(state, FCos80, st0);
244244
if (!IsNaN(res)) {
245-
state.sw.pe = IsImprecise(res);
245+
state.sw.pe |= IsImprecise(res);
246246
}
247247
Write(X87_ST0, res);
248248
return memory;
@@ -252,7 +252,7 @@ DEF_FPU_SEM(DoFSIN) {
252252
SetFPUIpOp();
253253
auto st0 = Read(X87_ST0);
254254
state.sw.ie |= IsSignalingNaN(st0) | IsInfinite(st0);
255-
state.sw.de = IsDenormal(st0);
255+
state.sw.de |= IsDenormal(st0);
256256
auto res = CheckedFloatUnaryOp(state, FSin80, st0);
257257
if (!IsNaN(res)) {
258258
state.sw.pe = IsImprecise(res);
@@ -265,7 +265,7 @@ DEF_FPU_SEM(DoFPTAN) {
265265
SetFPUIpOp();
266266
auto st0 = Read(X87_ST0);
267267
state.sw.ie |= IsSignalingNaN(st0) | IsInfinite(st0);
268-
state.sw.de = IsDenormal(st0);
268+
state.sw.de |= IsDenormal(st0);
269269
auto res = CheckedFloatUnaryOp(state, FTan80, st0);
270270
if (!IsNaN(res)) {
271271
state.sw.pe = IsImprecise(res);
@@ -302,7 +302,7 @@ DEF_FPU_SEM(DoFSQRT) {
302302
Write(X87_ST0, st0);
303303
} else {
304304
state.sw.ie |= IsSignalingNaN(st0) | IsNegative(st0);
305-
state.sw.de = IsDenormal(st0);
305+
state.sw.de |= IsDenormal(st0);
306306
auto res = CheckedFloatUnaryOp(state, FSqrt80, st0);
307307
if (!IsNaN(res)) {
308308
state.sw.pe = IsImprecise(res);
@@ -316,7 +316,7 @@ DEF_FPU_SEM(DoFSINCOS) {
316316
SetFPUIpOp();
317317
auto st0 = Read(X87_ST0);
318318
state.sw.ie |= IsSignalingNaN(st0) | IsInfinite(st0);
319-
state.sw.de = IsDenormal(st0);
319+
state.sw.de |= IsDenormal(st0);
320320
auto sin_res = CheckedFloatUnaryOp(state, FSin80, st0);
321321
auto cos_res = CheckedFloatUnaryOp(state, FCos80, st0);
322322
if (!IsNaN(sin_res) && !IsNaN(cos_res)) {
@@ -339,7 +339,7 @@ DEF_FPU_SEM(DoF2XM1) {
339339
SetFPUIpOp();
340340
auto st0 = Read(X87_ST0);
341341
state.sw.ie |= IsSignalingNaN(st0) | IsInfinite(st0);
342-
state.sw.de = IsDenormal(st0);
342+
state.sw.de |= IsDenormal(st0);
343343
state.sw.ue = 0; // TODO(pag): Not sure.
344344
auto res = FSub(Float80(Exp2(st0)), Float80(1.0));
345345
if (!IsNaN(res)) {
@@ -392,6 +392,18 @@ DEF_SEM(DoFWAIT) {
392392

393393
DEF_SEM(DoFNCLEX) {
394394
feclearexcept(FE_ALL_EXCEPT);
395+
state.sw.pe = 0;
396+
state.sw.ue = 0;
397+
state.sw.oe = 0;
398+
state.sw.ze = 0;
399+
state.sw.de = 0;
400+
state.sw.ie = 0;
401+
402+
state.sw.c0 = UUndefined8();
403+
state.sw.c1 = UUndefined8();
404+
state.sw.c2 = UUndefined8();
405+
state.sw.c3 = UUndefined8();
406+
395407
return memory;
396408
}
397409

@@ -998,7 +1010,7 @@ DEF_FPU_SEM(DoFXAM) {
9981010
}
9991011

10001012
DEF_HELPER(OrderedCompare, native_float80_t src1, native_float80_t src2)->void {
1001-
state.sw.de = IsDenormal(src1) | IsDenormal(src2);
1013+
state.sw.de |= IsDenormal(src1) | IsDenormal(src2);
10021014
state.sw.ie = 0;
10031015

10041016
if (__builtin_isunordered(src1, src2)) {
@@ -1024,7 +1036,7 @@ DEF_HELPER(OrderedCompare, native_float80_t src1, native_float80_t src2)->void {
10241036
}
10251037

10261038
DEF_HELPER(UnorderedCompare, native_float80_t src1, native_float80_t src2)->void {
1027-
state.sw.de = IsDenormal(src1) | IsDenormal(src2);
1039+
state.sw.de |= IsDenormal(src1) | IsDenormal(src2);
10281040
state.sw.ie = 0;
10291041

10301042
if (__builtin_isunordered(src1, src2)) {
@@ -1146,7 +1158,7 @@ DEF_FPU_SEM(DoFCOMPP) {
11461158
}
11471159

11481160
DEF_HELPER(UnorderedCompareEflags, native_float80_t src1, native_float80_t src2)->void {
1149-
state.sw.de = IsDenormal(src1) | IsDenormal(src2);
1161+
state.sw.de |= IsDenormal(src1) | IsDenormal(src2);
11501162
state.sw.ie = 0;
11511163

11521164
if (__builtin_isunordered(src1, src2)) {
@@ -1173,7 +1185,7 @@ DEF_HELPER(UnorderedCompareEflags, native_float80_t src1, native_float80_t src2)
11731185
}
11741186

11751187
DEF_HELPER(OrderedCompareEflags, native_float80_t src1, native_float80_t src2)->void {
1176-
state.sw.de = IsDenormal(src1) | IsDenormal(src2);
1188+
state.sw.de |= IsDenormal(src1) | IsDenormal(src2);
11771189
state.sw.ie = 0;
11781190

11791191
if (__builtin_isunordered(src1, src2)) {
@@ -1328,7 +1340,7 @@ DEF_FPU_SEM(DoFRNDINT) {
13281340
auto st0 = Read(X87_ST0);
13291341
auto rounded = FRoundUsingMode(st0);
13301342
state.sw.ie |= IsSignalingNaN(st0);
1331-
state.sw.de = IsDenormal(st0);
1343+
state.sw.de |= IsDenormal(st0);
13321344
if (!IsNaN(rounded)) {
13331345
state.sw.pe = st0 != rounded;
13341346
}

tests/X86/X87/FCOM.S

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ TEST_INPUTS(TEST_INPUTS_MMX_QWORD)
7575
fcomi st(2)
7676
TEST_END_64
7777

78+
TEST_BEGIN_64(FCOMIst0st2_CE, 2)
79+
TEST_INPUTS(TEST_INPUTS_MMX_QWORD)
80+
push ARG1_64
81+
fld QWORD PTR [rsp]
82+
push ARG2_64
83+
fld QWORD PTR [rsp]
84+
push ARG2_64
85+
fld QWORD PTR [rsp]
86+
fnclex
87+
fcomi st(2)
88+
TEST_END_64
89+
7890
TEST_BEGIN_64(FCOMIPst0st2, 2)
7991
TEST_INPUTS(TEST_INPUTS_MMX_QWORD)
8092
push ARG1_64

tests/X86/X87/MISC.S

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,40 @@ TEST_INPUTS(
270270
ftst
271271
TEST_END_64
272272

273+
TEST_BEGIN_64(FTST_1, 2)
274+
TEST_INPUTS(
275+
0x8008000000000000, 0x7ff8000000000000,
276+
0x7ff8000000000000, 0x8008000000000000)
277+
push ARG1_64
278+
fld QWORD PTR [rsp]
279+
push ARG2_64
280+
fld QWORD PTR [rsp]
281+
ftst
282+
TEST_END_64
283+
284+
TEST_BEGIN_64(FTST_CE, 1)
285+
TEST_INPUTS(
286+
QNAN_64,
287+
SNAN_64,
288+
0x7ff0000000000000, /* +inf */
289+
0xfff0000000000000, /* -inf */
290+
0xfff8000000000000, /* -nan */
291+
0x7ff8000000000000, /* nan */
292+
0x0010000000000000, /* std::numeric_limits<double>::min() */
293+
0x7fefffffffffffff, /* std::numeric_limits<double>::max() */
294+
0x0008000000000000, /* std::numeric_limits<double>::min() / 2.0 */
295+
0x8008000000000000, /* std::numeric_limits<double>::min() / -2.0 */
296+
0x0000000000000000, /* +0 */
297+
0x8000000000000000, /* -0 */
298+
0x3fe0000000000000, /* 0.5 */
299+
0xbfe0000000000000) /* -0.5 */
300+
301+
push ARG1_64
302+
fld QWORD PTR [rsp]
303+
fnclex
304+
ftst
305+
TEST_END_64
306+
273307
TEST_BEGIN_64(FRNDINT, 1)
274308
TEST_INPUTS(
275309
QNAN_64,

0 commit comments

Comments
 (0)