Frank Heckenbach wrote:
One could also try to invent some compromise rules, for example trying to use "most precise fast arithmetic", but doint it right is tricky.
And it makes testing for several targets tricky, because they can differ about which types are fast -- not only relating to size, but also to Pascal types, e.g. MedInt may be fast or not.
However, I do see a GPC problem here. According to ISO Pascal, operations should not be done on smaller than Integer types. GPC followed this rule for `+' and `-', but not for other operations. The attached patch fixes this. It doesn't cause any regressions in the test suite on IA32 (but I haven't tested on other systems yet, and type size changes are always somewhat critical -- that's why I included 3 versions of these test programs, even if rather similar).
Thanks for the patch ! It fixes the problem and doesn't cause any regressions on powerpc-apple-darwin7.
Whether SizeOf gives a result of type SizeType or another type is quite irrelevant as GPC mostly ignores types of integer constants.
But it also ignores explicit typecasts on integer constants (see below).
Basically speaking gpc performs operations up to precision of more precise argument. When computing `i*j' gpc notes that `j' is more precise (usually `SizeType' has 32-bit or better precision) and uses its precision to perform multiplication. In the second case (`i*SizeOf(point)') gpc notes that `SizeOf(point)' is a constant and that this constant fits into 16-bits, and uses only 16-bit precision for multiplication.
Also, ATM gpc has no runtime overflow checking, so one silently gets incorrect result.
You may ask gpc is "correct". That is samewhat tricky question. Namely, gpc applies rules, and AFAICS it applies exactly the rules which were intended by programers coding them (I think Frank changed rules to the current ones). So the real question is if the rules are good ("correct"). Now, it would be nice to have rules which always give mathematically correct result (in other words, use precision big enough to avoid any possibility of overflow). But this is impossible in currect gpc: we have maximal precision and we can not go beyond that. Another possibility is to give correct results if possible and use maximal precision otherwise. However, the maximal precision is really a "double precision". Namely, gpc can perform arithmetic at twice of normal machine precision. Which is nice, but expensive: such operation may be significantly slower then normal operations. ATM gpc is rather dumb when predicting needed precision, so even if arguments are small gpc may think that maximal precision is needed. Also, even maximal precision may still give you wrong results.
So, there is rather nasty compromise between correctness and speed. I usuallt go for correctness. However, here speed penalty may be very significant (about 3 times when done right, but may be as high as 20 if maximal precision is slow). So, having optional overflow checking looks more attractive: one can test with overflow checking on and then release with checking off.
Yes, that's my reasoning too. I've always had overflow checking in mind (even though I also cannot work on it in the near future).
Then, I kindly ask to put the following program (with overflow checking) in p/test/todo (to be implemented at some point in the future).
program testsubrange;
type int32 = integer attribute( size = 32); int64 = integer attribute( size = 64); millionbytes = array[ 1..1000000] of byte;
var i: int32;
procedure P( size: int64); begin WriteLn ('size = ', size) end;
begin i:= 3658; P( i * SizeOf( millionbytes)); end.
And, of course, there should always be a way to force evaluation in higher precision if needed. In GPC/BP modes, type-casting one operand is a common way (also common in BP code). In ISO mode, we don't have such a way, AFAICS. OTOH, ISO doesn't support types larger than `Integer' anyway.
But typecasting the SizeOf operand doesn't work, e.g.
program testsubrange;
type int32 = integer attribute( size = 32); int64 = integer attribute( size = 64); millionbytes = array[ 1..1000000] of byte;
var i: int32;
procedure P( size: int64); begin if size = 3658000000 then WriteLn ('OK') else WriteLn ('failed: ', 'size = ', size) end;
begin i:= 3658; P( i * int64( SizeOf( millionbytes))); end.
Typecasting the variable operand (i) does work.
Regards,
Adriaan van Os