Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement f32.demote_f64 instruction #458

Merged
merged 3 commits into from
Aug 14, 2020
Merged

Implement f32.demote_f64 instruction #458

merged 3 commits into from
Aug 14, 2020

Conversation

chfast
Copy link
Collaborator

@chfast chfast commented Aug 4, 2020

image

@chfast chfast requested review from axic and gumb0 August 4, 2020 17:03
@chfast chfast force-pushed the fp_promote branch 6 times, most recently from 4fe85a3 to 6636ce0 Compare August 12, 2020 10:39
Base automatically changed from fp_promote to master August 12, 2020 13:51
@codecov
Copy link

codecov bot commented Aug 12, 2020

Codecov Report

Merging #458 into master will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff            @@
##           master     #458    +/-   ##
========================================
  Coverage   99.55%   99.55%            
========================================
  Files          54       54            
  Lines       16569    16685   +116     
========================================
+ Hits        16495    16611   +116     
  Misses         74       74            

@chfast chfast force-pushed the fp_demote branch 3 times, most recently from 7d8ad08 to b5cef53 Compare August 12, 2020 16:33
@chfast chfast force-pushed the fp_demote branch 2 times, most recently from a94bc35 to 111b100 Compare August 12, 2020 21:02
auto instance = instantiate(parse(wasm));

// The boundary input value that results in the infinity.
constexpr double lowest_to_inf = 0x1.ffffffp127;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused and might be wrong, but cases p > lowest_to_inf and p < -lowest_to_inf are missing, and I think they are undefined behavior in C++, but defined to result in infinities in wasm.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is defined if IEEE 754 is supported (as for some other cases) because then infinities also counts.

The minimum range of representable values for a floating type is the most negative finite floating-point number representable in that type through the most positive finite floating-point number representable in that type. In addition, if negative infinity is representable in a type, the range of that type is extended to all negative real numbers; likewise, if positive infinity is representable in a type, the range of that type is extended to all positive real numbers.

https://stackoverflow.com/a/25831946/725174

Although, I'm confused how to chose nearest value between max and infinity...

The cases you mentions are not present because lowest_to_inf already yields infinity, so for any p > lowest_to_inf we get infinity too. But I can add test for nextafter(lowest_to_inf).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This answers my question.

In the default IEEE 754 round-to-nearest mode, a few double values above the maximum finite float (that is, FLT_MAX) convert to FLT_MAX. The exact limit is the number midway between FLT_MAX (0x1.fffffep127 in C99 hexadecimal representation) and the next float number that could be represented if the exponent in the single-precision format had a larger range, 0x2.0p127. The limit is thus 0x1.ffffffp127 or approximately 3.4028235677973366e+38 in decimal.

https://stackoverflow.com/a/17751145/725174

Although I wander where wasm spec handles this, if anywhere.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally have explanation for the lowest_to_inf value (see comments).
I also added two cases for p > lowest_to_inf.

@chfast chfast force-pushed the fp_demote branch 2 times, most recently from e59b743 to 6facac3 Compare August 13, 2020 20:07
@chfast chfast marked this pull request as draft August 14, 2020 07:30
@chfast chfast marked this pull request as ready for review August 14, 2020 08:21
constexpr double f32_limit = 0x1p128; // 2**128.

// The lower boundary input value that results in the infinity. The number is midway between
// f32_max and f32_limit. For this value rounding prefers infinity, because f32_limit is even.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand the last sentence. f32_limit would indeed be even if casted to int, but for floats there's no even/odd ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I guess it's about evenness of the mantissa part

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course there is (at least in Wasm spec).
image
In this case f32_limit is even by definition.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But still confused, mantissa of f32_max is even, manitssa of f32_limit is odd

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in both cases you are confused by the size of the f32 mantisa which is 23 bits. When written as 6 hex digits the last bit should always be 0. The mantissa full of ones is 1.fffffe (leading 1 is implicit). Then m = 0x7fffff and is odd.

The f32_limit is even by definition: even_N(+-limit_N) <=> true. But also mantissa of 1p128 is all zero therefore even.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, yes, I was confused by hex notation.

{-lowest_to_inf, -FP32::Limits::infinity()},

{std::nextafter(lowest_to_inf, FP64::Limits::infinity()), FP32::Limits::infinity()},
{-std::nextafter(lowest_to_inf, FP64::Limits::infinity()), -FP32::Limits::infinity()},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be

Suggested change
{-std::nextafter(lowest_to_inf, FP64::Limits::infinity()), -FP32::Limits::infinity()},
{std::nextafter(-lowest_to_inf, -FP64::Limits::infinity()), -FP32::Limits::infinity()},

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the same. floats has symmetrical positive and negative ranges.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to use only single variant consistently.

@chfast chfast force-pushed the fp_demote branch 2 times, most recently from 6014abe to 22adbb7 Compare August 14, 2020 09:54

EXPECT_THAT(execute(*instance, 0, {0x1.fffffefffffffp0}), Result(0x1.fffffep0f)); // round down
EXPECT_THAT(execute(*instance, 0, {0x1.fffffe0000000p0}), Result(0x1.fffffep0f)); // exact
EXPECT_THAT(execute(*instance, 0, {0x1.fffffd0000001p0}), Result(0x1.fffffep0f)); // round up
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maye also add the case with double value in the middle between two floats, to show tie-to-even

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

@@ -92,7 +92,7 @@ struct WasmTypeName
template <typename T>
class execute_floating_point_types : public testing::Test
{
protected:
public:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to access the list of NaNs from other test suite.

@chfast chfast force-pushed the fp_demote branch 2 times, most recently from b5159f4 to 28be58f Compare August 14, 2020 12:32
auto instance = instantiate(parse(wasm));

constexpr double f32_max = FP32::Limits::max();
ASSERT_EQ(f32_max, 0x1.fffffep127);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this assert here and not in limits? If here, can't this be made into a static_assert?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be. I just want to see what the value is.

// The lower boundary input value that results in the infinity. The number is midway between
// f32_max and f32_limit. For this value rounding prefers infinity, because f32_limit is even.
constexpr double lowest_to_inf = (f32_max + f32_limit) / 2;
ASSERT_EQ(lowest_to_inf, 0x1.ffffffp127);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really matter, but is there a reason this should assert_eq and not static_assert?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with static_assert, then decided that maybe it should build anyway even if not true. I guess static_assert may be less confusing for readers.

test/unittests/execute_floating_point_test.cpp Outdated Show resolved Hide resolved
{0x1.fffffd0000001p0, 0x1.fffffep0f}, // round up

{0x1.fffff8p0, 0x1.fffff8p0f}, // exact (even)
{(0x1.fffff8p0 + 0x1.fffffap0) / 2, 0x1.fffff8p0}, // tie-to-even down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{(0x1.fffff8p0 + 0x1.fffffap0) / 2, 0x1.fffff8p0}, // tie-to-even down
{(0x1.fffff8p0 + 0x1.fffffap0) / 2, 0x1.fffff8p0f}, // tie-to-even down

{0x1.fffff8p0, 0x1.fffff8p0f}, // exact (even)
{(0x1.fffff8p0 + 0x1.fffffap0) / 2, 0x1.fffff8p0}, // tie-to-even down
{0x1.fffffap0, 0x1.fffffap0f}, // exact (odd)
{(0x1.fffffap0 + 0x1.fffffcp0) / 2, 0x1.fffffcp0}, // tie-to-even up
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{(0x1.fffffap0 + 0x1.fffffcp0) / 2, 0x1.fffffcp0}, // tie-to-even up
{(0x1.fffffap0 + 0x1.fffffcp0) / 2, 0x1.fffffcp0f}, // tie-to-even up

@chfast chfast merged commit 439af1d into master Aug 14, 2020
@chfast chfast deleted the fp_demote branch August 14, 2020 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants