Переглянути джерело

* enable specifying the alignment mismatch of the frame/stack pointer
relative to the normal stack alignment of the target (e.g., when using
ebp as framepointer, all addresses are offset 8 to the stack pointer) in
the temp generator. This enables allocating temps/locals with the correct
alignment as long as the required alignment is not bigger than the
guaranteed stack pointer alignment (fixes mantis #15582 on systems where
the stack pointer is at least aligned to 16 bytes; e.g., not yet on
i386-platforms other than darwin)

git-svn-id: trunk@22277 -

Jonas Maebe 13 роки тому
батько
коміт
a5cb157091
5 змінених файлів з 157 додано та 13 видалено
  1. 2 0
      .gitattributes
  2. 4 0
      compiler/i386/cpupi.pas
  3. 27 13
      compiler/tgobj.pas
  4. 52 0
      tests/webtbs/tw15582.pp
  5. 72 0
      tests/webtbs/uw15582.pp

+ 2 - 0
.gitattributes

@@ -12426,6 +12426,7 @@ tests/webtbs/tw15500.pp svneol=native#text/plain
 tests/webtbs/tw15504.pp svneol=native#text/plain
 tests/webtbs/tw15504.pp svneol=native#text/plain
 tests/webtbs/tw15530.pp svneol=native#text/pascal
 tests/webtbs/tw15530.pp svneol=native#text/pascal
 tests/webtbs/tw15571.pp svneol=native#text/pascal
 tests/webtbs/tw15571.pp svneol=native#text/pascal
+tests/webtbs/tw15582.pp svneol=native#text/plain
 tests/webtbs/tw15591.pp svneol=native#text/pascal
 tests/webtbs/tw15591.pp svneol=native#text/pascal
 tests/webtbs/tw15592.pp svneol=native#text/plain
 tests/webtbs/tw15592.pp svneol=native#text/plain
 tests/webtbs/tw15599.pp svneol=native#text/plain
 tests/webtbs/tw15599.pp svneol=native#text/plain
@@ -13587,6 +13588,7 @@ tests/webtbs/uw13345y.pp svneol=native#text/plain
 tests/webtbs/uw13583.pp svneol=native#text/plain
 tests/webtbs/uw13583.pp svneol=native#text/plain
 tests/webtbs/uw14124.pp svneol=native#text/plain
 tests/webtbs/uw14124.pp svneol=native#text/plain
 tests/webtbs/uw14958.pp svneol=native#text/plain
 tests/webtbs/uw14958.pp svneol=native#text/plain
+tests/webtbs/uw15582.pp svneol=native#text/plain
 tests/webtbs/uw15591.pp svneol=native#text/pascal
 tests/webtbs/uw15591.pp svneol=native#text/pascal
 tests/webtbs/uw15909.pp svneol=native#text/plain
 tests/webtbs/uw15909.pp svneol=native#text/plain
 tests/webtbs/uw15966.pp svneol=native#text/plain
 tests/webtbs/uw15966.pp svneol=native#text/plain

+ 4 - 0
compiler/i386/cpupi.pas

@@ -64,6 +64,10 @@ unit cpupi;
             if not(po_assembler in procdef.procoptions) and
             if not(po_assembler in procdef.procoptions) and
                (tg.direction > 0) then
                (tg.direction > 0) then
               tg.setfirsttemp(tg.direction*maxpushedparasize);
               tg.setfirsttemp(tg.direction*maxpushedparasize);
+            if (tg.direction < 0) and
+               not(po_nostackframe in procdef.procoptions) then
+              { compensate for the return address and the "pushl %ebp" }
+              tg.setalignmentmismatch(sizeof(pint)*2);
           end;
           end;
       end;
       end;
 
 

+ 27 - 13
compiler/tgobj.pas

@@ -67,7 +67,11 @@ unit tgobj;
           templist      : ptemprecord;
           templist      : ptemprecord;
           { Offsets of the first/last temp }
           { Offsets of the first/last temp }
           firsttemp,
           firsttemp,
-          lasttemp      : longint;
+          lasttemp,
+          { Offset of temp base register relative to guaranteed stack alignment
+            (note: currently only behaves as expected if it's a power of 2,
+               and if all requested alignments are also a power of 2) }
+          alignmismatch: longint;
           direction : shortint;
           direction : shortint;
           constructor create;virtual;reintroduce;
           constructor create;virtual;reintroduce;
           {# Clear and free the complete linked list of temporary memory
           {# Clear and free the complete linked list of temporary memory
@@ -80,6 +84,7 @@ unit tgobj;
              @param(l start offset where temps will start in stack)
              @param(l start offset where temps will start in stack)
           }
           }
           procedure setfirsttemp(l : longint); virtual;
           procedure setfirsttemp(l : longint); virtual;
+          procedure setalignmentmismatch(l : longint); virtual;
 
 
           { version of gettemp that is compatible with hlcg-based targets;
           { version of gettemp that is compatible with hlcg-based targets;
             always use in common code, only use gettemp in cgobj and
             always use in common code, only use gettemp in cgobj and
@@ -206,6 +211,7 @@ implementation
         tempfreelist:=nil;
         tempfreelist:=nil;
         firsttemp:=0;
         firsttemp:=0;
         lasttemp:=0;
         lasttemp:=0;
+        alignmismatch:=0;
       end;
       end;
 
 
 
 
@@ -224,12 +230,19 @@ implementation
       end;
       end;
 
 
 
 
+    procedure ttgobj.setalignmentmismatch(l: longint);
+      begin
+        alignmismatch:=l*direction;
+      end;
+
+
     function ttgobj.AllocTemp(list: TAsmList; size,alignment : longint; temptype : ttemptype;def : tdef) : longint;
     function ttgobj.AllocTemp(list: TAsmList; size,alignment : longint; temptype : ttemptype;def : tdef) : longint;
       var
       var
          tl,htl,
          tl,htl,
          bestslot,bestprev,
          bestslot,bestprev,
          hprev,hp : ptemprecord;
          hprev,hp : ptemprecord;
          freetype : ttemptype;
          freetype : ttemptype;
+         adjustedpos : longint;
          bestatend,
          bestatend,
          fitatbegin,
          fitatbegin,
          fitatend : boolean;
          fitatend : boolean;
@@ -270,11 +283,12 @@ implementation
                   - share the same type
                   - share the same type
                   - contain enough space
                   - contain enough space
                   - has a correct alignment }
                   - has a correct alignment }
+               adjustedpos:=hp^.pos+alignmismatch;
                if (hp^.temptype=freetype) and
                if (hp^.temptype=freetype) and
                   (hp^.def=def) and
                   (hp^.def=def) and
                   (hp^.size>=size) and
                   (hp^.size>=size) and
-                  ((hp^.pos=align(hp^.pos,alignment)) or
-                   (hp^.pos+hp^.size-size = align(hp^.pos+hp^.size-size,alignment))) then
+                  ((adjustedpos=align(adjustedpos,alignment)) or
+                   (adjustedpos+hp^.size-size = align(adjustedpos+hp^.size-size,alignment))) then
                 begin
                 begin
                   { Slot is the same size then leave immediatly }
                   { Slot is the same size then leave immediatly }
                   if (hp^.size=size) then
                   if (hp^.size=size) then
@@ -293,25 +307,25 @@ implementation
                      { still suffices. And we pick the block which will     }
                      { still suffices. And we pick the block which will     }
                      { have the best alignmenment after this new block is   }
                      { have the best alignmenment after this new block is   }
                      { substracted from it.                                 }
                      { substracted from it.                                 }
-                     fitatend:=(hp^.pos+hp^.size-size)=align(hp^.pos+hp^.size-size,alignment);
-                     fitatbegin:=hp^.pos=align(hp^.pos,alignment);
+                     fitatend:=(adjustedpos+hp^.size-size)=align(adjustedpos+hp^.size-size,alignment);
+                     fitatbegin:=adjustedpos=align(adjustedpos,alignment);
                      if assigned(bestslot) then
                      if assigned(bestslot) then
                        begin
                        begin
                          fitatend:=fitatend and
                          fitatend:=fitatend and
                            ((not bestatend and
                            ((not bestatend and
                              (direction=-1)) or
                              (direction=-1)) or
                             (bestatend and
                             (bestatend and
-                             isbetteralignedthan(abs(bestslot^.pos+hp^.size-size),abs(hp^.pos+hp^.size-size),current_settings.alignment.localalignmax)));
+                             isbetteralignedthan(abs(bestslot^.pos+hp^.size-size),abs(adjustedpos+hp^.size-size),current_settings.alignment.localalignmax)));
                          fitatbegin:=fitatbegin and
                          fitatbegin:=fitatbegin and
                            (not bestatend or
                            (not bestatend or
                             (direction=1)) and
                             (direction=1)) and
-                           isbetteralignedthan(abs(hp^.pos+size),abs(bestslot^.pos+size),current_settings.alignment.localalignmax);
+                           isbetteralignedthan(abs(adjustedpos+size),abs(bestslot^.pos+size),current_settings.alignment.localalignmax);
                        end;
                        end;
                      if fitatend and
                      if fitatend and
                         fitatbegin then
                         fitatbegin then
-                       if isbetteralignedthan(abs(hp^.pos+hp^.size-size),abs(hp^.pos+size),current_settings.alignment.localalignmax) then
+                       if isbetteralignedthan(abs(adjustedpos+hp^.size-size),abs(adjustedpos+size),current_settings.alignment.localalignmax) then
                          fitatbegin:=false
                          fitatbegin:=false
-                       else if isbetteralignedthan(abs(hp^.pos+size),abs(hp^.pos+hp^.size-size),current_settings.alignment.localalignmax) then
+                       else if isbetteralignedthan(abs(adjustedpos+size),abs(adjustedpos+hp^.size-size),current_settings.alignment.localalignmax) then
                          fitatend:=false
                          fitatend:=false
                        else if (direction=1) then
                        else if (direction=1) then
                          fitatend:=false
                          fitatend:=false
@@ -392,13 +406,13 @@ implementation
             { Extend the temp }
             { Extend the temp }
             if direction=-1 then
             if direction=-1 then
               begin
               begin
-                 lasttemp:=(-align(-lasttemp,alignment))-size;
-                 tl^.pos:=lasttemp;
+                lasttemp:=(-align(-lasttemp-alignmismatch,alignment))-size-alignmismatch;
+                tl^.pos:=lasttemp;
               end
               end
             else
             else
               begin
               begin
-                 tl^.pos:=align(lasttemp,alignment);
-                 lasttemp:=tl^.pos+size;
+                tl^.pos:=align(lasttemp+alignmismatch,alignment)-alignmismatch;
+                lasttemp:=tl^.pos+size;
               end;
               end;
 
 
             tl^.size:=size;
             tl^.size:=size;

+ 52 - 0
tests/webtbs/tw15582.pp

@@ -0,0 +1,52 @@
+{ %cpu=x86_64,i386,powerpc,powerpc64}
+{ %skiptarget=linux,freebsd,netbsd,openbsd,win32,os2,go32v2}
+
+{ should actually only skip i386-variants of win32/linux/.. for now, but that can't be specified }
+
+{ test can only work correctly (for now) on targets with 16-byte aligned stacks }
+
+program tw15582;
+
+{$MODE OBJFPC}{$H+}
+
+{$codealign varmin=16}
+{$codealign localmin=16}
+
+uses
+  uw15582;
+
+var g1,g2,g3 : byte;
+    g4 : integer;
+    g5 : byte;
+    g6 : array[0..39] of double;
+
+procedure l;
+var l1,l2,l3 : byte;
+    l4 : integer;
+    l5 : byte;
+    l6 : array[0..39] of double;
+
+begin
+  check('l1',@l1);
+  check('l2',@l2);
+  check('l3',@l3);
+  check('l4',@l4);
+  check('l5',@l5);
+  check('l6',@l6);
+end;
+
+
+begin
+  check('g1',@g1);
+  check('g2',@g2);
+  check('g3',@g3);
+  check('g4',@g4);
+  check('g5',@g5);
+  check('g6',@g6);
+  l;
+  l_unit('main ');
+  l_unit_nostackframe;
+  writeln(n_checks,' tests. ',n_failed,' failed');
+  if n_failed > 0 then 
+    halt(1); 
+end.

+ 72 - 0
tests/webtbs/uw15582.pp

@@ -0,0 +1,72 @@
+unit uw15582;
+
+{$MODE OBJFPC}{$H+}
+
+
+{$codealign varmin=16}
+{$codealign localmin=16}
+
+interface
+
+var 
+  n_checks : integer = 0;
+  n_failed : integer = 0;
+
+procedure check(const v : string;p : pointer);
+procedure l_unit(const pfx : string);
+procedure l_unit_nostackframe;
+
+implementation
+
+var g1,g2,g3 : byte;
+    g4 : integer;
+    g5 : byte;
+    g6 : array[0..39] of double;
+
+procedure check(const v : string;p : pointer);
+begin
+  inc(n_checks);
+  if (ptruint(p) and ptruint(-16)) <> ptruint(p) then begin
+    writeln('Wrong aligned: "',v,'" : ',hexstr(p));
+    inc(n_failed);
+  end;
+end;
+
+
+procedure l_unit(const pfx : string);
+var l1,l2,l3 : byte;
+    l4 : integer;
+    l5 : byte;
+    l6 : array[0..39] of double;
+
+
+begin
+  check(pfx+'l_unit1',@l1);
+  check(pfx+'l_unit2',@l2);
+  check(pfx+'l_unit3',@l3);
+  check(pfx+'l_unit4',@l4);
+  check(pfx+'l_unit5',@l5);
+  check(pfx+'l_unit6',@l6);
+end;
+
+procedure l_unit_nostackframe;
+var
+  b1, b2: byte;
+begin
+  inc(n_checks);
+  if (ptruint(@b1) and ptruint(15)) <> 0 then
+    inc(n_failed);
+  inc(n_checks);
+  if (ptruint(@b2) and ptruint(15)) <> 0 then
+    inc(n_failed);
+end;
+
+initialization
+  check('g_unit1',@g1);
+  check('g_unit2',@g2);
+  check('g_unit3',@g3);
+  check('g_unit4',@g4);
+  check('g_unit5',@g5);
+  check('g_unit6',@g6);
+  l_unit('ca_unit.initialization ');
+end.