Jump to page: 1 2
Thread overview
GDC adds intrinsic support for core.checkedint
Jun 30, 2015
Iain Buclaw
Jun 30, 2015
Walter Bright
Jun 30, 2015
tsbockman
Jun 30, 2015
tsbockman
Jul 02, 2015
tsbockman
Jul 02, 2015
rsw0x
Jul 02, 2015
tsbockman
Jul 03, 2015
Timon Gehr
Jul 03, 2015
Timon Gehr
Jul 03, 2015
Tofu Ninja
Jul 03, 2015
rsw0x
Jul 03, 2015
Matthias Bentrup
Jul 03, 2015
Timon Gehr
Jul 01, 2015
Andrea Fontana
June 30, 2015
Hi,

GDC now recognizes all functions in core.checkedint as intrinsics.  May you all enjoy using inlined, hardware leveraged, overflow-checking integer operations.

https://github.com/D-Programming-GDC/GDC/pull/110

I say 'you all', but what I really mean is 'bearophile'. :-)

Regards
Iain.
June 30, 2015
On 6/30/2015 11:25 AM, Iain Buclaw wrote:
> GDC now recognizes all functions in core.checkedint as intrinsics.  May you all
> enjoy using inlined, hardware leveraged, overflow-checking integer operations.
>
> https://github.com/D-Programming-GDC/GDC/pull/110


Pretty dazz, Iain!
June 30, 2015
On Tuesday, 30 June 2015 at 18:25:14 UTC, Iain Buclaw wrote:
> Hi,
>
> GDC now recognizes all functions in core.checkedint as intrinsics.  May you all enjoy using inlined, hardware leveraged, overflow-checking integer operations.
>
> https://github.com/D-Programming-GDC/GDC/pull/110
>
> I say 'you all', but what I really mean is 'bearophile'. :-)
>
> Regards
> Iain.

core.checkedint is not very nice to work with directly, so Robert burner Schadek and I have been working on a wrapper struct for Phobos.

    Robert's version: https://github.com/D-Programming-Language/phobos/pull/3389
    My version:       https://github.com/tsbockman/CheckedInt

    Some comparative benchmarks (note: these predate Iain's update to GDC):
https://github.com/D-Programming-Language/phobos/pull/3389#issuecomment-115997507

I don't think either of our versions is ready to be pulled - for one thing, mine has no documentation yet. However, we could use some feedback from anyone interested in making use of checked integer arithmetic:

    1. What name do you prefer? SafeInt!T? CheckedInt!T? Something else?

    2. Regardless of which name is selected, it will still be rather verbose. I myself intend to use aliases like these to streamline things:

alias cint = CheckedInt!int;
alias cuint = CheckedInt!uint;
// etc...

static if(debug) {
  alias dint = CheckedInt!int;
  alias duint = CheckedInt!uint;
  // etc...
} else {
  alias dint = int;
  alias duint = uint;
  // etc...
}

       (These aliases could easily be placed in a separate module, or in a mixin template, to prevent namespace pollution when they aren't wanted.)

       Would anyone else like to see aliases like these included in Phobos?

    3. I know D is on a big @nogc nothrow kick right now, but this seems like something where exceptions could be really useful. It would be easy to forget to manually check .isNaN.

       I think a template option should be included to throw an exception when attempting to unwrap a NaN value. The API I have in mind would still allow unchecked unwrapping when explicitly requested, and the performance hit from the extra branches should be minimal.

       The disadvantage of throwing when unwrapping is that the exception might be thrown much later than the NaN value was actually generated. The alternative would be to throw immediately when a NaN is generated. However, this would be substantially slower in at least some cases.

       Thoughts?

    4. Robert has suggested that a SafeInt type should disable bitwise operations like ~, &, |, ^, but I don't understand why.

       It seems highly desirable to me to have NaN values propagate sensibly through all standard integer "math" - not only the operators, but also things like core.bitop and the integer operations in std.math.

       Ideally, I would like to have a sufficiently complete set of CheckedInt!T-aware math operations, that the implicit conversion to T could be removed so that the compiler would remind people to check isNaN before passing the wrapped value to non-CheckedInt!T-aware functions.

       (I'm not sure it will really make sense to go that far, though, since this scheme would still add syntactic friction to things like indexing an array with a CheckedInt.)

       What features do you want?

    5. For anyone who cares to take a look at our work-in-progress code, which version looks more promising to you at this point? Robert's, or mine?

June 30, 2015
After thinking about the both the exception issue, and the implicit conversion issue, I believe the best solution would be something like this:

Have an additional template parameter to CheckedInt!T which controls whether an implicit conversion to type T is available or not. If there is an implicit conversion, attempting to use it on a NaN value will throw an exception.

This approach will keep the user reasonably safe from accidentally ignoring a NaN condition for both the throwing and the nothrow versions. The throwing version will just be a little more syntactically convenient.

This behaviour should probably extend to explicit opCast!V() calls as well, where V is an integral type.

Unchecked unwrapping will always be available either way, by using CheckedInt.value.

To ease the writing of generic code which might accept a built-in integer or a CheckedInt, a template function like this can be included:

auto numValue(T)(in T t) pure
	if(isNumeric!T || isCheckedInt!T || isCIStore!T)
{
	static if(isCheckedInt!T || isCIStore!T)
		return t.value;
	else
		return t;
}

(Something like this actually already exists in both my version and Robert's version, for internal use.)

July 01, 2015
On Tuesday, 30 June 2015 at 18:25:14 UTC, Iain Buclaw wrote:
> I say 'you all', but what I really mean is 'bearophile'. :-)

I don't read messages on forum by him for weeks. :|

July 01, 2015
On Tuesday, 30 June 2015 at 20:24:38 UTC, tsbockman wrote:
>     4. Robert has suggested that a SafeInt type should disable bitwise operations like ~, &, |, ^, but I don't understand why.

The name SafeInt and the missing bitwise operations go in tandem.
SafeInt is a math type, +-/*% nothing more. Whenever I saw people beginning cleaver and use bitwise operations for math, they failed. Me included.

Thats why
July 02, 2015
On Wednesday, 1 July 2015 at 21:15:33 UTC, Robert burner Schadek wrote:
> On Tuesday, 30 June 2015 at 20:24:38 UTC, tsbockman wrote:
>>     4. Robert has suggested that a SafeInt type should disable bitwise operations like ~, &, |, ^, but I don't understand why.
>
> The name SafeInt and the missing bitwise operations go in tandem.
> SafeInt is a math type, +-/*% nothing more. Whenever I saw people beginning cleaver and use bitwise operations for math, they failed. Me included.
>
> Thats why

That makes sense. However, I am still interested in knowing whether others generally share your view, or mine.

I, personally, find bitwise operations useful. Bitwise operators are not just for "clever" code; the use of `x << y` rather than `x * 2^^y` both ensures good code gen, and is clear and concise.

API-wise, there are a few different options:

1. Disable bitwise operations on `SafeInt`.

    Pros: Discourages the use of bug-prone optimization techniques.

    Cons: Code that actually has a good reason to use bitwise operators either ends up being rewritten in a slow/unnatural/bug-prone fashion using the approved operators, or it is written against `SafeInt.value` and is not only unchecked itself, but also disrupts the propagation of NaN states from earlier checked operations.

2. Include checked (NaN propagating) bitwise operations in `SafeInt`.

    Pros: Allows safe, efficient use of bitwise operations where appropriate.

    Cons: Allows abuse of bitwise operations to write inscrutible "clever" code.

3. Make checked bitwise operations optional according to an additional template parameter to `SafeInt`.

    Pros: Allows safe, efficient use of bitwise operations where appropriate. Where they are not needed, the programmer may request that the compiler block their abuse.

    Cons: Complicates the design and usage of `SafeInt`.

I now understand your motivation for banning the use of bitwise operations with `SafeInt`.

However, I really don't think removing them entirely from `SafeInt` is a good idea; it takes so little code to work around this restriction that people (me, for one) will just use them anyway.

Without checked versions in `SafeInt`, more code that converts between `SafeInt` and built-in integral types will be written. Unless we always throw an exception when unwrapping a NaN value, such code will tend to silently eat NaN states and hide bugs even in the preceding checked arithmetic.

More generally, all the bitwise operators except the shifts (`<<`, `>>`, and `>>>`) have very well-defined and predictable behaviour. Even the shifts are no more confusing to work with than the equivalent composites of `*` or `/` with `2^^`.

It doesn't really seem to fit the spirit of D to ban such well-behaved basic tools just because people sometimes try to use them for things they shouldn't. People write incorrect algorithms or forget to handle corner cases when working with the normal arithmetic operators all the time; should we ban them?
July 02, 2015
On Wednesday, 1 July 2015 at 21:15:33 UTC, Robert burner Schadek wrote:
> On Tuesday, 30 June 2015 at 20:24:38 UTC, tsbockman wrote:
>>     4. Robert has suggested that a SafeInt type should disable bitwise operations like ~, &, |, ^, but I don't understand why.
>
> The name SafeInt and the missing bitwise operations go in tandem.
> SafeInt is a math type, +-/*% nothing more. Whenever I saw people beginning cleaver and use bitwise operations for math, they failed. Me included.
>
> Thats why

all bitwise ops except for shifting are fundamental math operators just like addition and subtraction if you view an integer as a bitstring(which is what it is...)
July 02, 2015
On Thursday, 2 July 2015 at 00:29:46 UTC, rsw0x wrote:
> all bitwise ops except for shifting are fundamental math operators just like addition and subtraction if you view an integer as a bitstring(which is what it is...)

I must have missed something in my math classes.

"Like the natural numbers, Z is closed under the operations of addition and multiplication" [1]

build in Integer are not really closed, but close enough.
No mentioning of shift operations though.

[1] https://en.wikipedia.org/wiki/Integer


July 02, 2015
On Thursday, 2 July 2015 at 11:26:24 UTC, Robert burner Schadek wrote:
> On Thursday, 2 July 2015 at 00:29:46 UTC, rsw0x wrote:
>> all bitwise ops except for shifting are fundamental math operators just like addition and subtraction if you view an integer as a bitstring(which is what it is...)
>
> I must have missed something in my math classes.
>
> "Like the natural numbers, Z is closed under the operations of addition and multiplication" [1]
>
> build in Integer are not really closed, but close enough.
> No mentioning of shift operations though.
>
> [1] https://en.wikipedia.org/wiki/Integer

I don't see why the closed-ness of the integers under an operation should determine whether it makes the cut or not, but if that's the standard:

The built-in integer types are truly closed under the bitwise operators `~`, `&`, `|`, and `^`, with no overflow, underflow, or undefined combinations.

In contrast, unary `-` can overflow, while binary `+`, `-`, and `*` can all overflow or underflow.

`<<` and `>>` are not closed, but they are conceptually identical to `* 2^^` and `/ 2^^`, respectively. Their invalid input combinations can be handled the same way.
« First   ‹ Prev
1 2