Recent

Author Topic: Global variables alignment  (Read 6591 times)

Marladu

  • New Member
  • *
  • Posts: 19
Global variables alignment
« on: February 16, 2015, 01:35:27 am »
 I'm wondering how to make certain of global variable alignment in freepascal for win32. Here's some code where each and every variable is aligned to a 16byte boundary:

---------------------------------------------------
program Project1;

{$APPTYPE GUI}
{$align 1}

var
 b1,b2,b3,b4:byte;
 w1,w2,w3,w4:word;
 l1,l2,l3,l4:longint;
 q1,q2,q3,q4:int64;

begin
 b1:=1;b2:=2;b3:=3;b4:=4;
 w1:=1;w2:=2;w3:=3;w4:=4;
 l1:=1;l2:=2;l3:=3;l4:=4;
 q1:=1;q2:=2;q3:=3;q4:=4;

 if (longint(@b2)-longint(@b1))=16 then
  halt(1);

 if (b1+b2+b3+b4+w1+w2+w3+w4+l1+l2+l3+l4+q1+q2+q3+q4)=0 then
  halt(1);
end.
---------------------------------------------------

 According to the documentation (http://www.freepascal.org/docs-html/prog/progsu171.html) I expected the byte variables to be aligned on 1byte boundaries, word variables to be aligned on 2byte boundaries, and the others on 4byte boundaries. But every single variable is aligned on 16byte boundaries.

 Is there a way to control on what boundary global variables are aligned by free pascal?

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Global variables alignment
« Reply #1 on: February 16, 2015, 03:48:44 am »
Switch to the external assembler: -Aas
Optimize for size: -Og

On the other hand, odd alignment implies a structured data?
Code: [Select]
program project1;

{$APPTYPE GUI}
{$ALIGN 1}

type
TRec = packed record
 b1,b2,b3,b4:byte;
 w1,w2,w3,w4:word;
 l1,l2,l3,l4:longint;
 q1,q2,q3,q4:int64;
end;

var
  r: TRec;

begin
 with r do begin
 b1:=1;b2:=2;b3:=3;b4:=4;
 w1:=1;w2:=2;w3:=3;w4:=4;
 l1:=1;l2:=2;l3:=3;l4:=4;
 q1:=1;q2:=2;q3:=3;q4:=4;

 if (@b2-@b1)=16 then
  halt(1);

 if (b1+b2+b3+b4+w1+w2+w3+w4+l1+l2+l3+l4+q1+q2+q3+q4)=0 then
  halt(1);

 end;
end.

Notice that $ALIGN is for records.

Marladu

  • New Member
  • *
  • Posts: 19
Re: Global variables alignment
« Reply #2 on: February 16, 2015, 04:33:36 am »
 Yeah i realize that $align is for record field alignment. However for delphi xe7 (not sure when it was implemented) there's a little documented keyword to choose memory alignment of global variables like so:

type
 record_align8=record
  a,b,c:longint;
 end align 8;

 It's not a functionality i'm missing in free pascal if global variables are always aligned on 16byte boundaries, but what I'd like to know is what are the rules of global variable alignment since they seem to differ from what the documentation states, and what are the ways to influence them.

 As for optimize for size the documentation page I linked lists what it should give but I didn't try it.
« Last Edit: February 16, 2015, 04:46:16 am by Marladu »

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Global variables alignment
« Reply #3 on: February 16, 2015, 05:18:36 am »
However for delphi xe7 (not sure when it was implemented) there's a little documented keyword to choose memory alignment of global variables

Any link to its documentation?

like so:

type
 record_align8=record
  a,b,c:longint;
 end align 8;

The example you gave is to declare a type not a variable. Would adding "align 8" align the elements of the record, or global variables of type record_align8?

Marladu

  • New Member
  • *
  • Posts: 19
Re: Global variables alignment
« Reply #4 on: February 16, 2015, 05:49:43 pm »
However for delphi xe7 (not sure when it was implemented) there's a little documented keyword to choose memory alignment of global variables

Any link to its documentation?

like so:

type
 record_align8=record
  a,b,c:longint;
 end align 8;

The example you gave is to declare a type not a variable. Would adding "align 8" align the elements of the record, or global variables of type record_align8?

 The effect of that keyword is that global variables of that type will be aligned on memory boundaries that are multiples of the specified value. For example:

type
 record_align8=record
  a,b,c:longint;
 end align 8;
 record_align16=record
  a,b,c:longint;
 end align 16;
var
 aligned8:record_align8;   // this global variable will be aligned to memory addresses ending in $0 or $8 only
 aligned16:record_align16; // this global variable will be aligned to memory addresses ending in $0 only

 This won't cause this type if used as a record field to be aligned like with the {$align} directive though.

 As for official documentation I can't seem to find any right now, perhaps it is not documented yet? Dunno how I found out about it then, but I've been using it for a couple months to properly align constants used by SSE code.

 But regardless of what delphi does, I'd like to go back to the subject of this thread and find  out what the rules of global variable alignment for win32 are in free pascal since they don't seem to match the documentation listed in the first post. For now it appears to be that all global variables are always aligned to 16byte memory boundaries on win32 target.

edit: here's a link where an example is shown (in the second answer): http://stackoverflow.com/questions/8460862/what-does-packed-now-forces-byte-alignment-of-records-mean . So it seems it's been supported since delphi xe2.
« Last Edit: February 16, 2015, 05:54:46 pm by Marladu »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Global variables alignment
« Reply #5 on: February 16, 2015, 09:06:29 pm »
You can still solve all your aligning problems by wrapping them inside records?
Code: [Select]
{$ALIGN 1}
...
TGlobalVarPack1 = record
  a, b: byte;
  c, d: byte;
end; // sizeof 4 bytes

var
  gv1: TGlobalVarPack1;

implementation
...
Any mistakes there, or should it just be packed record?

Marladu

  • New Member
  • *
  • Posts: 19
Re: Global variables alignment
« Reply #6 on: February 18, 2015, 04:30:00 pm »
 Thanks to a nice contributor to a different question on this forum this issue is fully resolved now. There's a variation on the compiler directive {$codealign} that guarantees results I was looking for: {$CODEALIGN VARMIN=xxx}.