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

fix operators containing percent for VM usage #13536

Merged
merged 11 commits into from
Mar 11, 2020

Conversation

krux02
Copy link
Contributor

@krux02 krux02 commented Feb 28, 2020

Short explanation, in the VM signed numbers are stored with an extended sign. Unsigned numbers do not have a sign and therefore no sign extension. Applying unsigned operations on numbers with with sign extensions will have different results than without those extensions. Also unsigned ops do not apply sign extension afterwards, even though signed numbers require the sign extension. The casting operations introduced in this PR will do the sign extension removal and reintroduction for the VM accordingly. For runtime behavior, casting is a noop and should not affect performance.

fixes #13513

@krux02 krux02 changed the title fix #13513 fix operators containing percent for VM usage Feb 29, 2020
@krux02
Copy link
Contributor Author

krux02 commented Feb 29, 2020

Somehow there is a breaking test. This is what breaks, but it also breaks on devel. But it would mean that the development branch is broken.

import times

echo parse("1", "YYYY", utc())

@timotheecour
Copy link
Member

BTW I am too lazy to add a test right now.

just copy the one I wrote here: https://github.com/nim-lang/Nim/pull/13532/files#diff-750bc0bcbc3193d1a2854eed2d5ec5d1

@krux02
Copy link
Contributor Author

krux02 commented Feb 29, 2020

@timotheecour Thanks for the help, but that test isn't suitable. I am circumventing to fix semfold for +%, so I don't special case testing for it. Also I am not just fixing +% in isolation. There is a problem with all % operators. So I need to test all of them. But if you care, your test does pass on my machine.

@@ -17,17 +17,17 @@ proc add[T](x: var seq[T]; y: openArray[T])
first type mismatch at position: 1
required type for x: var seq[T]
but expression 'k' is of type: Alias
proc add(result: var string; x: float)
proc add(x: var string; y: cstring)
Copy link
Member

@timotheecour timotheecour Feb 29, 2020

Choose a reason for hiding this comment

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

no action needed here but I see this kind of thing break a lot (where ordering is changed), may be good to start sorting sigmatch errors in compiler by some reliable criterion (simplest would be raw string sort) to avoid having to edit tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea it is annoying. But I don't know what the cause it. Is it that I changed some definitions that symbols get a different order when iterating them? Or is it because I introduce a bug into +% so that hash values are calculated differently? Or did I fix +% and hash values are calculated differently? I don't know. I am worried because I don't understand it.

Copy link
Member

Choose a reason for hiding this comment

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

not sure about the other points raised but I'm tracking this specific issue here #13538


template `>=%`*(x, y: untyped): untyped = y <=% x
proc `>=%`*(x, y: int): bool {.inline.} =
Copy link
Member

Choose a reason for hiding this comment

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

  • instead of introducing all those overloads (previous code had a single template for >=%) use this:
template `>=%`*[T](x, y: T): untyped = y <=% x
  • ditto with >%

@timotheecour
Copy link
Member

timotheecour commented Feb 29, 2020

The implementation that uses a proc instead of a magic might cause slower performance on non optimized builds.

from reading your diff, seems like performance impact should only be for VM, not RT, can you confirm?
As for VM performance for such ops, may be good to do a quick benchmark to see what's the damage.
If VM performance isn't negatively affected, getting rid of VM specific code sounds like a very nice cleanup

  • you can remove dead code that's introduced in this PR, eg if mLeU64 is no longer used, these:
compiler/ast.nim:617:6:    mLeU64, mLtU64,
compiler/ast.nim:687:6:    mLeU64, mLtU64,
compiler/ccgexprs.nim:608:7:  of mLeU64: applyFormat("((NU64)($1) <= (NU64)($2))")
compiler/forloops.nim:16:42:    mEqUntracedRef, mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
compiler/guards.nim:20:34:  someLe = {mLeI, mLeF64, mLeU, mLeU64, mLeEnum,
compiler/jsgen.nim:579:7:  of mLeU64: applyFormat("($1 <= $2)", "($1 <= $2)")
compiler/semfold.nim:294:13:  of mLeU, mLeU64:
compiler/vmgen.nim:1081:21:  of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)

ditto with mLtU64 etc

@krux02
Copy link
Contributor Author

krux02 commented Mar 1, 2020

This is the test that you can execute to verify that here is a problem to fix.

proc testUnsignedOps() =
  let a: int8 = -128
  let b: int8 = 127

  echo toHex(cast[uint16](b +% 1))
  echo toHex(cast[uint16](b -% -1))
  echo toHex(cast[uint16](b *% 2))
  echo toHex(cast[uint16](a /% 4))
  echo toHex(cast[uint16](a %% 7))

testUnsignedOps()
static:
  testUnsignedOps()

@krux02 krux02 requested a review from Araq March 1, 2020 13:21
@krux02
Copy link
Contributor Author

krux02 commented Mar 1, 2020

Test failure is unrelated.

mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"],
mFloatToStr: ["cstrToNimstr", "cstrToNimstr"],
mCStrToStr: ["cstrToNimstr", "cstrToNimstr"],
mStrToStr: ["", ""]]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had to remove the mMeU64 and mLtU64. Since I was already at it. I converted the comments of the array into proper named array members.

@Araq
Copy link
Member

Araq commented Mar 3, 2020

I'd be happier with templates instead of inline procs as inline procs are currently not inlined in debug builds. Also you seem to mix refactorings with bugfixes which makes everything harder and slower to review.

@timotheecour
Copy link
Member

timotheecour commented Mar 3, 2020

I'd be happier with templates instead of inline procs as inline procs are currently not inlined in debug builds

then maybe that should be fixed instead ? IMO {.inline.} procs should inline in debug builds (ie without -d:release), but we could have an option --nimIgnoreInline to ignore {.inline.}
no strong opinion either way

@krux02
Copy link
Contributor Author

krux02 commented Mar 3, 2020

I'd be happier with templates instead of inline procs as inline procs are currently not inlined in debug builds.

I can do it if you say that is how it should be done.

Also you seem to mix refactorings with bugfixes which makes everything harder and slower to review.

I only mix in those refactoring that are structurally integrated with the bugfixes. The other refactorings are part of my other already merged PR here: #13551

But please don't expect me to like this splitting of the contribution. I only do it to do you a favor. But for me it means that the amount of time that I have to deal the slow CI the review process is doubled. And then when when one of the PRs is merged I usually get merge conflics as the bug fixes and refactorings can't be separated perfectly. So I have to deal with the CI yet another time.

@timotheecour
Copy link
Member

  • in this particular case I feel like those refactorings are directly related to the bugfix so it wouldn't make sense to split in 2 PRs
  • in other similar cases though, there's a better way than splitting in 2 PRs PR1,PR2 (and having to deal with a lot of overhead work on the side of the contributor especially when PR1 needs to address review comment which then affects PR2):
    simply make sure there are refactoring-only commits and bugfix-only commits (and if neeed, add a note to reviewer to that effect); and if a change needs to be addressed, use the usual git rebase -i HEAD~4

it results in much less overhead on side of contributor than splitting in PR's.

@Araq
Copy link
Member

Araq commented Mar 3, 2020

MO {.inline.} procs should inline in debug builds (ie without -d:release), but we could have an option --nimIgnoreInline to ignore {.inline.}

Agreed, let's hope __always_inline (or whatever it is called) is portable enough...

@timotheecour
Copy link
Member

timotheecour commented Mar 3, 2020

Agreed, let's hope __always_inline (or whatever it is called) is portable enough...

=> let's discuss this in nim-lang/RFCs#198

I'd be happier with templates instead of inline procs as inline procs are currently not inlined in debug builds

that's not what I'm seeing, see nim-lang/RFCs#198: cgen generates
static N_INLINE(NI, fun2x__rxUfcN4ZvcApCx0waSVH8At10303b)(NI a) {. regardless of -d:danger or not,

however:

@Araq Araq merged commit 2f55765 into nim-lang:devel Mar 11, 2020
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.

Compiler creates invalid out-of-range int8 constants.
3 participants