[fpc-devel] Division nodes

J. Gareth Moreton gareth at moreton-family.com
Tue May 23 18:54:27 CEST 2023


I just repeated the test on i386-win32 and it's the same thing... with 
one notable exception:

procedure DoDivMod(N, D: Int64; out Q, R: LongInt); noinline;
begin
   Q := LongInt(N) div LongInt(D);
   R := LongInt(N) mod LongInt(D);
end;

This reduces the operation to 32 bits, but does NOT generate a 
conditional check for a divisor of -1, so LongInt($0000000080000000) div 
LongInt(-1) will raise an exception, but won't raise an exception on 
x86_64-win64, thus behaviour between platforms is different.

Can others confirm this?

Kit

On 21/05/2023 00:00, J. Gareth Moreton via fpc-devel wrote:
> Hi Florian,
>
> Can I have a specific code example where this is absolutely necessary, 
> and, if applicable, a target where it's known to cause a problem 
> otherwise?  I've tried to create the example listed in the e-mail with 
> the following:
>
> procedure DoDivMod(N, D: Int64; out Q, R: LongInt); noinline;
> begin
>   Q := N div D;
>   R := N mod D;
> end;
>
> I'm testing on x86_64-win64.  In this case, the "expanding to 64-bit" 
> is necessary and so "doremoveinttypeconvs" is never called, thus the 
> condition is not inserted.  The "idiv" operation is 64-bit and the 
> result downsized to 32-bit - this also occurs if I do an explicit 
> typecast on the result:
>
> procedure DoDivMod(N, D: Int64; out Q, R: LongInt); noinline;
> begin
>   Q := LongInt(N div D);
>   R := LongInt(N mod D);
> end;
>
> However, if I do an explicit typecast on the operands...
>
> procedure DoDivMod(N, D: Int64; out Q, R: LongInt); noinline;
> begin
>   Q := LongInt(N) div LongInt(D);
>   R := LongInt(N) mod LongInt(D);
> end;
>
> ... then "doremoveinttypeconvs" is called and the condition inserted.  
> I would argue here though that typecasting a value to a LongInt, where 
> an output of $80000000 is a real possibility, should raise an 
> exception if you try to divide it by -1 since the programmer is asking 
> to downsize values that could potentially be out of range.
>
> Kit
>
> On 19/05/2023 21:55, Florian Klämpfl via fpc-devel wrote:
>> Am 19.05.23 um 21:14 schrieb J. Gareth Moreton via fpc-devel:
>>> So I need to ask... should the check for a divisor of -1 still be 
>>> performed? 
>>
>> Yes. This is the result of "down sizing" a division. In case of
>>
>> longint(int64 div int64) can be converted only into longint(int64) 
>> div longint(int64) if this check is carried out. longint($80000000 
>> div $ffffffff) must silently result in $8000000 in this case.
>>
>>> The case of doing "min_int div -1", even with unsigned-to-signed 
>>> typecasting, seems very contrived and the programmer should expect 
>>> problems if "min_int" and "-1" appear as the operands.  Is there a 
>>> specific example where this implicit check is absolutely necessary?  
>>> As others have pointed out, silently returning "min_int" as the 
>>> answer seems more unexpected (granted this is just the behaviour of 
>>> an optimisation that converts the nodes equating to "x div -1" to 
>>> "-x", and Intel's NEG instruction doesn't return an error if min_int 
>>> is its input operand, but I can't be sure if the same applies to 
>>> non-Intel processors and their equivalent instructions).
>>>
>>> Kit
>>>
>>> On 17/05/2023 09:51, J. Gareth Moreton via fpc-devel wrote:
>>>> Logically yes, but using 16-bit as an example, min_int is -32,768, 
>>>> and signed 16-bit integers range from -32,768 to 32,767. So -32,768 
>>>> ÷ -1 = 32,768, which is out of range.  This is where the problem lies.
>>>>
>>>> Internally, negation involves inverting all of the bits and then 
>>>> adding 1 (essentially how you subtract a number using two's 
>>>> complement), so min_int, which is 1000000000000000, becomes 
>>>> 0111111111111111 and then, after incrementing, 1000000000000000, 
>>>> which is min_int again.
>>>>
>>>> Kit
>>>>
>>>> On 16/05/2023 13:13, Jean SUZINEAU via fpc-devel wrote:
>>>>> Le 16/05/2023 à 01:47, Stefan Glienke via fpc-devel a écrit :
>>>>>> min_int div -1
>>>>>
>>>>> "min_int div -1"  should give  "- min_int" ?
>>>>> _______________________________________________
>>>>> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
>>>>> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>>>>>
>>>> _______________________________________________
>>>> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
>>>> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>>>>
>>> _______________________________________________
>>> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
>>> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>>
>> _______________________________________________
>> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
>> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>>
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>


More information about the fpc-devel mailing list