Browse Source

* fixed conversion to llvm format of variant records with less deeply
nested variant parts following an earlier part

git-svn-id: branches/llvm@12052 -

Jonas Maebe 17 years ago
parent
commit
8af42a0319
1 changed files with 84 additions and 38 deletions
  1. 84 38
      compiler/symtable.pas

+ 84 - 38
compiler/symtable.pas

@@ -152,7 +152,7 @@ interface
          procedure generate;
          // helpers
          procedure appenddefoffset(vardef:tdef; fieldoffset: aint; derefclass: boolean);
-         procedure findvariantstarts(item: TObject; arg: pointer);
+         procedure findvariantstarts(variantstarts: tfplist);
          procedure addalignmentpadding(finalsize: aint);
          procedure buildmapping(variantstarts: tfplist);
          procedure buildtable(variantstarts: tfplist);
@@ -1209,7 +1209,7 @@ implementation
       begin
         equivst:=st;
         curroffset:=0;
-        symdeflist:=tfpobjectlist.create(false);
+        symdeflist:=tfpobjectlist.create(true);
         generate;
       end;
       
@@ -1301,41 +1301,82 @@ implementation
       end;
 
 
-    procedure tllvmshadowsymtable.findvariantstarts(item: TObject; arg: pointer);
+    procedure tllvmshadowsymtable.findvariantstarts(variantstarts: tfplist);
       var
-        variantstarts: tfplist absolute arg;
-        sym: tfieldvarsym absolute item;
+        sym: tfieldvarsym;
         lastoffset: aint;
         newalignment: aint;
+        i, j: longint;
       begin
-        if (tsym(item).typ<>fieldvarsym) then
-          exit;
-        { a "better" algorithm might be to use the largest }
-        { variant in case of (bit)packing, since then      }
-        { alignment doesn't matter                         }
-        if (vo_is_first_field in sym.varoptions) then
+        i:=0;
+        while (i<equivst.symlist.count) do
           begin
-            { we assume that all fields are processed in order. }
-            { the most deeply nested variant always comes last  }
-            { in Pascal                                         }
-            if (variantstarts.count<>0) then
-              lastoffset:=tfieldvarsym(variantstarts[variantstarts.count-1]).fieldoffset
-            else
-              lastoffset:=-1;
-
-            if (lastoffset=sym.fieldoffset) then
+            if (tsym(equivst.symlist[i]).typ<>fieldvarsym) then
               begin
-                if (equivst.fieldalignment<>bit_alignment) then
-                  newalignment:=used_align(sym.vardef.alignment,current_settings.alignment.recordalignmin,equivst.fieldalignment)
+                inc(i);
+                continue;
+              end;
+            sym:=tfieldvarsym(equivst.symlist[i]);
+            { a "better" algorithm might be to use the largest }
+            { variant in case of (bit)packing, since then      }
+            { alignment doesn't matter                         }
+            if (vo_is_first_field in sym.varoptions) then
+              begin
+                { we assume that all fields are processed in order. }
+                if (variantstarts.count<>0) then
+                  lastoffset:=tfieldvarsym(variantstarts[variantstarts.count-1]).fieldoffset
                 else
-                  newalignment:=1;
-                if (newalignment>tfieldvarsym(variantstarts[variantstarts.count-1]).vardef.alignment) then
-                  tfieldvarsym(variantstarts[variantstarts.count-1]):=sym
-              end
-            else if (lastoffset<sym.fieldoffset) then
-              variantstarts.add(sym)
-            else
-              internalerror(2008051003);
+                  lastoffset:=-1;
+
+                { new variant at same level as last one: use if higher alignment }
+                if (lastoffset=sym.fieldoffset) then
+                  begin
+                    if (equivst.fieldalignment<>bit_alignment) then
+                      newalignment:=used_align(sym.vardef.alignment,current_settings.alignment.recordalignmin,equivst.fieldalignment)
+                    else
+                      newalignment:=1;
+                    if (newalignment>tfieldvarsym(variantstarts[variantstarts.count-1]).vardef.alignment) then
+                      variantstarts[variantstarts.count-1]:=sym;
+                  end
+                { variant at deeper level than last one -> add }
+                else if (lastoffset<sym.fieldoffset) then
+                  variantstarts.add(sym)
+                else
+                  begin
+                    { a variant at a less deep level, so backtrack }
+                    j:=variantstarts.count-2;
+                    while (j>=0) do
+                      begin
+                        if (tfieldvarsym(variantstarts[j]).fieldoffset=sym.fieldoffset) then
+                          break;
+                        dec(j);
+                      end;
+                    if (j<0) then
+                      internalerror(2008051003);
+                    { new variant has higher alignment? }
+                    if (equivst.fieldalignment<>bit_alignment) then
+                      newalignment:=used_align(sym.vardef.alignment,current_settings.alignment.recordalignmin,equivst.fieldalignment)
+                    else
+                      newalignment:=1;
+                    { yes, replace and remove previous nested variants }
+                    if (newalignment>tfieldvarsym(variantstarts[j]).vardef.alignment) then
+                      begin
+                        variantstarts[j]:=sym;
+                        variantstarts.count:=j+1;
+                      end
+                   { no, skip this variant }
+                    else
+                      begin
+                        inc(i);
+                        while (i<equivst.symlist.count) and
+                              ((tsym(equivst.symlist[i]).typ<>fieldvarsym) or
+                               (tfieldvarsym(equivst.symlist[i]).fieldoffset>sym.fieldoffset)) do
+                          inc(i);
+                        continue;
+                      end;
+                  end;
+              end;
+            inc(i);
           end;
       end;
 
@@ -1365,10 +1406,10 @@ implementation
               begin
                 { if we want to process the same variant offset twice, it means that we  }
                 { got to the end and are trying to process the next variant part -> stop }
-                if (tfieldvarsym(equivst.symlist[i]).fieldoffset=lastvaroffsetprocessed) then
+                if (tfieldvarsym(equivst.symlist[i]).fieldoffset<=lastvaroffsetprocessed) then
                   break;
-                if (varcount>=variantstarts.count) or
-                   (tfieldvarsym(equivst.symlist[i]).fieldoffset<>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+
+                if (varcount>=variantstarts.count) then
                   internalerror(2008051005);
                 { new variant part -> use the one with the biggest alignment }
                 i:=equivst.symlist.indexof(tobject(variantstarts[varcount]));
@@ -1404,11 +1445,16 @@ implementation
             { start of a new variant? }
             if (vo_is_first_field in tfieldvarsym(equivst.symlist[i]).varoptions) then
               begin
-                { the variant can either come after the current one, or }
-                { be at the same level                                  }
-                if (tfieldvarsym(equivst.symlist[i]).fieldoffset<tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                { back up to a less deeply nested variant level? }
+                while (tfieldvarsym(equivst.symlist[i]).fieldoffset<tfieldvarsym(variantstarts[varcount]).fieldoffset) do
                   dec(varcount);
-                if (tfieldvarsym(equivst.symlist[i]).fieldoffset<>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                { it's possible that some variants are more deeply nested than the
+                  one we recorded in the shadowsymtable (since we recorded the one
+                  with the biggest alignment, not necessarily the biggest one in size
+                }
+                if (tfieldvarsym(equivst.symlist[i]).fieldoffset>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
+                  varcount:=variantstarts.count-1
+                else if (tfieldvarsym(equivst.symlist[i]).fieldoffset<>tfieldvarsym(variantstarts[varcount]).fieldoffset) then
                   internalerror(2008051006);
                 { reset the shadowindex to the start of this variant. }
                 { in case the llvmfieldnr is not (yet) set for this   }
@@ -1443,7 +1489,7 @@ implementation
         { first go through the entire record and }
         { store the fieldvarsyms of the variants }
         { with the highest alignment             }
-        equivst.symlist.foreachcall(@findvariantstarts,pointer(variantstarts));
+        findvariantstarts(variantstarts);
 
         { now go through the regular fields and the selected variants, }
         { and add them to the  llvm shadow record symtable             }