[solved] Is the FreeBASIC array alignment safe ?

General FreeBASIC programming questions.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

[solved] Is the FreeBASIC array alignment safe ?

Post by D.J.Peters »

There is a standard C++ high optimized header only math library glm for all platforms. (it based on SSE, NEON, AVX ...)
https://github.com/g-truc/glm
I compiled a C99 cglm static lib for FreeBASIC which are not usable, the SSE, NEON, AVX stuff are in lined in the headers not in the static lib itself.
https://github.com/recp/cglm
Than I compiled shared 32/64-bit lib's now the problem are vec4() and mat(2) and mat(4) must be minimum aligned(16) SINGLE/float arrays !

Code: Select all

typedef float                   vec2[2];
typedef float                   vec3[3];
typedef int                    ivec3[3];
typedef CGLM_ALIGN_IF(16) float vec4[4];
typedef vec4                    versor;     /* |x, y, z, w| -> w is the last */
typedef vec3                    mat3[3];
typedef CGLM_ALIGN_IF(16) vec2  mat2[2];
typedef CGLM_ALIGN_MAT    vec4  mat4[4];
I made this short fbc array info test and it looks good but is it save for fixed length float arrays ?
Is it the same for fbc ARM (NEON) and what is if an fixed size array are dim'ed temporary inside of sub/functions are they allocated aligned on stack ?

Joshy

Code: Select all

#include "fbc-int/array.bi"

function flagsString(flags as uinteger) as string
  return str(flags and &h0000000f) & " allocated dims " & _
  iif(flags and &h00000010,"dimensions are fixed " ," ") & _
  iif(flags and &h00000020,"memory is fixed lenght" ,"") 
end function

function alignedString(adr as uinteger) as string
  if (adr and 31) = 0 then return " aligned(32)"
  if (adr and 15) = 0 then return " aligned(16)"
  if (adr and  7) = 0 then return " aligned(8)"
  return " not SSE aligned !"
end function

sub printArrayInfo(array() as const single) 
  var p=FBC.ArrayConstDescriptorPtr(array())
  print "index_ptr         " & str(p->index_ptr) & alignedString(cast(uinteger,p->index_ptr))
  print "base_ptr          " & p->base_ptr & alignedString(cast(uinteger,p->base_ptr))
  print "size              " & p->size
  print "element_len       " & p->element_len
  print "dimensions        " & p->dimensions
  print "flags             " & p->flags & " " & flagsString(p->flags)
  if p->dimensions<1 then return
  for i as uinteger = 0 to p->dimensions-1
    print "dimtb(" & i & ").elements " & p->dimtb(i).elements
    print "dimtb(" & i & ").lbound   " & p->dimtb(i).lbound
    print "dimtb(" & i & ").ubound   " & p->dimtb(i).ubound
    print
  next
end sub

dim as single vec3(2)
dim as single vec4(3)
dim as single mat4(15)
print "vec3()"
printArrayInfo(vec3())
print
print "vec4()"
printArrayInfo(vec4())
print
print "mat4()"
printArrayInfo(mat4())
print
sleep
Last edited by D.J.Peters on Jun 17, 2021 10:31, edited 2 times in total.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Is the FreeBASIC array alignment safe ?

Post by jj2007 »

Hi Joshy,

Your code throws lots of errrors, so I can't test it. Therefore, out of my belly: I would be surprised if arrays were aligned 16. The Windows HeapAlloc() etc functions are all align 8. To get align 16, you need some acrobatics. It's not too difficult, so the FB developers might put it on their todo list ;-)
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Is the FreeBASIC array alignment safe ?

Post by fxm »

To be compiled with fbc >= 1.08.

It doesn't change anything for your chosen examples (all arrays beginning at '0' index), but more generally the start of memory at array lowest bounds (alignment) is 'base_ptr' and not 'index_ptr' (@array(0, 0, 0, ... ) that may be even virtual).
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Is the FreeBASIC array alignment safe ?

Post by fxm »

Otherwise there is in addition a typo in your code:
print "index_ptr " & str(p->index_ptr) & alignedString(cast(uinteger,@p->index_ptr))
print "index_ptr " & str(p->index_ptr) & alignedString(cast(uinteger,p->index_ptr))

but that does not change your final conclusion.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: Is the FreeBASIC array alignment safe ?

Post by D.J.Peters »

jj2007 wrote:Your code throws lots of errors, so I can't test it.
I use 1.08.0 !
jj2007 wrote:I would be surprised if arrays were aligned 16. The Windows HeapAlloc() etc functions are all align 8.
You are right :-(

I fixed the mistake and it shows 1 dimensional fixed size arrays are guaranteed only 8 bytes aligned.

So array's are not the right option for the high performance math library.

But the good points are C/C++ array's are simple pointers under the hood.

May be a TYPE in FreeBASIC with overloaded aligned NEW operator can be the solution.

The class destructor can used a overloaded delete operator to free the original unaligned pointer.
(same as the aligned FB Image pointer)

I must think about a working solution.

Joshy
Lost Zergling
Posts: 538
Joined: Dec 02, 2011 22:51
Location: France

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by Lost Zergling »

An array twice as large and a wrapper ( Fix(i/2+1) ) (1 dim) on the index ? Would require to implement index wrapping capabilities (tasting like lzae stepcursor) into the library (whenever unsupported) maybe ? Just an idea, don't know.
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Is the FreeBASIC array alignment safe ?

Post by fxm »

D.J.Peters wrote:May be a TYPE in FreeBASIC with overloaded aligned NEW operator can be the solution.
Yes but only for a fix-len array inside a UDT.
See my second example at Operator New Overload documentation page.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by D.J.Peters »

This here works as excepted there is only one problem
FreeBASIC does not call the overloaded delete operator self
Is there a way to call the overloaded delete operator from the destructor ?

I mean delete b are not called by the user and the termination of the exe doesn't call delete ?

Code: Select all

#ifndef NULL
#define NULL cptr(any ptr,0)
#endif

function AlignAlloc(byval nBytes as uinteger) as any ptr
  const as uinteger ALIGN = 15, MASK = NOT ALIGN
  const as uinteger PSIZE = sizeof(any ptr) 
  if nBytes<1 then return NULL
  dim as any ptr o = allocate(nBytes + PSIZE + ALIGN)
  dim as any ptr p = cptr(any ptr,((cast(uinteger,o) + PSIZE + ALIGN) and MASK))
  cptr(any ptr ptr,p)[-1] = o
  return p
end function

sub AlignFree(byref p as any ptr)
  if p then
    var o = cptr(any ptr ptr,p)[-1]
    if o then deallocate o
    p = NULL
  end if 
end sub

type vec4
  declare destructor
  declare constructor(byref x as const single=0, _
                      byref y as const single=0, _
                      byref z as const single=0, _
                      byref w as const single=1)
  declare operator new (byval size as uinteger) as any ptr
  declare operator delete (byval buf as any ptr)
  declare operator cast as single ptr
  declare operator cast as string
  as single x,y,z,w
end type
destructor vec4
  print "detructor:" & @this
  'this.delete @this
end destructor
constructor vec4(byref a as const single, _
                 byref b as const single, _
                 byref c as const single, _
                 byref d as const single)
  x=a:y=b:z=c:w=d
  print "constructor: " & this 
end constructor
operator vec4 . new (ByVal size As UInteger) As Any Ptr
  print "new:" & size
  return AlignAlloc(size) 
end operator
operator vec4 . delete (ByVal buf As Any Ptr)
  print "delete:" & buf
  AlignFree(buf)
end operator
operator vec4 . cast as single ptr
  return @this.x
end operator
operator vec4 . cast as string
  return @this & " -> [" & x & ", " & y  & ", " & z  & ", " & w & "]"
end operator

var a = new vec4
var b = new vec4(1,2,3,4)
print *a
print *b
delete a
'delete b
sleep
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by fxm »

I don't see where is the problem.
If you un-comment this line
'delete b ' <--- b never deleted by FreeBASIC (the OS free all memory OK but)
that works.
(everything else would be unsafe)
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by srvaldez »

I think it bad practice not to clean up after yourself, some coders like to allocate memory but don't bother to free it because they expect the OS to do it for them
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by dodicat »

This seems to align arrays off the stack.
But not to be taken seriously.
fb 1.08
win 10

Code: Select all

#include "fbc-int/array.bi"

function flagsString(flags as uinteger) as string
  return str(flags and &h0000000f) & " allocated dims " & _
  iif(flags and &h00000010,"dimensions are fixed " ," ") & _
  iif(flags and &h00000020,"memory is fixed lenght" ,"")
end function

function alignedString(adr as uinteger) as string
  if (adr and 31) = 0 then return " aligned(32)"
  if (adr and 15) = 0 then return " aligned(16)"
  if (adr and  7) = 0 then return " aligned(8)"
  return " not SSE aligned !"
end function

sub printArrayInfo(array() as const single)
  var p=FBC.ArrayConstDescriptorPtr(array())
  print "index_ptr         " & str(p->index_ptr) & alignedString(cast(uinteger,p->index_ptr))
  print "base_ptr          " & p->base_ptr & alignedString(cast(uinteger,p->base_ptr))
  print "size              " & p->size
  print "element_len       " & p->element_len
  print "dimensions        " & p->dimensions
  print "flags             " & p->flags & " " & flagsString(p->flags)
  if p->dimensions<1 then return
  for i as uinteger = 0 to p->dimensions-1
    print "dimtb(" & i & ").elements " & p->dimtb(i).elements
    print "dimtb(" & i & ").lbound   " & p->dimtb(i).lbound
    print "dimtb(" & i & ").ubound   " & p->dimtb(i).ubound
    print
  next
end sub

sub align(s() as single,n as long)
    redim s(0)
    dim as long flag=0,count
    do
        count+=1
        var i=cast(uinteger,@s(0))
        locate 
     if  (i mod 32<>0) and (i mod 16=0) then return
    redim s(0 to count+n+1)
    loop
end sub


redim as single vec3(),vec4(),mat4()
align(vec3(),2)
align(vec4(),3)
align(mat4(),15)
redim vec3(2)
redim vec4(3)
redim mat4(15)

print "vec3()"
printArrayInfo(vec3())
print
print "vec4()"
printArrayInfo(vec4())
print
print "mat4()"
printArrayInfo(mat4())
print
sleep 
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by fxm »

fbc 1.08 32-bit, win 10: infinite loop (in 'align()') with my PC.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by dodicat »

It is OK here fxm, 32/64 bits
But it is definitely generally doable probably, I'll mess around later.
If byref arrays were possible then this problem would be easy to solve, create a dummy array at least the size of everything you want, and mark suitable slots (mod32<>0 and mod 16=0) and share these slots with working arrays.
Are byref arrays on the cards I wonder?
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by dodicat »

This seems to work better.
Do it in the main module by macro.
Or you can make the macro a sub, still works.

Code: Select all


#include "fbc-int/array.bi"

function flagsString(flags as uinteger) as string
  return str(flags and &h0000000f) & " allocated dims " & _
  iif(flags and &h00000010,"dimensions are fixed " ," ") & _
  iif(flags and &h00000020,"memory is fixed lenght" ,"")
end function

function alignedString(adr as uinteger) as string
  if (adr and 31) = 0 then return " aligned(32)"
  if (adr and 15) = 0 then return " aligned(16)"
  if (adr and  7) = 0 then return " aligned(8)"
  return " not SSE aligned !"
end function

sub printArrayInfo(array() as const single)
  var p=FBC.ArrayConstDescriptorPtr(array())
  print "index_ptr         " & str(p->index_ptr) & alignedString(cast(uinteger,p->index_ptr))
  print "base_ptr          " & p->base_ptr & alignedString(cast(uinteger,p->base_ptr))
  print "size              " & p->size
  print "element_len       " & p->element_len
  print "dimensions        " & p->dimensions
  print "flags             " & p->flags & " " & flagsString(p->flags)
  if p->dimensions<1 then return
  for i as uinteger = 0 to p->dimensions-1
    print "dimtb(" & i & ").elements " & p->dimtb(i).elements
    print "dimtb(" & i & ").lbound   " & p->dimtb(i).lbound
    print "dimtb(" & i & ").ubound   " & p->dimtb(i).ubound
    print
  next
end sub

#macro align(s,n)
scope
redim s(0)
    dim as long count
    do
        count+=1
        var i=cast(uinteger,@s(0))
     if  (i mod 32<>0) and (i mod 16=0) then exit do
     redim as byte b(count)
    redim s(0 to n+count)
loop
redim preserve s(n)
end scope
#endmacro

redim as single vec3(),vec4(),mat4(),tst()
align(vec3,2)
align(vec4,3)
align(mat4,15)
align(tst,5)


print "vec3()"
printArrayInfo(vec3())
print
print "vec4()"
printArrayInfo(vec4())
print
print "mat4()"
printArrayInfo(mat4())
print
print "test()"
printArrayInfo(tst())
print
sleep
 
Tested 32/64 bits and gas
fxm
Moderator
Posts: 12108
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: [solved] Is the FreeBASIC array alignment safe ?

Post by fxm »

With gas 32-bit:

Code: Select all

vec3()
index_ptr         35995728 aligned(16)
base_ptr          35995728 aligned(16)
size              12
element_len       4
dimensions        1
flags             8 8 allocated dims
dimtb(0).elements 3
dimtb(0).lbound   0
dimtb(0).ubound   2


vec4()
index_ptr         11142320 aligned(16)
base_ptr          11142320 aligned(16)
size              16
element_len       4
dimensions        1
flags             8 8 allocated dims
dimtb(0).elements 4
dimtb(0).lbound   0
dimtb(0).ubound   3


mat4()
index_ptr         11145928 aligned(8)
base_ptr          11145928 aligned(8)
size              64
element_len       4
dimensions        1
flags             8 8 allocated dims
dimtb(0).elements 16
dimtb(0).lbound   0
dimtb(0).ubound   15


test()
index_ptr         11146000 aligned(16)
base_ptr          11146000 aligned(16)
size              24
element_len       4
dimensions        1
flags             8 8 allocated dims
dimtb(0).elements 6
dimtb(0).lbound   0
dimtb(0).ubound   5
See the alignment of 'mat4()'!

In any case, nothing justifies the principle of your algorithm.
Post Reply