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

Value type improvements #423

Merged
merged 3 commits into from
Jul 30, 2020
Merged

Value type improvements #423

merged 3 commits into from
Jul 30, 2020

Conversation

chfast
Copy link
Collaborator

@chfast chfast commented Jul 15, 2020

Depends on #419

@chfast chfast requested review from axic and gumb0 July 15, 2020 16:39
@gumb0
Copy link
Collaborator

gumb0 commented Jul 15, 2020

macOS builds failed

@chfast
Copy link
Collaborator Author

chfast commented Jul 16, 2020

macOS builds failed

It looks on macOS the uint64_t is unsigned long long so we need more overloads.

@codecov
Copy link

codecov bot commented Jul 16, 2020

Codecov Report

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

@@           Coverage Diff           @@
##           master     #423   +/-   ##
=======================================
  Coverage   99.54%   99.54%           
=======================================
  Files          51       51           
  Lines       14632    14663   +31     
=======================================
+ Hits        14565    14596   +31     
  Misses         67       67           

@chfast chfast force-pushed the value_type_cleanup branch from 246fdf8 to dc41d64 Compare July 16, 2020 12:10
@chfast chfast force-pushed the value_type branch 3 times, most recently from df0ceb4 to 399b2c3 Compare July 30, 2020 07:35
@chfast chfast force-pushed the value_type_cleanup branch from dc41d64 to 068f218 Compare July 30, 2020 14:52
using T = decltype(op(stack.top(), stack.top()));
const auto val2 = static_cast<T>(stack.pop());
const auto val1 = static_cast<T>(stack.top());
stack.top() = static_cast<std::make_unsigned_t<T>>(op(val1, val2));
Copy link
Collaborator

Choose a reason for hiding this comment

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

How come make_unsigned is not needed anymore? I think it was need for signed 32-bit operations, where without it it would incorrectly extend the sign to 64 bit.

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 think now constructor Value(int32_t v) does this.

Copy link
Member

Choose a reason for hiding this comment

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

Is it better to have it in the constructor or make it more explicit here? From a reader's perspective explicitness here is nice.

Do we recall the test case while it had to be converted between signed/unsigned in this function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

All "signed integer" instructions relay on this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think I like it better when Value itself encapsulates correct conversion int32_t->Value.

make_unsigned_t here looked to me more like a hack to handle an edge case...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could make the conversions from signed integers explicit. This is manageable in interpreter implementation, but inconvenient in tests and examples. I.e. all invokes with example {0, 1, 2} stops working (as naked integer literal is of type int) and you have to use {0u, 1u, 2u}.

Personally, I would leave it as is for now. And we can review Value type design after having floating point type in. And possibly i32 fields as well.

Copy link
Member

Choose a reason for hiding this comment

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

I'm fine keeping it this way but would prefer a simple comment that the result can be signed or unsigned and its conversion is handled in Value.

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 comments and used Value explicitly (no implicit conversion although available).

Copy link
Member

Choose a reason for hiding this comment

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

Hope it did not change runtimes lol.

@@ -13,8 +13,19 @@ union Value
uint64_t i64;

Value() = default;
constexpr Value(uint64_t v) noexcept : i64{v} {}
constexpr Value(unsigned int v) noexcept : i64{v} {}
Copy link
Collaborator

@gumb0 gumb0 Jul 30, 2020

Choose a reason for hiding this comment

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

Maybe a comment why we need these unsigned constuctors?

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of having 5 constructor for ints + deleted constructors, I can do all of that with a template constructor with some enable_if and some other magic. But I'm not sure we want that now. Maybe it's better to wait for floats before more cleanups.

Base automatically changed from value_type to master July 30, 2020 15:23
@chfast chfast force-pushed the value_type_cleanup branch 3 times, most recently from 54cd311 to 21a8bbe Compare July 30, 2020 16:38
@chfast chfast requested a review from gumb0 July 30, 2020 16:38
const auto status =
fizzy::execute(*m_instance, static_cast<uint32_t>(func_ref), {first_arg, args.size()});
const auto status = fizzy::execute(
*m_instance, static_cast<uint32_t>(func_ref), span<const Value>(first_arg, args.size()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this change required?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. Otherwise compiler thinks these are two values: first_arg -> bool -> Value and args.size() -> size_t -> Value.

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. Fo first_arg it's probably pointer to integer conversion, rather than bool, I think bool -> Value doesn't work anymore, you deleted the tests for it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Without the change it resolves overloading to Value(bool) what gives the compilation error (as this constructor is deleted).

@@ -1014,7 +1014,7 @@ ExecutionResult execute(Instance& instance, FuncIdx func_idx, span<const Value>
case Instr::i32_eqz:
{
const auto value = static_cast<uint32_t>(stack.pop());
stack.push(value == 0);
stack.push(uint32_t{value == 0});
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to make this clear? I know eqz returns 32-bit but we said we don't care because it is a union.

Copy link
Member

Choose a reason for hiding this comment

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

Does this have any effect on speed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The Value(bool) is deleted to avoid some surprises. So the bool expression must be converted to uint32_t (or uint64_t, but uint32_t seems nicer).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Does this have any effect on speed?

Nope.

@chfast chfast force-pushed the value_type_cleanup branch from 21a8bbe to d90f329 Compare July 30, 2020 17:19
@chfast
Copy link
Collaborator Author

chfast commented Jul 30, 2020

Cleaned up the git history.

@chfast
Copy link
Collaborator Author

chfast commented Jul 30, 2020

Benchmarks (no change):

fizzy/execute/blake2b/512_bytes_rounds_1_mean                     +0.0011         +0.0011            87            87            87            87
fizzy/execute/blake2b/512_bytes_rounds_16_mean                    +0.0006         +0.0006          1310          1311          1310          1311
fizzy/execute/ecpairing/onepoint_mean                             +0.0039         +0.0039        429238        430925        429239        430929
fizzy/execute/keccak256/512_bytes_rounds_1_mean                   -0.0056         -0.0056           105           104           105           104
fizzy/execute/keccak256/512_bytes_rounds_16_mean                  -0.0089         -0.0089          1530          1517          1530          1517
fizzy/execute/memset/256_bytes_mean                               -0.0033         -0.0033             7             7             7             7
fizzy/execute/memset/60000_bytes_mean                             +0.0004         +0.0004          1610          1610          1610          1610
fizzy/execute/mul256_opt0/input0_mean                             +0.0010         +0.0010            27            27            27            27
fizzy/execute/mul256_opt0/input1_mean                             +0.0015         +0.0015            27            27            27            27
fizzy/execute/sha1/512_bytes_rounds_1_mean                        -0.0011         -0.0011            95            95            95            95
fizzy/execute/sha1/512_bytes_rounds_16_mean                       +0.0004         +0.0004          1323          1324          1323          1324
fizzy/execute/sha256/512_bytes_rounds_1_mean                      +0.0064         +0.0064            99           100            99           100
fizzy/execute/sha256/512_bytes_rounds_16_mean                     +0.0025         +0.0025          1377          1380          1377          1380
fizzy/execute/micro/eli_interpreter/halt_mean                     +0.0018         +0.0018             0             0             0             0
fizzy/execute/micro/eli_interpreter/exec105_mean                  -0.0022         -0.0022             5             5             5             5
fizzy/execute/micro/factorial/10_mean                             +0.0020         +0.0020             0             0             0             0
fizzy/execute/micro/factorial/20_mean                             -0.0211         -0.0211             1             1             1             1
fizzy/execute/micro/fibonacci/24_mean                             -0.0103         -0.0103          7253          7178          7253          7178
fizzy/execute/micro/host_adler32/1_mean                           -0.0016         -0.0016             0             0             0             0
fizzy/execute/micro/host_adler32/100_mean                         +0.0013         +0.0013             3             3             3             3
fizzy/execute/micro/host_adler32/1000_mean                        +0.0086         +0.0086            30            30            30            30
fizzy/execute/micro/spinner/1_mean                                -0.0060         -0.0061             0             0             0             0
fizzy/execute/micro/spinner/1000_mean                             -0.0004         -0.0004            10            10            10            10

const auto val2 = static_cast<T>(stack.pop());
const auto val1 = static_cast<T>(stack.top());
stack.top() = static_cast<std::make_unsigned_t<T>>(op(val1, val2));
using T = decltype(op({}, {}));
Copy link
Member

Choose a reason for hiding this comment

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

Hm, what does this do with {}, {}?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The {} in f(T) more/less mean "construct the required type T with default constructor".

E.g. The void func(void*, Options, vector<int>, int) can be invoked as func(nullptr, {}, {}, 0) or even func({}, {}, {}, {}).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I get that, but in the case of op, which is std::add, std::sub, etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well, op is an instance of e.g. std::add<uint64_t>{} which has operator() overloaded so op(...) expression is valid. The decltype gets the type of this expression.

Copy link
Member

Choose a reason for hiding this comment

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

Okay so this line change is not related to the current PR. Could have been like this prior.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. The {} could have been use instead of stack.top() before. But now this simplifications is required as stack.top() has wrong type in general.

@chfast chfast force-pushed the value_type_cleanup branch from d90f329 to accd4b2 Compare July 30, 2020 19:25
@chfast chfast merged commit 40c459e into master Jul 30, 2020
@chfast chfast deleted the value_type_cleanup branch July 30, 2020 20:05
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