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

Separate safe and unsafe math operations #1395

Merged
merged 1 commit into from
Jan 25, 2017
Merged

Conversation

Praetonus
Copy link
Member

As discussed in #993.


Mathematic and logical operations are now fully defined by default for every input. This change includes:

  • Numeric conversions from/to floating point saturate if the value doesn't fit in the destination type
  • Signed integer division returns 0 on overflow (e.g. I8(-128) / -1)
  • Left shift by more bits than the type width returns 0
  • Logical (unsigned) right shift by more bits than the type width returns 0
  • Arithmetic (signed) right shift by more bits than the type width extends the sign bit on the low bits
  • Left and right bit rotate work correctly for amounts greater than the type width
  • Signed rotate is removed
  • Shift and rotate now take an unsigned amount as argument
  • popcount, clz, ctz and bitwidth now always have an unsigned return type

Add unsafe operations that can have undefined results for some inputs but can be faster and allow better optimisations. Unsafe functions are suffixed with _unsafe. This change includes:

  • Unsafe numeric conversions. If the value doesn't fit in the destination type, the result is undefined
  • Unsafe addition, substraction, multiplication and negation. For integers, the result is undefined on overflow. For floating points, fast math semantics are enabled
  • Unsafe division and modulus. For integers, the result is undefined on division/modulus by 0. For floating points, fast math semantics are enabled
  • Unsafe left shift. On overflow, the result is undefined
  • Unsafe right shift. If non-zero bits are shifted out, the result is undefined
  • Unsafe floating point comparisons. Fast math semantics are enabled
  • Unsafe square root. If the operand is negative, the result is undefined. Fast math semantics are enabled
  • Unsafe clz/ctz. If the operand is 0, the result is undefined.

Fast math semantics mean that the result is undefined if the computation involves NaN and/or +/- infinity. In addition, full compliance to IEEE-754 isn't required.

For reference, the semantics of undefined results and of the associated as-if rule are defined as follows.

As-if rule

The compiler is permitted to perform any changes to the program as long as the following remains true for every behaviour in the program.

  • At the end of a behaviour, the associated actor is exactly in the state it would be if the program was executed as written
  • If an object has a finaliser, that finaliser will eventually be called exactly once
  • Messages are sent as if the behaviour was executed as written, in the same order and with the same contents.
  • FFI calls to well-defined C functions are executed as written, in the same order and with the same arguments. The runtime functions (every function prefixed with pony_) are free from this rule and from the following one.
  • Message sends and FFI calls are not reordered with respect to each other.
  • Capability security (both object capability and reference capability) is maintained.

Undefined results

If an expression with undefined results is evaluated:

  • Every subsequent expression depending on udefined result also has undefined results.
  • If the constructor of an object with a finaliser has undefined results, that finaliser isn't guaranteed to be called.
  • If a message send or a FFI call has undefined results, it is free from the as-if rule.
  • The implementation is allowed to generate platform-specific exceptions (which are not Pony exceptions).
  • Capability security is always maintained.

@jemc
Copy link
Member

jemc commented Nov 5, 2016

Can we take this opportunity to also add some arithmetic tests corresponding to the semantics that were ironed out?

Obviously we can't test for undefined behaviour but at least we can test key parts of the defined domain of these functions.

@Praetonus
Copy link
Member Author

You're right. I'll add that.

@Praetonus
Copy link
Member Author

I also forgot to update the pony.g file. I'll fix that.

@Praetonus
Copy link
Member Author

The build failed with an assertion failure on OSX and I don't really see what could be wrong. Could somebody on OSX try running the compiler with the code here and see if the assertion failure occurs? If it does, a debugger call stack trace would be great to identify the problem.

@malthe
Copy link
Contributor

malthe commented Nov 8, 2016

@Praetonus the code that triggers the failure on OS X is:

class iso _TestNumberConversionSaturation is UnitTest
  ...
  fun float_to_ints[A: (Float & Real[A])](h: TestHelper) =>
    float_to_int[A, I8](h)
    float_to_int[A, I16](h)
    float_to_int[A, I32](h)
    float_to_int[A, I64](h)
    float_to_int[A, ILong](h)
    float_to_int[A, ISize](h)
    float_to_int[A, I128](h)

The unsigned counterparts don't cause trouble.

@Praetonus
Copy link
Member Author

Praetonus commented Nov 8, 2016

@malthe Thanks. I think I figured it out. Nope, it wasn't that. I really don't understand. The failure occurred after I modified something in the handling of U128, and according to the generated IR, I128 isn't using that code path.

@SeanTAllen
Copy link
Member

Can anyone with OSX grab this PR and run it in a debugger to get a stack trace for @Praetonus?

I might be able to do it in a couple weeks but I can't until a work project is finished.

@SeanTAllen
Copy link
Member

CHANGELOG was updated for 0.9.0 release. This will need to be rebased to pick up those changes and verify the CHANGELOG entries are correctly in the "unreleased" section

@Theodus
Copy link
Contributor

Theodus commented Dec 13, 2016

CHANGELOG update for 0.10.0 release means that you will need to rebase verify the entries are correctly in the "unreleased" section.

@Praetonus
Copy link
Member Author

I think I found the problem in this. I also updated the changelog entry, this should be ready for review & merge if CI passes.

@Praetonus
Copy link
Member Author

Note that this change will probably have some (quite small, I think) performance impact on the standard library. I'll make a followup PR to use unsafe maths in the standard library where function contracts guarantee it won't explode, so that we can minimise that performance loss.

@Praetonus
Copy link
Member Author

Rebased to catch up changes to the changelog.

@Praetonus
Copy link
Member Author

Conflicts resolved.

@SeanTAllen
Copy link
Member

Is this good to merge @Praetonus?

@Praetonus
Copy link
Member Author

Yes, I think it is.

Mathematic and logical operations are now fully defined by default for
every input. This change includes:

- Numeric conversions from/to floating point saturate if the value
  doesn't fit in the destination type
- Signed integer division returns 0 on overflow (e.g. I8(-128) / -1)
- Left shift by more bits than the type width returns 0
- Logical (unsigned) right shift by more bits than the type width
  returns 0
- Arithmetic (signed) right shift by more bits than the type width
  extends the sign bit on the low bits
- Left and right bit rotate work correctly for amounts greater than the
  type width
- Signed rotate is removed
- Shift and rotate now take an unsigned amount as argument
- popcount, clz, ctz and bitwidth now always have an unsigned return
  type

Add unsafe operations that can have undefined results for some inputs
but can be faster and allow better optimisations. Unsafe functions are
suffixed with _unsafe. This change includes:

- Unsafe numeric conversions. If the value doesn't fit in the
  destination type, the result is undefined
- Unsafe addition, substraction, multiplication and negation. For
  integers, the result is undefined on overflow. For floating points,
  fast math semantics are enabled
- Unsafe division and modulus. For integers, the result is undefined
  on division/modulus by 0. For floating points, fast math semantics
  are enabled
- Unsafe left shift. On overflow, the result is undefined
- Unsafe right shift. If non-zero bits are shifted out, the result is
  undefined
- Unsafe floating point comparisons. Fast math semantics are enabled
- Unsafe square root. If the operand is negative, the result is
  undefined
- Unsafe clz/ctz. If the operand is 0, the result is undefined

Fast math semantics mean that the result is undefined if the
computation involves NaN and/or +/- infinity. In addition, full
compliance to IEEE-754 isn't required.

For reference, the semantics of undefined results and of the associated
as-if rule are defined as follows.

As-if rule

The compiler is permitted to perform any changes to the program as long
as the following remains true for every behaviour in the program.

- At the end of a behaviour, the associated actor is exactly in the
  state it would be if the program was executed as written
- If an object has a finaliser, that finaliser will eventually be
  called exactly once
- Messages are sent as if the behaviour was executed as written, in the
  same order and with the same contents
- FFI calls to well-defined C functions are executed as written, in the
  same order and with the same arguments. The runtime functions (every
  function prefixed with pony_) are free from this rule and from the
  following one
- Message sends and FFI calls are not reordered with respect to each
  other
- Capability security (both object capability and reference capability)
  is maintained

Undefined results

If an expression with undefined results is evaluated:

- Every subsequent expression depending on udefined result also has
  undefined results
- If the constructor of an object with a finaliser has undefined
  results, that finaliser isn't guaranteed to be called
- If a message send or a FFI call has undefined results, it is free
  from the as-if rule
- The implementation is allowed to generate platform-specific
  exceptions (which are not Pony exceptions)
- Capability security is always maintained
@Praetonus
Copy link
Member Author

Conflicts resolved.

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.

6 participants