FBC 32bit - Macro problem [solved]

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

FBC 32bit - Macro problem [solved]

Post by MrSwiss »

Hi all,

a perfectly fine working single line Macro (a #Define), in FBC 64bit = all OK, however, in FBC 32bit:
FBC 32 wrote:Macro_vs_Union.bas(26) warning 33(0): Shift value greater than or equal to number of bits in data type

Make done
Executable returns wrong results ... I suspect it's (once again) the use of Integer (behind the scenes)!
Equally no problem is the used Union! (both versions of compiler)

This issue can't be forced, even with: CULngInt(...whatever), or, Cast(ULongInt, ...whatever)
Just to make things clear: the Function mk64() works perfectly, in both compiler versions!

It's the #Define mk64_() that has the problem. Is there any way to force its result to ULongInt?
Then the shift by 32 should work ...

see example code below:

Code: Select all

' Macro_vs_Union.bas -- 2017-03-21, by MrSwiss

Union UI_64 ' little endian!
    As ULongInt     UI64
    Type 
        As ULong    hi32
        As ULong    lo32
    End Type
End Union

Dim As UI_64 cc64

With cc64   ' little endian!
    .hi32 = &hCCDDEEFF
    .lo32 = &h8899AABB
End With
' End Union

' single line MACROS, instead of Union
' Function mk64() needed for FBC 32 (now also used for FBC 64)
Declare Function mk64( ByVal As ULong, ByVal As ULong) As ULongInt
#Define mk64_(l,h)   ( h Or l Shl 32 )       ' OK: FBC 64 -gen GCC | NOK: FBC 32 -gen GAS
#Define Hi32(ll)    ( ll And &hFFFFFFFF )   ' getter - high 32bit
#Define Lo32(ll)    ( ll Shr 32 )           ' getter - low 32bit

'Dim As ULongInt tt = mk64_(cc64.lo32, cc64.hi32) ' described error FBC 32 / OK in FBC 64
Dim As ULongInt tt = mk64(cc64.lo32, cc64.hi32) ' using Union's values + set Function
' End Macro's

Width 80, 25
Print : Color 10
Print "using the UNION:"
Print String(16, "-")
Print "Union - LO32: "; Hex(cc64.lo32, 8)
Print "Union - HI32: "; Hex(cc64.hi32, 8)
Print
Print "Union - cc64: "; Hex(cc64.UI64, 16)
Print : Color 15
' ----------------------
Print String(60, "~")   ' screen delimiter
' ----------------------
Print : Color 11
Print "using the MACROS/Function:"
Print String(26, "-")
Print "ULL 64bit: "; Hex(tt, 16)
Print
Print "UL - HI32: "; Hex(Hi32(tt), 8)       ' using get Macro
Print "UL - LO32: "; Hex(Lo32(tt), 8)       ' using get Macro
Locate CsrLin + 2 : Color 7
Print "any user action --> EXIT!";

Sleep

Function mk64( ByVal lo As ULong, ByVal hi As ULong) As ULongInt
    Asm     ' works with FBC-WIN 32/64 (tested: ver. 1.05.0)
        mov eax, dword Ptr [hi]
        mov edx, dword Ptr [lo]
        mov dword Ptr [Function], eax
        mov dword Ptr [Function + 4], edx
    End Asm
End Function
Last edited by MrSwiss on Mar 22, 2017 9:58, edited 1 time in total.
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: FBC 32bit - Macro problem

Post by sancho2 »

Why do you say it can't be forced with a cast:
This seems to work:

Code: Select all

#Define mk64_(l,h)   ( h Or Cast(ULongInt, l) Shl 32 )       ' OK: FBC 64 -gen GCC | NOK: FBC 32 -gen GAS
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FBC 32bit - Macro problem [solved]

Post by MrSwiss »

sancho2 wrote:This seems to work:

Code: Select all

#Define mk64_(l,h)   ( h Or Cast(ULongInt, l) Shl 32 )
It does, thanks a lot, full marks!

My error was to try and Cast the expression, instead of the variable only:

Code: Select all

#Define mk64_(l,h)  ( h Or CULngInt(l Shl 32) ) ' <-- not working
#Define mk64_(l,h)  ( h Or CULngInt(l) Shl 32 ) ' <-- OK - sancho2's idea
This case is solved! The devil was in the details, as usual.

A classical case of *tunnel vision* ... one can't see the light anymore.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: FBC 32bit - Macro problem [solved]

Post by counting_pine »

Code: Select all

Union UI_64 ' little endian!
    As ULongInt     UI64
    Type 
        As ULong    hi32
        As ULong    lo32
    End Type
End Union
That's big endian, is it not? Little-endian starts with the least significant byte.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FBC 32bit - Macro problem [solved]

Post by MrSwiss »

@counting_pine, have you compiled/run the code? Compared with the ASM Function etc.?
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: FBC 32bit - Macro problem [solved]

Post by counting_pine »

There seems to be an inconsistency throughout the code about the meaning of low/high/little-endian.
A convention borne out of the little-endian system - in many cases a necessary one - is to put the low part (least significant) before the high part (most significant).
The only exception is when the number is printed as a whole, which happens (whether in decimal or hex) in a human-readable big-endian fashion.
(This can be confusing, because in the hexadecimal layout, the high part will appear in front of the low part.)

Anyway, I tried changing your code to work from a consistently little-endian perspective (except for the long hex() readout). In some cases this involved swapping some definitions around, in other cases just a passive reordering of expressions.

Code: Select all

' Macro_vs_Union.bas -- 2017-03-21, by MrSwiss
' Changes made 2017-03-25, by counting_pine

Union UI_64 ' little endian
    As ULongInt     UI64
    Type
        As ULong    lo32
        As ULong    hi32
    End Type
End Union

Dim As UI_64 cc64

With cc64  ' little endian
    .lo32 = &hBBAA9988
    .hi32 = &hFFEEDDCC
End With

' single line MACROS, instead of Union
Declare Function mk64( ByVal lo As ULong, ByVal hi As ULong) As ULongInt
#Define mk64_(l,h)   ( l Or culngint(h) Shl 32 )  ' OK: FBC 64 -gen GCC | NOK: FBC 32 -gen GAS
#Define Lo32(ll)    ( ll And &hFFFFFFFFull )      ' getter - high 32bit
#Define Hi32(ll)    ( culngint(ll) Shr 32 )       ' getter - low 32bit

Dim As ULongInt tt_ = mk64_(cc64.lo32, cc64.hi32) ' described error FBC 32 / OK in FBC 64
Dim As ULongInt tt = mk64(cc64.lo32, cc64.hi32) ' using Union's values + set Function
' End Macro's

ASSERT(tt_ = tt_)

Print : Color 10
Print "using the UNION:"
Print String(16, "-")
Print "Union - LO32: "; Hex(cc64.lo32, 8)
Print "Union - HI32: "; Hex(cc64.hi32, 8)
Print
Print "Union - cc64: "; Hex(cc64.UI64, 16)
Print : Color 15
' ----------------------
Print String(60, "~")   ' screen delimiter
' ----------------------
Print : Color 11
Print "using the MACROS/Function:"
Print String(26, "-")
Print "ULL 64bit: "; Hex(tt, 16)
Print
Print "UL - LO32: "; Hex(Lo32(tt), 8)       ' using get Macro
Print "UL - HI32: "; Hex(Hi32(tt), 8)       ' using get Macro
Locate CsrLin + 2 : Color 7
Print "any user action --> EXIT!";

Sleep

Function mk64( ByVal lo As ULong, ByVal hi As ULong) As ULongInt
    Asm     ' works with FBC-WIN 32/64 (tested: ver. 1.05.0)
        mov eax, dword Ptr [lo]
        mov edx, dword Ptr [hi]
        mov dword Ptr [Function], eax
        mov dword Ptr [Function + 4], edx
    End Asm
End Function
I also fixed the macros so they should be 32/64-bit friendly. e.g. casting to ulongint before shifts, and making sure &HFFFFFFFF is an unsigned 64-bit version (to prevent it being interpreted as a signed 32-bit version).

I'm happy now that there is a consistency between the name, usage and ordering of hi/lo, and the code all seems to work as I would expect.

The only practical change that would be needed to work on a big-endian architecture would be to swap around lo32 and hi32 in the union, and to swap [Function] and [Function + 4] in the asm - although of course the latter is x86-specific anyway, and hence intrinsically little-endian.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FBC 32bit - Macro problem [solved]

Post by MrSwiss »

@counting_pine,

thanks for your effort. To settle this Union ordering issue, I've made additional tests with
what is, probably, the most common used Union of all: Color-Channels ...
It turns out, that the UBytes order (within the ULong) have to be: top/down-->MSB/LSB in
order, to have a functioning Alpha blending, in the following example:

Code: Select all

' Colour_Union_2.bas -- 2017-04-11, MrSwiss

' cchan = color-channel, range: 0 to 255 (UByte), see Union below
#Define cchan(p)    ( CUByte(p * 2.55) )    ' p = percent (input)

Union colour        ' BE since, AE: Color is a FB-keyword
    As ULong clr    ' UINT(32)
    Type
        As UByte b  ' MSB - blue  channel
        As UByte g  '       green channel
        As UByte r  '       red   channel
        As UByte a  ' LSB - alpha channel
    End Type
End Union

Dim As colour   c1, c2
' initialize color's (Union's)
c1.clr = &hFF0000FF ' blue opaque (alpha = 255 = &hFF)
c2.clr = &h00DF5F00 ' orange transparent (alpha = 0 = &h00)

' ===== MAIN =====
ScreenRes(301, 301, 32)
Color(&hFF000000, &hFFFFFFFF) : Cls         ' black(fg) on white(bg)

Dim As Any Ptr IMG = ImageCreate(301, 301, &h00FF00FF, 32)

For i As UInteger = 0 To 24                 ' construct image ...
    Var cc = i * 100 / 24, xy = i * 10 + 20 ' percentage | position
    c2.a = cchan(cc)                        ' get alpha by percent
    Circle IMG, (xy, xy), i, c2.clr,,,, F   ' orange filled circle
    Circle IMG, (xy, xy), i + 1, c1.clr     ' blue border (around it)
Next

Put (0, 0), IMG, Alpha                      ' image to screen
ImageDestroy(IMG) : IMG = 0                 ' clean up ...

Sleep                                       ' wait for user input
' ===== END-MAIN ===== '    ' ----- EOF ----- '
The second thing that had me puzzled:
counting_pine wrote:The only exception is when the number is printed as a whole, which happens (whether in decimal or hex) in a human-readable big-endian fashion.
(This can be confusing, because in the hexadecimal layout, the high part will appear in front of the low part.)
Above tested in code (at least with HEX()) does not seem to be the case, too ...

Code: Select all

' HEX_keyword.bas -- 2017-04-11, by MrSWiss

' parameters: see implementation's comment's
Declare Sub VStringCP ( ByVal As UByte = 1, ByVal As UByte = 1, ByRef As String, ByVal As UByte = 7 )
Declare Sub HStringCP ( ByVal As UByte = 1, ByVal As UByte = 1, ByRef As String, ByVal As UByte = 7 )

Const As ULong      c  = &hFF00007F
Const As ULongInt   cc = &hFF00007FFF00007F

' ===== MAIN =====
Width 80, 25    ' standard console settings (mine is by default 'larger')
HStringCP( , 19, "HEX_keyword.bas -- 2017-04-11, by MrSWiss", 14)

VStringCP(3, 30, "LSB|", 9) : VStringCP(3, 37, "MSB|", 9)
HStringCP(7,, "STRING &hFF00007F:", 15)
HStringCP(7, 30, Hex(c, 8), 15) : HStringCP(7, 50, "ULong", 15)

VStringCP(9, 30, "LSB|", 9) : VStringCP(9, 45, "MSB|", 9)
HStringCP(13,, "STRING &hFF00007FFF00007F:", 15)
HStringCP(13, 30, Hex(cc, 16), 15) : HStringCP(13, 50, "ULongInt", 15)

HStringCP(17, 23, "any user action --> EXIT prog. ", 4)

Sleep
' ===== END-MAIN =====
Sub VStringCP ( ByVal row  As UByte = 1, _  ' vertical start pos.
                ByVal col  As UByte = 1, _  ' horizontal start pos.
                ByRef strg As String, _     ' string (to print)
                ByVal clr  As UByte = 7 )   ' color
    Var lS = Len(strg) - 1          ' upper bound of string index
    Color clr : Locate ,, 0         ' set color | cursor OFF
    ' vertical character printing (one every row), no LF
    For v As UInteger = 0 To lS
        Locate row + v, col : Print Chr(strg[v]);
    Next
    Color 7 : Locate row, col+1, 1  ' reset color | pos. cursor + ON
End Sub

Sub HStringCP ( ByVal row  As UByte = 1, _  ' vertical start pos.
                ByVal col  As UByte = 1, _  ' horizontal start pos.
                ByRef strg As String, _     ' string (to print)
                ByVal clr  As UByte = 7 )   ' color
    Color clr   : Locate row, col   ' set color | position cursor
    Print strg; : Color 7           ' Print, no LF | reset color 
End Sub
' ----- EOF -----
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FBC 32bit - Macro problem [solved]

Post by fxm »

Is it safer to impose a field alignment without any padding bytes for this kind of declaration?

Code: Select all

Union colour field=1  ' BE since, AE: Color is a FB-keyword
    As ULong clr      ' UINT(32)
    Type field=1
        As UByte b    ' MSB - blue  channel
        As UByte g    '       green channel
        As UByte r    '       red   channel
        As UByte a    ' LSB - alpha channel
    End Type
End Union
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FBC 32bit - Macro problem [solved]

Post by MrSwiss »

@fxm,
not certain, to understand your question correctly, but I'd do it as follows (if forced to do it):

Code: Select all

Union colour field=4  ' BE since, AE: Color is a FB-keyword
    As ULong clr      ' UINT(32)
    Type field=1
        As UByte b    ' MSB - blue  channel
        As UByte g    '       green channel
        As UByte r    '       red   channel
        As UByte a    ' LSB - alpha channel
    End Type
End Union
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: FBC 32bit - Macro problem [solved]

Post by fxm »

It's rather a question for admin (dkl or counting_pine).


For example:

- Incorrect as for that wanted:

Code: Select all

Union test
  Type
    Dim As Short s
    Dim As Long l
    Dim As Longint li
  End Type
  Type
    Dim As Byte b(13)
  End Type
End Union

Print Sizeof(test)

Print Offsetof(test, s);
Print Offsetof(test, l);
Print Offsetof(test, li)

For I As Integer = 0 To 13
  Print Offsetof(test, b(I));
Next I
Print

Sleep

Code: Select all

 16
 0 4 8
 0 1 2 3 4 5 6 7 8 9 10 11 12 13
- Correct as for that wanted:

Code: Select all

Union test field=1
  Type
    Dim As Short s
    Dim As Long l
    Dim As Longint li
  End Type
  Type
    Dim As Byte b(13)
  End Type
End Union

Print Sizeof(test)

Print Offsetof(test, s);
Print Offsetof(test, l);
Print Offsetof(test, li)

For I As Integer = 0 To 13
  Print Offsetof(test, b(I));
Next I
Print

Sleep

Code: Select all

 14
 0 2 6
 0 1 2 3 4 5 6 7 8 9 10 11 12 13
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FBC 32bit - Macro problem [solved]

Post by dodicat »

Regarding the original Macro/union (concatenation)
This uses neither.
Seems OK 32/64 bit.

Code: Select all


Function mkulongint(n1 As Ulong,n2 As Ulong) As Ulongint
    Dim As Ulongint res
    Cast(Ulong Ptr,@res)[0]=n1
    Cast(Ulong Ptr,@res)[1]=n2
    Return res
End Function

Sub getulongs(n As Ulongint, Byref L1 As Ulong,Byref L2 As Ulong)
    L1=Cast(Ulong Ptr,@n)[0]
    L2=Cast(Ulong Ptr,@n)[1]
End Sub

'4294967295 max ulong


Dim As Ulongint u=mkulongint(4294967294,4294967295)
Print u

Dim As Ulong L1,L2

getulongs(u,L1,L2)
Print L1,L2


Print
Print
u=mkulongint(12,13)
Print u
getulongs(u,L1,L2)
Print L1,L2
Sleep  
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: FBC 32bit - Macro problem [solved]

Post by counting_pine »

MrSwiss wrote:The second thing that had me puzzled:
counting_pine wrote:The only exception is when the number is printed as a whole, which happens (whether in decimal or hex) in a human-readable big-endian fashion.
(This can be confusing, because in the hexadecimal layout, the high part will appear in front of the low part.)
Above tested in code (at least with HEX()) does not seem to be the case, too ...
I'm sorry, I don't understand what you're trying to do with your code..
All I can say is that by convention hexadecimal numbers (like decimal numbers) are written with the MSB at the start and the LSB at the end - the opposite way to the diagram produced by your code.
I would write a hexadecimal number like this:

Code: Select all

&H44332211
The MSB is 44 and the LSB is 11.

And I would write the hexadecimal bytes that make up a little-endian number like this:

Code: Select all

11 22 33 44
Again, the MSB is 44 and the LSB is 11.
Each byte is big endian, but the sequence of bytes is little-endian.

You are correct with the colour byte ordering: The 24-bit format is &HRRGGBB. The 32-bit format is &HAARRGGBB. The byte ordering is: BB GG RR AA (i.e. blue is first, alpha is last).

When we write numbers, we prefer the most significant digit first. When we store large numbers in memory - say, an array of integers - we tend to want to store the least significant digit first, and increase in significance the further through the array we go.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: FBC 32bit - Macro problem [solved]

Post by MrSwiss »

Hi counting_pine,

now, you might say: at long last, the Penny has dropped, since writing HEX numbers (in code) vs. it's *layout* (in mem) are different.
The last of your explanations did it, thanks a ton for your patience, in explaining the "nitty-gritty" stuff ...

This portion did the trick:
counting_pine wrote:I would write a hexadecimal number like this:

Code: Select all

&H44332211
The MSB is 44 and the LSB is 11.

And I would write the hexadecimal bytes that make up a little-endian number like this:

Code: Select all

11 22 33 44
Again, the MSB is 44 and the LSB is 11.
Each byte is big endian, but the sequence of bytes is little-endian.
Post Reply