Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2021-09

Conversion from C to Pascal - Left bit shift

7 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

LacaK

Hello *,

I have code in C like this:
  E1 << E2
If E1 is of unsigned type then "The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type."

I understand this as result of such operation does not grow over 32 bits, right?

In Pascal I have:
  E1 shl E2
where E1 is of LongWord type.

On 64-bit target this result of shl can overcome 32 bits (iow operates on 32 bits)?
(does also bit shift operations works on 64 bits or this only affect arithmetic operations like multiply?)

Assembler suggests that shl works on 32 bits: shl    %cl,%r11d

-Laco.

LacaK
to LacaK

Can we say that in Pascal the result of:
  E1 shl E2
is of same type as E1 ?
(so if E1 is LongWord then result is LongWord also?)

What if there is an expression on left side:
  (E1*x) shl E2
Will E1*x promote to 64 bits (on 64 bit target)?

-Laco.

Show quoted text 25 lines
Hello *, I have code in C like this:   E1 << E2 If E1 is of unsigned type then "The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type." I understand this as result of such operation does not grow over 32 bits, right? In Pascal I have:   E1 shl E2 where E1 is of LongWord type. On 64-bit target this result of shl can overcome 32 bits (iow operates on 32 bits)? (does also bit shift operations works on 64 bits or this only affect arithmetic operations like multiply?) Assembler suggests that shl works on 32 bits: shl    %cl,%r11d -Laco.
Christo Crause
to LacaK

On Fri, Sep 3, 2021 at 8:02 AM LacaK via fpc-pascal <

Show quoted text 11 lines
wrote: Can we say that in Pascal the result of: E1 shl E2 is of same type as E1 ? (so if E1 is LongWord then result is LongWord also?) What if there is an expression on left side: (E1*x) shl E2 Will E1*x promote to 64 bits (on 64 bit target)?

See documentation on automatic type conversion (the remarks section below table 3.3): https://www.freepascal.org/docs-html/ref/refsu4.html#x26-26004r3 While this doesn't explicitly mention shift behaviour, it implies that E1 and (E1*x) will be promoted to native sized integer if smaller. For the first example, if E1 is a longword on a 32 bit machine, the result should also be a longword.

Personal note: I find the naming of ordinal types confusing. Is shortint smaller than smallint, or smallint shorter than shortint? In FPC a word is 2 bytes in size, however on the hardware side a word refers to "the natural unit of data used by a particular processor design" ( https://en.wikipedia.org/wiki/Word_(computer_architecture)). I prefer to use the type aliases with explicit mention of size, such as int16, uint8 etc. I assume the flip side of this is when trying to write portable code that uses the most efficient size available on a target.

LacaK
to Christo Crause
Show quoted text 20 lines
Can we say that in Pascal the result of:    E1 shl E2 is of same type as E1 ? (so if E1 is LongWord then result is LongWord also?) What if there is an expression on left side:    (E1*x) shl E2 Will E1*x promote to 64 bits (on 64 bit target)? See documentation on automatic type conversion (the remarks section below table 3.3): https://www.freepascal.org/docs-html/ref/refsu4.html#x26-26004r3 <https://www.freepascal.org/docs-html/ref/refsu4.html#x26-26004r3> While this doesn't explicitly mention shift behaviour, it implies that E1 and (E1*x) will be promoted to native sized integer if smaller.  For the first example, if E1 is a longword on a 32 bit machine, the result should also be a longword.

But look at Delphi documentation:
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Expressions_(Delphi)#Logical_.28Bitwise.29_Operators

"The operations x shl y and x shr y shift the value of x to the left or right by y bits, which (if x is an unsigned integer) is equivalent to multiplying or dividing x by 2^y; the result is of the same type as x"

My understanding is, that in case:
E1 shl E2 result is of E1 type (so if E1 is LongWord on 64 bit platform result is still LongWord?)

Case
(E1*x) shl E2 is subject to native integer promotion I guess?

L.

Jean SUZINEAU
to LacaK
I made a few tests on Ubuntu 64 bits (arch x86_64) with variations on a
small test program:
var
    E2: Byte= 3;
    E1: LongWord= 1;
    E: QWord;
begin
      E:= (1000*E1) shl E2;
      writeln( 'E2', E2);
      writeln( 'E1', E1);
      writeln( 'E', E);
end.

In the assembly window, shl is computed on 64 bits %rax, I get :

project1.lpr:132 E:= (1000*E1) shl E2;
00000000004011B2 8b05d8f50c00             mov 0xcf5d8(%rip),%eax        # 0x4d0790 <TC_$P$PROJECT1_$$_E1>
00000000004011B8 4869c0e8030000           imul $0x3e8,%rax,%rax 00000000004011BF 0fb60dbaf50c00           movzbl 0xcf5ba(%rip),%ecx        # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011C6 48d3e0                   shl    %cl,%rax 00000000004011C9 48890580b51000           mov %rax,0x10b580(%rip)        # 0x50c750 <U_$P$PROJECT1_$$_E>

Changing the formula to E:= E1 shl E2, shl computed on 32 bits %edx, (I don't understand the "and    %edx,%edx", may be just to clear the carry ?) I get :

project1.lpr:132 E:= E1 shl E2;
00000000004011B2 0fb605c7f50c00           movzbl 0xcf5c7(%rip),%eax        # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011B9 8b15d1f50c00             mov 0xcf5d1(%rip),%edx        # 0x4d0790 <TC_$P$PROJECT1_$$_E1>
00000000004011BF 89c1                     mov    %eax,%ecx 00000000004011C1 d3e2                     shl    %cl,%edx 00000000004011C3 21d2                     and    %edx,%edx 00000000004011C5 48891584b51000           mov %rdx,0x10b584(%rip)        # 0x50c750 <U_$P$PROJECT1_$$_E>

Changing  E1 to QWord ( E1: QWord= 1; ), shl is computed on 64 bits %rax, I get :

project1.lpr:132 E:= E1 shl E2;
00000000004011B2 0fb605c7f50c00           movzbl 0xcf5c7(%rip),%eax        # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011B9 488b15d0f50c00           mov 0xcf5d0(%rip),%rdx        # 0x4d0790 <TC_$P$PROJECT1_$$_E1>
00000000004011C0 4889c1                   mov    %rax,%rcx 00000000004011C3 48d3e2                   shl    %cl,%rdx 00000000004011C6 48891583b51000           mov %rdx,0x10b583(%rip)        # 0x50c750 <U_$P$PROJECT1_$$_E>

Markus Greim
to Jean SUZINEAU

After 35 years of Pascal experience I would urgently recommend NOT to trust any automatic type conversion in the case of shift operators. Alteady Turbo Pascal failed here on x386 architectures. Force input and output variables to a certain data type before you use the shift operator.

Just my 5 cents
Markus Greim

Mit freundlichen Grüßen

Markus Greim

Schleibinger Geräte
Teubert u. Greim GmbH
Gewerbestrasse 4
84428 Buchbach
Germany

Tel. +49 8086 94731-10
Fax. +49 8086 94731-14
Mobil +49 172 8 999 196
http://www.schleibinger.com

Amtsgericht Traunstein HRB 9646
Geschäftsführer:
Dipl.-Ing. (FH) Oliver Teubert
Dipl.-Ing. (Univ.) Markus Greim
UST-ID. DE 174 175 046

Earlier message 44 lines
--- original message --- On September 3, 2021 at 2:36 PM GMT+2 wrote: I made a few tests on Ubuntu 64 bits (arch x86_64) with variations on a small test program: var E2: Byte= 3; E1: LongWord= 1; E: QWord; begin E:= (1000*E1) shl E2; writeln( 'E2', E2); writeln( 'E1', E1); writeln( 'E', E); end. In the assembly window, shl is computed on 64 bits %rax, I get : project1.lpr:132 E:= (1000*E1) shl E2; 00000000004011B2 8b05d8f50c00 mov 0xcf5d8(%rip),%eax # 0x4d0790 <TC_$P$PROJECT1_$$_E1> 00000000004011B8 4869c0e8030000 imul $0x3e8,%rax,%rax 00000000004011BF 0fb60dbaf50c00 movzbl 0xcf5ba(%rip),%ecx # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011C6 48d3e0 shl %cl,%rax 00000000004011C9 48890580b51000 mov %rax,0x10b580(%rip) # 0x50c750 <U_$P$PROJECT1_$$_E> Changing the formula to E:= E1 shl E2, shl computed on 32 bits %edx, (I don't understand the "and %edx,%edx", may be just to clear the carry ?) I get : project1.lpr:132 E:= E1 shl E2; 00000000004011B2 0fb605c7f50c00 movzbl 0xcf5c7(%rip),%eax # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011B9 8b15d1f50c00 mov 0xcf5d1(%rip),%edx # 0x4d0790 <TC_$P$PROJECT1_$$_E1> 00000000004011BF 89c1 mov %eax,%ecx 00000000004011C1 d3e2 shl %cl,%edx 00000000004011C3 21d2 and %edx,%edx 00000000004011C5 48891584b51000 mov %rdx,0x10b584(%rip) # 0x50c750 <U_$P$PROJECT1_$$_E> Changing E1 to QWord ( E1: QWord= 1; ), shl is computed on 64 bits %rax, I get : project1.lpr:132 E:= E1 shl E2; 00000000004011B2 0fb605c7f50c00 movzbl 0xcf5c7(%rip),%eax # 0x4d0780 <TC_$P$PROJECT1_$$_E2> 00000000004011B9 488b15d0f50c00 mov 0xcf5d0(%rip),%rdx # 0x4d0790 <TC_$P$PROJECT1_$$_E1> 00000000004011C0 4889c1 mov %rax,%rcx 00000000004011C3 48d3e2 shl %cl,%rdx 00000000004011C6 48891583b51000 mov %rdx,0x10b583(%rip) # 0x50c750 <U_$P$PROJECT1_$$_E>
Jonas Maebe
to LacaK: Can we say that in Pascal the result of:   E1 shl E2 is of same type as E1 ? (so if E1…
LacaK wrote 16 lines
> I have code in C like this: >   E1 << E2 > If E1 is of unsigned type then "The value of E1 << E2 is E1 > left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has > an unsigned type, the value of the result is E1 × 2^E2, reduced modulo > one more than the maximum value representable in the result type." > > I understand this as result of such operation does not grow over 32 > bits, right? > > In Pascal I have: >   E1 shl E2 > where E1 is of LongWord type. > > On 64-bit target this result of shl can overcome 32 bits (iow operates > on 32 bits)?

If E1 is 32 bits, the result will be 32 bits. From the compiler source code:

{ calculations for ordinals < 32 bit have to be done in 32 bit for backwards compatibility. That way 'shl 33' is the same as 'shl 1'. It's ugly but compatible with delphi/tp/gcc }

Note that the "shl 33' is the same as 'shl 1'" part of the comment refers to the specific behaviour of the x86 family of processors. That is not necessarily the case on other systems (e.g. on 32 bit PowerPC, the result will be 0 as you would normally expect).

Can we say that in Pascal the result of: E1 shl E2 is of same type as E1 ?

No. If E1 is smaller than 32 bits, the result will be promoted to
1) on 32/64 bit platforms: 32 bits
2) on 8/16 bit platforms: the smallest integer type that can represent both E1 and the native integer type of the platform

What if there is an expression on left side: (E1*x) shl E2 Will E1*x promote to 64 bits (on 64 bit target)?

Expressions are always evaluated independently of how their result is used. So, yes.

Jonas