Bit-shifting uses inconsistent operand sizes versus ASM-backend

All bugs related to new C backend
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Bit-shifting uses inconsistent operand sizes versus ASM-backend

Post by yuki »

System Info

OS: Windows 11 (x64), macOS 13.6 (arm64)
PB Version: 6.02, 6.03b9
PB Backend: C / ASM (inconsistency)
PB Architecture: x64, arm64

Details

Given a 64-bit target platform, bit-shift operations with the C-backend sometimes operate in 32-bit mode and other times 64-bit. Meanwhile, the ASM-backend seems to always sign-extend the value-to-shift to 64-bits and operate in 64-bit mode.

SHL (<<) and SHR (>>) operations vary in their application of mode.

Details – SHL (<<)

The C-backend's left-shift is inconsistent with the ASM-backend's behaviour when all of:
  • The result type is smaller than the machine word.
  • The shift-count type is smaller than the machine word.
In this case, SHL suffers reduction of shift-count range (6-bits → 5-bits, i.e.: 0…63 → 0…31).

Example:

Code: Select all

If Not OpenConsole() : DebuggerError("Failed to open console!") : End : EndIf

Define x.l = -2013265920

Define count_long.l = 32
Define count_quad.q = 32

Define x_shl_inline.l  = x << 32            ; C 64-bit | ASM 64-bit
Define x_shl_by_long.l = x << count_long    ; C 32-bit | ASM 64-bit
Define x_shl_by_quad.l = x << count_quad    ; C 64-bit | ASM 64-bit

PrintN("x: " + x)
PrintN("x << inline : " + x_shl_inline)
PrintN("x << long   : " + x_shl_by_long)
PrintN("x << quad   : " + x_shl_by_quad)

Input()
Results (6.03b9 ASM, Windows 11 x64):

Code: Select all

x: -2013265920
x << inline : 0
x << long   : 0
x << quad   : 0
Results (6.03b9 C, Windows 11 x64 + macOS 13.6 arm64):

Code: Select all

x: -2013265920
x << inline : 0
x << long   : -2013265920
x << quad   : 0
While left-shifting a long by 32 is somewhat odd (as it'd always produce zero), I'd hope for consistent results with it across backends.

Produced C in this case:

Code: Select all

// Define x_shl_by_long.l = x << count_long    
v_x_shl_by_long=(v_x<<v_count_long);
By casting the shifted value to quad, consistency with ASM-backend is reached:

Code: Select all

// Define x_shl_by_long.l = x << count_long    
v_x_shl_by_long=((quad)v_x<<v_count_long);


Details – SHR (>>)

The C-backend's right-shift is inconsistent with the ASM-backend's behaviour when any of:
  • The value to be shifted is of a type smaller than the machine word.
In this case, SHR suffers reduction of shift-count range (6-bits → 5-bits, i.e.: 0…63 → 0…31).

Example:

Code: Select all

If Not OpenConsole() : DebuggerError("Failed to open console!") : End : EndIf

Define x.l = -2013265920

Define count_long.l = 32
Define count_quad.q = 32

Define x_shr_inline.l  = x >> 32            ; C 32-bit | ASM 64-bit
Define x_shr_by_long.l = x >> count_long    ; C 32-bit | ASM 64-bit
Define x_shr_by_quad.l = x >> count_quad    ; C 32-bit | ASM 64-bit 

PrintN("x: " + x)
PrintN("x >> inline : " + x_shr_inline)
PrintN("x >> long   : " + x_shr_by_long)
PrintN("x >> quad   : " + x_shr_by_quad)

Input()
Results (6.03b9 ASM, Windows 11 x64):

Code: Select all

x: -2013265920
x >> inline : -1
x >> long   : -1
x >> quad   : -1
Results (6.03b9 C, Windows 11 x64 + macOS 13.6 arm64):

Code: Select all

x: -2013265920
x >> inline : -2013265920
x >> long   : -2013265920
x >> quad   : -2013265920
Similarly to left-shifting a long by 32, right-shifting a long by 32 is also quite bizarre. Even so, parity across compiler backends here would be of great use.

Produced C in this case:

Code: Select all

// Define x_shr_inline.l  = x >> 32            
v_x_shr_inline=(v_x>>(int)32);
// Define x_shr_by_long.l = x >> count_long    
v_x_shr_by_long=(v_x>>v_count_long);
// Define x_shr_by_quad.l = x >> count_quad    
v_x_shr_by_quad=(v_x>>v_count_quad);
By casting the shifted value to quad, consistency with ASM-backend is reached:

Code: Select all

// Define x_shr_inline.l  = x >> 32            
v_x_shr_inline=((quad)v_x>>(int)32);
// Define x_shr_by_long.l = x >> count_long    
v_x_shr_by_long=((quad)v_x>>v_count_long);
// Define x_shr_by_quad.l = x >> count_quad    
v_x_shr_by_quad=((quad)v_x>>v_count_quad);

Expectation

C and ASM backends should probably agree here.

It's difficult to say which backend's approach should be preferred.

The C-backend's approach of favouring 32-bit in some cases allows for performance gains, whereas the ASM-backend's approach is much more predictable.

If the backends are not to agree in this case, documentation of this as potentially undefined behaviour would be appreciated.
juergenkulow
Enthusiast
Enthusiast
Posts: 556
Joined: Wed Sep 25, 2019 10:18 am

Re: Bit-shifting uses inconsistent operand sizes versus ASM-backend

Post by juergenkulow »

Code: Select all

; SAR r15,cl versus SAR ebx,cl 
Define x.l = $F0F0F0F0
Define count_long.l
For count_long=0 To 63
  Define x_shr_by_long.l = x >> count_long
  Debug RSet(Str(count_long),2,"0")+":"+Bin(x_shr_by_long,#PB_Long)
Next 
; ASM Backend x64
; 00:11110000111100001111000011110000
; 01:11111000011110000111100001111000
; 02:11111100001111000011110000111100
; 03:11111110000111100001111000011110
; 04:11111111000011110000111100001111
; 05:11111111100001111000011110000111
; 06:11111111110000111100001111000011
; 07:11111111111000011110000111100001
; 08:11111111111100001111000011110000
; 09:11111111111110000111100001111000
; 10:11111111111111000011110000111100
; 11:11111111111111100001111000011110
; 12:11111111111111110000111100001111
; 13:11111111111111111000011110000111
; 14:11111111111111111100001111000011
; 15:11111111111111111110000111100001
; 16:11111111111111111111000011110000
; 17:11111111111111111111100001111000
; 18:11111111111111111111110000111100
; 19:11111111111111111111111000011110
; 20:11111111111111111111111100001111
; 21:11111111111111111111111110000111
; 22:11111111111111111111111111000011
; 23:11111111111111111111111111100001
; 24:11111111111111111111111111110000
; 25:11111111111111111111111111111000
; 26:11111111111111111111111111111100
; 27:11111111111111111111111111111110
; 28:11111111111111111111111111111111
; 29:11111111111111111111111111111111
; 30:11111111111111111111111111111111
; 31:11111111111111111111111111111111
; 32:11111111111111111111111111111111
; 33:11111111111111111111111111111111
; 34:11111111111111111111111111111111
; 35:11111111111111111111111111111111
; 36:11111111111111111111111111111111
; 37:11111111111111111111111111111111
; 38:11111111111111111111111111111111
; 39:11111111111111111111111111111111
; 40:11111111111111111111111111111111
; 41:11111111111111111111111111111111
; 42:11111111111111111111111111111111
; 43:11111111111111111111111111111111
; 44:11111111111111111111111111111111
; 45:11111111111111111111111111111111
; 46:11111111111111111111111111111111
; 47:11111111111111111111111111111111
; 48:11111111111111111111111111111111
; 49:11111111111111111111111111111111
; 50:11111111111111111111111111111111
; 51:11111111111111111111111111111111
; 52:11111111111111111111111111111111
; 53:11111111111111111111111111111111
; 54:11111111111111111111111111111111
; 55:11111111111111111111111111111111
; 56:11111111111111111111111111111111
; 57:11111111111111111111111111111111
; 58:11111111111111111111111111111111
; 59:11111111111111111111111111111111
; 60:11111111111111111111111111111111
; 61:11111111111111111111111111111111
; 62:11111111111111111111111111111111
; 63:11111111111111111111111111111111
; ASM Backend x86
; 00:11110000111100001111000011110000
; 01:11111000011110000111100001111000
; 02:11111100001111000011110000111100
; 03:11111110000111100001111000011110
; 04:11111111000011110000111100001111
; 05:11111111100001111000011110000111
; 06:11111111110000111100001111000011
; 07:11111111111000011110000111100001
; 08:11111111111100001111000011110000
; 09:11111111111110000111100001111000
; 10:11111111111111000011110000111100
; 11:11111111111111100001111000011110
; 12:11111111111111110000111100001111
; 13:11111111111111111000011110000111
; 14:11111111111111111100001111000011
; 15:11111111111111111110000111100001
; 16:11111111111111111111000011110000
; 17:11111111111111111111100001111000
; 18:11111111111111111111110000111100
; 19:11111111111111111111111000011110
; 20:11111111111111111111111100001111
; 21:11111111111111111111111110000111
; 22:11111111111111111111111111000011
; 23:11111111111111111111111111100001
; 24:11111111111111111111111111110000
; 25:11111111111111111111111111111000
; 26:11111111111111111111111111111100
; 27:11111111111111111111111111111110
; 28:11111111111111111111111111111111
; 29:11111111111111111111111111111111
; 30:11111111111111111111111111111111
; 31:11111111111111111111111111111111
; 32:11110000111100001111000011110000
; 33:11111000011110000111100001111000
; 34:11111100001111000011110000111100
; 35:11111110000111100001111000011110
; 36:11111111000011110000111100001111
; 37:11111111100001111000011110000111
; 38:11111111110000111100001111000011
; 39:11111111111000011110000111100001
; 40:11111111111100001111000011110000
; 41:11111111111110000111100001111000
; 42:11111111111111000011110000111100
; 43:11111111111111100001111000011110
; 44:11111111111111110000111100001111
; 45:11111111111111111000011110000111
; 46:11111111111111111100001111000011
; 47:11111111111111111110000111100001
; 48:11111111111111111111000011110000
; 49:11111111111111111111100001111000
; 50:11111111111111111111110000111100
; 51:11111111111111111111111000011110
; 52:11111111111111111111111100001111
; 53:11111111111111111111111110000111
; 54:11111111111111111111111111000011
; 55:11111111111111111111111111100001
; 56:11111111111111111111111111110000
; 57:11111111111111111111111111111000
; 58:11111111111111111111111111111100
; 59:11111111111111111111111111111110
; 60:11111111111111111111111111111111
; 61:11111111111111111111111111111111
; 62:11111111111111111111111111111111
; 63:11111111111111111111111111111111

; C Backend 
; 00:11110000111100001111000011110000
; 01:11111000011110000111100001111000
; 02:11111100001111000011110000111100
; 03:11111110000111100001111000011110
; 04:11111111000011110000111100001111
; 05:11111111100001111000011110000111
; 06:11111111110000111100001111000011
; 07:11111111111000011110000111100001
; 08:11111111111100001111000011110000
; 09:11111111111110000111100001111000
; 10:11111111111111000011110000111100
; 11:11111111111111100001111000011110
; 12:11111111111111110000111100001111
; 13:11111111111111111000011110000111
; 14:11111111111111111100001111000011
; 15:11111111111111111110000111100001
; 16:11111111111111111111000011110000
; 17:11111111111111111111100001111000
; 18:11111111111111111111110000111100
; 19:11111111111111111111111000011110
; 20:11111111111111111111111100001111
; 21:11111111111111111111111110000111
; 22:11111111111111111111111111000011
; 23:11111111111111111111111111100001
; 24:11111111111111111111111111110000
; 25:11111111111111111111111111111000
; 26:11111111111111111111111111111100
; 27:11111111111111111111111111111110
; 28:11111111111111111111111111111111
; 29:11111111111111111111111111111111
; 30:11111111111111111111111111111111
; 31:11111111111111111111111111111111
; 32:11110000111100001111000011110000
; 33:11111000011110000111100001111000
; 34:11111100001111000011110000111100
; 35:11111110000111100001111000011110
; 36:11111111000011110000111100001111
; 37:11111111100001111000011110000111
; 38:11111111110000111100001111000011
; 39:11111111111000011110000111100001
; 40:11111111111100001111000011110000
; 41:11111111111110000111100001111000
; 42:11111111111111000011110000111100
; 43:11111111111111100001111000011110
; 44:11111111111111110000111100001111
; 45:11111111111111111000011110000111
; 46:11111111111111111100001111000011
; 47:11111111111111111110000111100001
; 48:11111111111111111111000011110000
; 49:11111111111111111111100001111000
; 50:11111111111111111111110000111100
; 51:11111111111111111111111000011110
; 52:11111111111111111111111100001111
; 53:11111111111111111111111110000111
; 54:11111111111111111111111111000011
; 55:11111111111111111111111111100001
; 56:11111111111111111111111111110000
; 57:11111111111111111111111111111000
; 58:11111111111111111111111111111100
; 59:11111111111111111111111111111110
; 60:11111111111111111111111111111111
; 61:11111111111111111111111111111111
; 62:11111111111111111111111111111111
; 63:11111111111111111111111111111111

Code: Select all

; SAL r15,cl or SAL ebx,cl or SHL edx,cl 
Define x.l = $FFFFFFFF
Define count_long.l
For count_long=0 To 63
  Define x_shl_by_long.l = x << count_long
  Debug RSet(Str(count_long),2,"0")+":"+Bin(x_shl_by_long,#PB_Long)
Next 
; ASM Backend x64 
; 00:11111111111111111111111111111111
; 01:11111111111111111111111111111110
; 02:11111111111111111111111111111100
; 03:11111111111111111111111111111000
; 04:11111111111111111111111111110000
; 05:11111111111111111111111111100000
; 06:11111111111111111111111111000000
; 07:11111111111111111111111110000000
; 08:11111111111111111111111100000000
; 09:11111111111111111111111000000000
; 10:11111111111111111111110000000000
; 11:11111111111111111111100000000000
; 12:11111111111111111111000000000000
; 13:11111111111111111110000000000000
; 14:11111111111111111100000000000000
; 15:11111111111111111000000000000000
; 16:11111111111111110000000000000000
; 17:11111111111111100000000000000000
; 18:11111111111111000000000000000000
; 19:11111111111110000000000000000000
; 20:11111111111100000000000000000000
; 21:11111111111000000000000000000000
; 22:11111111110000000000000000000000
; 23:11111111100000000000000000000000
; 24:11111111000000000000000000000000
; 25:11111110000000000000000000000000
; 26:11111100000000000000000000000000
; 27:11111000000000000000000000000000
; 28:11110000000000000000000000000000
; 29:11100000000000000000000000000000
; 30:11000000000000000000000000000000
; 31:10000000000000000000000000000000
; 32:0
; 33:0
; 34:0
; 35:0
; 36:0
; 37:0
; 38:0
; 39:0
; 40:0
; 41:0
; 42:0
; 43:0
; 44:0
; 45:0
; 46:0
; 47:0
; 48:0
; 49:0
; 50:0
; 51:0
; 52:0
; 53:0
; 54:0
; 55:0
; 56:0
; 57:0
; 58:0
; 59:0
; 60:0
; 61:0
; 62:0
; 63:0
; ASM Backend x86
; 00:11111111111111111111111111111111
; 01:11111111111111111111111111111110
; 02:11111111111111111111111111111100
; 03:11111111111111111111111111111000
; 04:11111111111111111111111111110000
; 05:11111111111111111111111111100000
; 06:11111111111111111111111111000000
; 07:11111111111111111111111110000000
; 08:11111111111111111111111100000000
; 09:11111111111111111111111000000000
; 10:11111111111111111111110000000000
; 11:11111111111111111111100000000000
; 12:11111111111111111111000000000000
; 13:11111111111111111110000000000000
; 14:11111111111111111100000000000000
; 15:11111111111111111000000000000000
; 16:11111111111111110000000000000000
; 17:11111111111111100000000000000000
; 18:11111111111111000000000000000000
; 19:11111111111110000000000000000000
; 20:11111111111100000000000000000000
; 21:11111111111000000000000000000000
; 22:11111111110000000000000000000000
; 23:11111111100000000000000000000000
; 24:11111111000000000000000000000000
; 25:11111110000000000000000000000000
; 26:11111100000000000000000000000000
; 27:11111000000000000000000000000000
; 28:11110000000000000000000000000000
; 29:11100000000000000000000000000000
; 30:11000000000000000000000000000000
; 31:10000000000000000000000000000000
; 32:11111111111111111111111111111111
; 33:11111111111111111111111111111110
; 34:11111111111111111111111111111100
; 35:11111111111111111111111111111000
; 36:11111111111111111111111111110000
; 37:11111111111111111111111111100000
; 38:11111111111111111111111111000000
; 39:11111111111111111111111110000000
; 40:11111111111111111111111100000000
; 41:11111111111111111111111000000000
; 42:11111111111111111111110000000000
; 43:11111111111111111111100000000000
; 44:11111111111111111111000000000000
; 45:11111111111111111110000000000000
; 46:11111111111111111100000000000000
; 47:11111111111111111000000000000000
; 48:11111111111111110000000000000000
; 49:11111111111111100000000000000000
; 50:11111111111111000000000000000000
; 51:11111111111110000000000000000000
; 52:11111111111100000000000000000000
; 53:11111111111000000000000000000000
; 54:11111111110000000000000000000000
; 55:11111111100000000000000000000000
; 56:11111111000000000000000000000000
; 57:11111110000000000000000000000000
; 58:11111100000000000000000000000000
; 59:11111000000000000000000000000000
; 60:11110000000000000000000000000000
; 61:11100000000000000000000000000000
; 62:11000000000000000000000000000000
; 63:10000000000000000000000000000000
; C Backend 
; 00:11111111111111111111111111111111
; 01:11111111111111111111111111111110
; 02:11111111111111111111111111111100
; 03:11111111111111111111111111111000
; 04:11111111111111111111111111110000
; 05:11111111111111111111111111100000
; 06:11111111111111111111111111000000
; 07:11111111111111111111111110000000
; 08:11111111111111111111111100000000
; 09:11111111111111111111111000000000
; 10:11111111111111111111110000000000
; 11:11111111111111111111100000000000
; 12:11111111111111111111000000000000
; 13:11111111111111111110000000000000
; 14:11111111111111111100000000000000
; 15:11111111111111111000000000000000
; 16:11111111111111110000000000000000
; 17:11111111111111100000000000000000
; 18:11111111111111000000000000000000
; 19:11111111111110000000000000000000
; 20:11111111111100000000000000000000
; 21:11111111111000000000000000000000
; 22:11111111110000000000000000000000
; 23:11111111100000000000000000000000
; 24:11111111000000000000000000000000
; 25:11111110000000000000000000000000
; 26:11111100000000000000000000000000
; 27:11111000000000000000000000000000
; 28:11110000000000000000000000000000
; 29:11100000000000000000000000000000
; 30:11000000000000000000000000000000
; 31:10000000000000000000000000000000
; 32:11111111111111111111111111111111
; 33:11111111111111111111111111111110
; 34:11111111111111111111111111111100
; 35:11111111111111111111111111111000
; 36:11111111111111111111111111110000
; 37:11111111111111111111111111100000
; 38:11111111111111111111111111000000
; 39:11111111111111111111111110000000
; 40:11111111111111111111111100000000
; 41:11111111111111111111111000000000
; 42:11111111111111111111110000000000
; 43:11111111111111111111100000000000
; 44:11111111111111111111000000000000
; 45:11111111111111111110000000000000
; 46:11111111111111111100000000000000
; 47:11111111111111111000000000000000
; 48:11111111111111110000000000000000
; 49:11111111111111100000000000000000
; 50:11111111111111000000000000000000
; 51:11111111111110000000000000000000
; 52:11111111111100000000000000000000
; 53:11111111111000000000000000000000
; 54:11111111110000000000000000000000
; 55:11111111100000000000000000000000
; 56:11111111000000000000000000000000
; 57:11111110000000000000000000000000
; 58:11111100000000000000000000000000
; 59:11111000000000000000000000000000
; 60:11110000000000000000000000000000
; 61:11100000000000000000000000000000
; 62:11000000000000000000000000000000
; 63:10000000000000000000000000000000
Also Linux.
User avatar
yuki
Enthusiast
Enthusiast
Posts: 101
Joined: Sat Mar 31, 2018 9:09 pm

Re: Bit-shifting uses inconsistent operand sizes versus ASM-backend

Post by yuki »

@juergenkulow thanks a bunch for that super clear demonstration between backends and architectures!
juergenkulow
Enthusiast
Enthusiast
Posts: 556
Joined: Wed Sep 25, 2019 10:18 am

Re: Bit-shifting uses inconsistent operand sizes versus ASM-backend

Post by juergenkulow »

Part Two:

Code: Select all

// Define x_shl_by_quad.l = x << count_quad    
        v_x_shl_by_quad=((quad)v_x<<v_count_quad);
                          ^

Define x_shl_inline.l  = x << 32
                              ^^
[07:30:07] [COMPILER] Zeile 8: The specified number is incorrect for '<<' or '>>' operators (must be 0-31).
Post Reply