www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Reading few CPU flags from D code

reply bearophile <bearophileHUGS lycos.com> writes:
One of the things I miss from Delphi is the ranged types of integral values,
they actually increase the safety of programs, restricting a variable in a sub
range.

So I can create a struct template as this that implements a ranged integral
value:

Ranged!(1, 1001, int) foo;
alias Ranged!('a', 'z'+1, char) Lowercase;

(In theory the type used by the struct of the can be omitted, so for a range in
[1, 1000] it can chose to use an int.)

I have seen that I am not the only one that has this idea, see the range_type
here (C++):
http://www.richherrick.com/software/herrick_library.html

Multiplications are quite less common on ranged variables, + and - == and
assigns are the most common operations done on them.

The preconditions of the methods of that struct can test for the out of range
conditions. In release mode they are removed (or I can use a debug statement).
But it's better to keep those tests when possible, so I'd like that Ranged to
be efficient.

Delphi ranges are fast also because the compiler can remove some unnecessary
checks, I can't do this in a simple way (template expressions are overkill
here).

The struct has to test for out-of-range and true overflows of the int/ubyte/etc
they are implemented on.

Checking for overflow in D with no inline assembly can be a little slow. I
don't know much assembly yet, and it's more error-prone and less portable than
D code, baseline D (with no LDC extensions) doesn't inline the structs methods
that contain the asm code (and maybe the prologue-epilogue of the asm code can
kill any performance improvement given by reading the overflow bit from asm).

A solution is to make the backend smarter, so I can hope it will recognize
patterns in my code and compile it into good asm, but llvm doesn't currently
perform well here. I have filed few enhancement requests:

http://llvm.org/bugs/show_bug.cgi?id=4916
http://llvm.org/bugs/show_bug.cgi?id=4917
http://llvm.org/bugs/show_bug.cgi?id=4918

But even if the gentle Chris Lattner implements those tiny optimizations for
me, that's not a full solution, because the bad thing with compiler
optimizations is that you can't rely on them.

So, as a possible solution, that's portable on many CPU types (CPUs aren't
forced have them, but they are common), and gives some performance, can
std.intrinsic grow few ways to test for Overflow, Zero and Carry flags? I am
not sure if and how this can be implemented.

Bye,
bearophile
Mar 18 2010
parent bearophile <bearophileHUGS lycos.com> writes:
A simple way to implement it is to define few magic variables inside the
std.intrinsic module, and then allow them to be used only inside an if, alone,
like this:

import std.intrinsic: overflow_flag;

if (overflow_flag) {...} else {...}

But magic variables are not tidy. So a tidier solution is to turn them into
boolean functions that the compiler manages in a special way, as the other
intrinsics:

bool o = if overflow_flag();
Or:
if (overflow_flag()) {...} else {...}

But then the compiler has to manage them efficiently (for example here using a
single JNO or JO instruction).

Bye,
bearophile
Mar 20 2010