Browse Source

* if an agregate contains unaligned fields, it has to be passed via memory
(mantis #22878)

git-svn-id: trunk@22390 -

Jonas Maebe 13 years ago
parent
commit
dcdcc6988d
3 changed files with 59 additions and 4 deletions
  1. 1 0
      .gitattributes
  2. 27 4
      compiler/x86_64/cpupara.pas
  3. 31 0
      tests/webtbs/tw22878.pp

+ 1 - 0
.gitattributes

@@ -12827,6 +12827,7 @@ tests/webtbs/tw2280.pp svneol=native#text/plain
 tests/webtbs/tw22860.pp svneol=native#text/plain
 tests/webtbs/tw22860.pp svneol=native#text/plain
 tests/webtbs/tw22864.pp svneol=native#text/pascal
 tests/webtbs/tw22864.pp svneol=native#text/pascal
 tests/webtbs/tw22869.pp svneol=native#text/plain
 tests/webtbs/tw22869.pp svneol=native#text/plain
+tests/webtbs/tw22878.pp svneol=native#text/plain
 tests/webtbs/tw2289.pp svneol=native#text/plain
 tests/webtbs/tw2289.pp svneol=native#text/plain
 tests/webtbs/tw2291.pp svneol=native#text/plain
 tests/webtbs/tw2291.pp svneol=native#text/plain
 tests/webtbs/tw2294.pp svneol=native#text/plain
 tests/webtbs/tw2294.pp svneol=native#text/plain

+ 27 - 4
compiler/x86_64/cpupara.pas

@@ -342,6 +342,7 @@ unit cpupara;
         i,
         i,
         words,
         words,
         num: longint;
         num: longint;
+        checkalignment: boolean;
       begin
       begin
         result:=init_aggregate_classification(def,varspez,words,classes);
         result:=init_aggregate_classification(def,varspez,words,classes);
         if (words=0) then
         if (words=0) then
@@ -354,6 +355,7 @@ unit cpupara;
               continue;
               continue;
             vs:=tfieldvarsym(tabstractrecorddef(def).symtable.symlist[i]);
             vs:=tfieldvarsym(tabstractrecorddef(def).symtable.symlist[i]);
             num:=-1;
             num:=-1;
+            checkalignment:=true;
             if not tabstractrecordsymtable(tabstractrecorddef(def).symtable).is_packed then
             if not tabstractrecordsymtable(tabstractrecorddef(def).symtable).is_packed then
               begin
               begin
                 new_byte_offset:=byte_offset+vs.fieldoffset;
                 new_byte_offset:=byte_offset+vs.fieldoffset;
@@ -363,11 +365,25 @@ unit cpupara;
               begin
               begin
                 new_byte_offset:=byte_offset+vs.fieldoffset div 8;
                 new_byte_offset:=byte_offset+vs.fieldoffset div 8;
                 if (vs.vardef.typ in [orddef,enumdef]) then
                 if (vs.vardef.typ in [orddef,enumdef]) then
-                  { calculate the number of bytes spanned by
-                    this bitpacked field }
-                  size:=((vs.fieldoffset+vs.vardef.packedbitsize+7) div 8)-(vs.fieldoffset div 8)
+                  begin
+                    { calculate the number of bytes spanned by
+                      this bitpacked field }
+                    size:=((vs.fieldoffset+vs.vardef.packedbitsize+7) div 8)-(vs.fieldoffset div 8);
+                    { our bitpacked fields are interpreted as always being
+                      aligned, because unlike in C we don't have char:1, int:1
+                      etc (so everything is basically a char:x) }
+                    checkalignment:=false;
+                  end
                 else
                 else
-                  size:=vs.vardef.size
+                  size:=vs.vardef.size;
+              end;
+            { If [..] an object [..] contains unaligned fields, it has class
+              MEMORY }
+            if checkalignment and
+               (align(new_byte_offset,vs.vardef.structalignment)<>new_byte_offset) then
+              begin
+                result:=0;
+                exit;
               end;
               end;
             num:=classify_aggregate_element(vs.vardef,varspez,size,classes,new_byte_offset);
             num:=classify_aggregate_element(vs.vardef,varspez,size,classes,new_byte_offset);
             if (num=0) then
             if (num=0) then
@@ -413,6 +429,13 @@ unit cpupara;
             begin
             begin
               { size does not change }
               { size does not change }
               new_byte_offset:=byte_offset+i*elesize;
               new_byte_offset:=byte_offset+i*elesize;
+              { If [..] an object [..] contains unaligned fields, it has class
+                MEMORY }
+              if align(new_byte_offset,def.alignment)<>new_byte_offset then
+                begin
+                  result:=0;
+                  exit;
+                end;
             end
             end
           else
           else
             begin
             begin

+ 31 - 0
tests/webtbs/tw22878.pp

@@ -0,0 +1,31 @@
+program gr;
+{$mode objfpc}
+    type
+        t0= record
+            p: pointer;
+        end;
+        t1= packed record
+            u16: word;
+            data: t0;
+        end;
+
+        td= class
+            function return: t1;
+        end;
+            function td.return: t1;
+            begin
+              return.u16:=1;
+              return.data.p:=pointer(2);
+            end;
+var
+  c: td;
+  r: t1;
+begin
+  c:=td.create;
+  r:=c.return;
+  if r.u16<>1 then
+    halt(1);
+  if r.data.p<>pointer(2) then
+    halt(2);
+end.
+