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

Incorrect semantic computation for MULX when first and second argument are same #525

Closed
basavesh opened this issue Jul 16, 2023 · 11 comments · Fixed by #531
Closed

Incorrect semantic computation for MULX when first and second argument are same #525

basavesh opened this issue Jul 16, 2023 · 11 comments · Fixed by #531

Comments

@basavesh
Copy link
Collaborator

Found through random fuzz-test. this is true for both size variants of 32 and 64.
Bug: When the first and second argument are same, Jasmin semantics and hardware semantics differ.

If the first and second operand are identical, it will contain the high half of the multiplication result.

Size=64
Executing instruction MULX R14 R14 RDI -> mulxq %rdi, %r14, %r14
Before:

RDI: 12585089653095806027
R14: 3958074007382419651

Jasmin After:

R14: 37409020628164682

H/W After:

r14 = 7136978533371468338

Size = 32
Executing instruction MULX_32 R14 R14 RDI -> mulxl %edi, %r14d, %r14d

Before:

RDI: 13977003853042703850
R14: 17852321287948986267

Jasmin After:

R14: 3375765496

H/W After:

r14 = 915477969

CC: @vbgl @bgregoir @gbarthe @cryptojedi

@vbgl
Copy link
Member

vbgl commented Jul 17, 2023

Thanks for finding and reporting this issue. Might it be that the results are written (in the semantics) in the wrong order, so that the low half overwrites the high half?

I think that the compiler cannot produce code that witnesses this error: the liveness analysis used during register allocation is not precise enough.

@basavesh
Copy link
Collaborator Author

That is possible. However, I don't think I saw a special case when the 1st and 2nd arguments are same.
As you suggested, it might be a better idea to simply write the high half later to deal with this special case.

@bgregoir
Copy link
Contributor

Just to resume, the discussion with Vincent. We are agree that this is a bug in the semantics.
There is a simple way to fix it, say that mulx return (lo, hi) instead of (hi, lo). In that case the pb is solve but
this require to fix the jasmin program, and certainly to do the same kind of change for similar instructions.
like (hi, lo) = x * y --> (lo, hi) = x * y.
The EC model need to be changed to.
So we think it is not reasonable...
The other way to fix it is to ensure that the semantic reject such a program were both destination are equals.
So the semantics will be incomplete compare to the architecture but it is correct.
In any case, the compiler never generate code where both destination are the same register. Both destination are marked to be in conflict.
But maybe this can change in the future

@cryptojedi
Copy link
Contributor

cryptojedi commented Jul 17, 2023 via email

@vbgl
Copy link
Member

vbgl commented Jul 17, 2023

It is already the case that the compiler cannot emit code that witness the bug: two outputs of an instruction are considered live after this instruction, hence conflict, i.e., cannot be allocated to the same register.

@basavesh
Copy link
Collaborator Author

So there is a room for improving the live analysis and maybe do better allocation in the future. (Depending on whether this instruction will help in some special case).

So, is it going to be a semantic bug which will not be fixed?

@basavesh
Copy link
Collaborator Author

According to me, a better and probably correct solution to implement in the future would be to track if those two registers are same and then return (hi, hi). I think this will faithfully implement the Intel semantics instead of writing high later hack.

@bgregoir
Copy link
Contributor

I agree that the best solution will be to change the order of elements in the return (i.e. (lo,hi) instead of (hi,lo)).
The question is are we agree to pay the cost of this change.
@peter, I think the compiler will fail to generate code like (hi,hi) = #mulx(x,y) (I have not tested, I think this come from what was explained by Vincent). This does not means that it will still true in the futur.

@cryptojedi
Copy link
Contributor

cryptojedi commented Jul 18, 2023 via email

@bgregoir
Copy link
Contributor

It was the point of rejecting mulx r r, if this has no semantic if the compiler generates a mulx r r at some point
we will not be able to prove its correctness.
Any way, we discussed with Vincent, and we decided to do the following.
Add an instruction MULX_lo_hi (the current MULX return hi, lo), the compiler will emit a mulx
Add an instruction MULX_hi (return a single element) the compiler mulx hi hi ...
Keep the current MULX, the compiler will emit a warning that the instruction is deprecated.
(hi,lo) = #MULX(x,y) will be translated to (lo,hi) = #MULX_lo_hi(x,y) with a check that lo <> hi, else fail.
Once libjade is patched, we can remove MULX with a explicite failure instead of a warning.
A some point we can rename MULX_lo_hi into MULX (in 2 or 3 version of the compiler).

@bgregoir
Copy link
Contributor

Ok, I think the current solution will not require to do any change in libjade.

@basavesh basavesh linked a pull request Jul 19, 2023 that will close this issue
@vbgl vbgl closed this as completed in #531 Jul 19, 2023
vbgl pushed a commit that referenced this issue Jul 19, 2023
Add MULX_lo_hi and MULX_hi pseudo instructions.

Fixes #525
@vbgl vbgl removed the bug label Jul 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants