[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Unexpected handling of mixed-precision integer arithmetic
From: |
Gaius Mulley |
Subject: |
Re: Unexpected handling of mixed-precision integer arithmetic |
Date: |
Sat, 03 Feb 2024 01:00:08 +0000 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux) |
"Nelson H. F. Beebe" <beebe@math.utah.edu> writes:
> In most programming languages, the conventions for evaluation of
> expressions in integer arithmetic with operands of mixed precision is
> that the lower-precision ones are promoted to the higher precision,
> before the expression is evaluated.
>
> In gm2-13 and gm2-14 up to builds from January 2024 gcc snapshots, I
> found unexpected lower precision for both unsigned and signed
> expressions that I believe are due to a compiler bug, rather than
> being a misfeature of the Modula-2 language.
>
> Here is a test program that shows the results of two ways of
> evaluation of a mixed-precision expression:
>
> % cat TestCardinalExpr.mod
> MODULE TestCardinalExpr;
>
> FROM CardinalIO IMPORT WriteLongCardinal, WriteLongHex;
> FROM NumberIO IMPORT WriteHex;
> FROM StrIO IMPORT WriteLn, WriteString;
> FROM SYSTEM IMPORT CARDINAL32, CARDINAL64;
>
> VAR vv, ww : CARDINAL64;
> h : CARDINAL32;
>
> BEGIN
> vv := 0000000100000000H;
> h := 7H;
>
> ww := 16 * vv + h;
> WriteString('16 * 0x');
> WriteLongHex(vv, 16);
> WriteString(' + 0x');
> WriteHex(h, 0);
> WriteString(' = 0x');
> WriteLongHex(ww, 16);
> WriteLn;
>
> vv := 0000000100000000H;
> h := 7H;
>
> ww := 16 * vv + VAL(CARDINAL64, h);
> WriteString('16 * 0x');
> WriteLongHex(vv, 16);
> WriteString(' + 0x');
> WriteHex(h, 0);
> WriteString(' = 0x');
> WriteLongHex(ww, 16);
> WriteLn;
>
> END TestCardinalExpr.
>
> Here is the program output:
>
> % gm2 TestCardinalExpr.mod && ./a.out
> 16 * 0x0000000100000000 + 0x7 = 0x0000000000000007
> 16 * 0x0000000100000000 + 0x7 = 0x0000001000000007
>
> The correct answer is in the second line. I believe that the
> VAL(CARDINAL64, h) wrapper should NOT have been necessary, because the
> expression 16 * vv is already in the higher precision, so 16 * vv + h
> should be as well.
>
> A similar test program with CARDINAL replaced by INTEGER shows
> identical behavior.
>
> During compiler code generation, there is likely to be a node for the
> Lisp-like form (* vv h), and I expect that the test for the precision
> of the multiplication is wrong, picking that of the shorter operand,
> rather than the longer one.
Hi Nelson,
Many thanks for the bug report and test code - now fixed in the git
repro (under PR modula2/113730). The problem occurred when a sub
expression is formed from a ZType and integer (or cardinal) the
expression was assigned a ZType type (rather than the integer or
cardinal). The expression was then (incorrectly) allowed to be used
with another ordinal type.
I've corrected the sub expression type assignment - and now a compile
yields:
$ gm2 TestCardinalExpr.mod
TestCardinalExpr.mod:15:18: error: In program module ‘TestCardinalExpr’: type
incompatibility between ‘CARDINAL32’ and ‘CARDINAL64’
15 | ww := 16 * vv + h;
| ~~~~~~~~^~~
I've added regression tests to gcc/testsuite/gm2/extensions/fail:
$ gm2 arith1.mod
arith1.mod:30:15: error: In procedure ‘testCardinal’: type incompatibility
between ‘CARDINAL8’ and ‘CARDINAL32’
30 | c16 := c16 + c8 ;
| ~~~~^~~~
$ gm2 arith2.mod
arith2.mod:30:15: error: In procedure ‘testCardinal’: type incompatibility
between ‘CARDINAL8’ and ‘CARDINAL64’
30 | c64 := c64 + c8
| ~~~~^~~~
$ gm2 arith3.mod
arith3.mod:30:15: error: In procedure ‘testCardinal’: type incompatibility
between ‘CARDINAL64’ and ‘CARDINAL32’
30 | c64 := c32 + c64
| ~~~~^~~~~
$ gm2 arith4.mod
arith4.mod:30:20: error: In procedure ‘testCardinal’: type incompatibility
between ‘CARDINAL32’ and ‘CARDINAL64’
30 | c64 := 16 * c64 + c32; (* Should fail here. *)
| ~~~~~~~~~^~~~~
regards,
Gaius