I can not use SHL (left shift) with int64 variables

Result:= b8; Result:= Result+ (b7 SHL 8); Result:= Result+ (b6 SHL 16); Result:= Result+ (b5 SHL 24); Result:= Result+ (b4 SHL 32); Result:= Result+ (b3 SHL 40); <------ here Result:= Result+ (b2 SHL 48); Result:= Result+ (MSB SHL 56); 

(The result is int64, and b1-b8 is a byte).

But the compiler complains that "the constant exp violates the boundaries of the subbands." Then I found this warning, β€œThe compiler will reject hard-coded shift offsets that exceed 32, unless the Int64 data type. The same does not apply to Shl” on the website. Help Delphi says nothing about this. Why is there a limit? Can I stop him? Maybe a compiler directive or something else? I can use multiplication to overcome it, but it will be slower. Is there a faster way to do this?

Edit: I am also thinking of creating two cardinals, because I can use SHL on cardinals and then combine the cardinals together. This will require only one multiplication. Any other ideas?

Edit2: The code is part of an algorithm that converts the base of number forms 255 to base 256 (and vice versa). I do this 50,000 million times; therefore speed is important.

+6
source share
3 answers

I would avoid all arithmetic (your code has additions and shifts) and do it like this:

 Int64Rec(Result).Bytes[0] := b8; Int64Rec(Result).Bytes[1] := b7; //etc. 

Int64Rec defined in SysUtils as follows:

 Int64Rec = packed record case Integer of 0: (Lo, Hi: Cardinal); 1: (Cardinals: array [0..1] of Cardinal); 2: (Words: array [0..3] of Word); 3: (Bytes: array [0..7] of Byte); end; 

If you saved your bytes in an array, you can wrap it all in a for loop.

+16
source

I assume that your Result already Int64 , and b8 , b7 , etc. declared as Byte . The compiler needs a little help. Typecast to Int64 :

  Result := b8; Result := Result + (b7 shl 8); Result := Result + (b6 shl 16); Result := Result + (b5 shl 24); Result := Result + (Int64(b4) shl 32); Result := Result + (Int64(b3) shl 40); Result := Result + (Int64(b2) shl 48); Result := Result + (Int64(msb) shl 56); 
+10
source

Here is another solution that uses shifts, but I think it is β€œcleaner” (although not as clean as David's suggestion):

 result := MSB; result := (result shl 8) or b2; { could use "shl sizeof(b2)" instead of 8 } result := (result shl 8) or b3; etc result := (result shl 8) or b8; 

this solution avoids all β€œmagic” shifting values, and is probably easier to understand. Furthermore, if MSB..b8 (or b1..b8) was an array of bytes, the above code could easily be converted into a single linear loop.

To answer the question of why the compiler does not accept a value of 40 or higher, the reason is most likely related to this quote from volume 2B of the Intel instruction set reference for the SHLD instruction:

In non-64-bit modes and the default is 64-bit mode; only bits 0 through 4 of the count. This masks the counter to a value from 0 to 31. If count is larger than the operand size, the result is undefined.

The equivalent condition in the SHL instruction is not so strict:

8086 does not mask shift count. However, all other IA-32 processors (starting with Intel 286) make a shift counting mask of up to 5 bits, which leads to a maximum count of 31. This masking is performed in all operating modes (including virtual-8086) to reduce the maximum execution time of the instruction.

In any case, a value greater than 31 is either useless (when using SHL) or undefined (when using SHLD). The compiler obviously knows about this, and this prevents you from writing code that is potentially erroneous (in 64-bit mode).

if you are really doing this 50 MLRL operation. times, then you might want to do this in an inline assembly, which would be pretty simple:

 asm xor eax, eax or eax, MSB { or b1 depending on how you named the MSB } shl eax, 8 or eax, b2 shl eax, 8 or eax, b3 shl eax, 8 or eax, b4 mov High32bit, eax end; 

and repeat the above operation for the low-order 32-bit word and b5th in figure eight. I did not suggest using SHLD because I do not believe that Delphi supports 64-bit registers or 64-bit instructions (I could be wrong, I never tried).

Note. I heard rumors that the 64-bit version of Delphi does not support built-in assembly. It may or may not be, but I would stay away from the built-in assembly if it is really absolutely necessary.

Hope this helps,

John.

PS: there is another reason why David Heffernan's decision is the best. In the solution I presented, each instruction depends on the previous instruction (that is, eax must be shifted by 8 to the next "or" command can be executed). David's solution sets individual bytes, as such, each assignment does not depend on the previous assignment, this will allow the processor to potentially perform several assignments in parallel. In this era of multi-core processors, it can be a little faster than the build code I gave as an example.

+7
source

Source: https://habr.com/ru/post/888195/


All Articles