Sign in Join

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

Mailing lists / fpc-pascal / 2007-11

memory aligning

3 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

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

David Pethes

Hi,
I'm writing a video codec. I need some of my memory aligned to 16-byte boundaries, since I'm using SSE2 instructions in asm code, that assume this alignment. I was using a custom getmem, that called classic getmem to get some memory block, then cast the pointer and adjust it to next aligned address. Offset to original pointer was saved as byte at (aligned_address - 1). Custom freemem took aligned pointer, read the address (ptr-1) to get the offset, set the original pointer address and call the classic freemem.
This worked well, though compiler was complaining about that casting the pointer to int was not portable. I discovered the Align() function in system unit, so I modified the code like this:

function evk_malloc (size: longword): pointer;
const
   ALIGNMENT = 16;
begin
   result := GetMem(size + ALIGNMENT);
   result := Align (result, ALIGNMENT);
end;
procedure evk_free (ptr: pointer);
begin
   Freemem(ptr);
end;

I assumed that freemem will handle the aligned pointer correctly. This even worked for few weeks, until I added some more getmem/freemem in the code - started crashing on freemems. Even valgrind complained. I discovered that my assumption was false - I need to free the original pointer. So I mixed the two codes and come with something like this:

function evk_malloc (size: longword): pointer;
const
   ALIGNMENT = 16;
var
   ptr: pointer;
begin
   ptr := getmem(size + ALIGNMENT);
   result := Align (ptr, ALIGNMENT);
   if result = ptr then
       pbyte(result) += 16;
   //store offset to original address
   (pbyte(result) - 1)^ := result - ptr;
end;
procedure evk_free (ptr: pointer);
begin
   if ptr = nil then exit;
   //adjust to original address
   pbyte(ptr) -= pbyte(ptr-1)^ ;
   freemem(ptr);
end;

Is this correct to use? Wouldn't be there any catches for example when running on 64-bit machine?

Also, does FPC support aligning stack variables and record members on mod16 addresses like GCC
(http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Variable-Attributes.html#Variable-Attributes) ? I would like to have an array inside a rather huge record that starts at aligned address for SSE2 use, too.

Best regards,

David

Micha Nelissen
to David Pethes
David Pethes wrote 12 lines
pointer. So I mixed the two codes and come with something like this: function evk_malloc (size: longword): pointer; const ALIGNMENT = 16; var ptr: pointer; begin ptr := getmem(size + ALIGNMENT); result := Align (ptr, ALIGNMENT); if result = ptr then pbyte(result) += 16;

Why not use ALIGNMENT here also?

Show quoted text 6 lines
//store offset to original address (pbyte(result) - 1)^ := result - ptr; end; Is this correct to use? Wouldn't be there any catches for example when running on 64-bit machine?

This looks ok.

BTW, GetMem already returns 16 byte aligned blocks. If it does not, it's considered a bug.

Also, does FPC support aligning stack variables and record members on mod16 addresses like GCC (http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Variable-Attributes.html#Variable-Attributes)

Don't know.

Micha

David Pethes
to Micha Nelissen

Hi,

Micha Nelissen wrote 12 lines
> function evk_malloc (size: longword): pointer; > const > ALIGNMENT = 16; > var > ptr: pointer; > begin > ptr := getmem(size + ALIGNMENT); > result := Align (ptr, ALIGNMENT); > if result = ptr then > pbyte(result) += 16; Why not use ALIGNMENT here also?

Hah, I got stuck between using a constant and direct value... :) I should make it consistent. Thanks for reviewing and pointing this out.

BTW, GetMem already returns 16 byte aligned blocks. If it does not, it's considered a bug.

I didn't know that, looks like I should reread the documentation. I need the address on which the block begins to be divisible with 16, though.

David