Prechádzať zdrojové kódy

+ a_loadfpu_* and a_loadmm_* methods in tcg
* register allocation is now handled by a class and is mostly processor
independent (+rgobj.pas and i386/rgcpu.pas)
* temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
* some small improvements and fixes to the optimizer
* some register allocation fixes
* some fpuvaroffset fixes in the unary minus node
* push/popusedregisters is now called rg.save/restoreusedregisters and
(for i386) uses temps instead of push/pop's when using -Op3 (that code is
also better optimizable)
* fixed and optimized register saving/restoring for new/dispose nodes
* LOC_FPU locations now also require their "register" field to be set to
R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
- list field removed of the tnode class because it's not used currently
and can cause hard-to-find bugs

Jonas Maebe 23 rokov pred
rodič
commit
7fb55bf4e4
49 zmenil súbory, kde vykonal 4248 pridanie a 2422 odobranie
  1. 64 7
      compiler/cgbase.pas
  2. 68 8
      compiler/cgobj.pas
  3. 144 234
      compiler/i386/cga.pas
  4. 179 8
      compiler/i386/cgcpu.pas
  5. 54 3
      compiler/i386/cpubase.pas
  6. 17 3
      compiler/i386/cpunode.pas
  7. 97 55
      compiler/i386/csopt386.pas
  8. 49 32
      compiler/i386/daopt386.pas
  9. 160 157
      compiler/i386/n386add.pas
  10. 126 133
      compiler/i386/n386cal.pas
  11. 48 26
      compiler/i386/n386cnv.pas
  12. 21 6
      compiler/i386/n386con.pas
  13. 41 24
      compiler/i386/n386flw.pas
  14. 62 42
      compiler/i386/n386inl.pas
  15. 79 99
      compiler/i386/n386ld.pas
  16. 120 104
      compiler/i386/n386mat.pas
  17. 79 41
      compiler/i386/n386mem.pas
  18. 19 3
      compiler/i386/n386obj.pas
  19. 44 27
      compiler/i386/n386opt.pas
  20. 57 40
      compiler/i386/n386set.pas
  21. 121 126
      compiler/i386/n386util.pas
  22. 21 4
      compiler/i386/popt386.pas
  23. 354 0
      compiler/i386/rgcpu.pas
  24. 21 4
      compiler/i386/rropt386.pas
  25. 0 746
      compiler/i386/tgcpu.pas
  26. 21 12
      compiler/nbas.pas
  27. 22 15
      compiler/ncal.pas
  28. 23 6
      compiler/ncgbas.pas
  29. 49 30
      compiler/ncgcnv.pas
  30. 19 3
      compiler/ncgcon.pas
  31. 73 35
      compiler/ncgflw.pas
  32. 49 32
      compiler/ncgmem.pas
  33. 31 14
      compiler/ncgutil.pas
  34. 47 94
      compiler/nflw.pas
  35. 19 2
      compiler/ninl.pas
  36. 21 4
      compiler/nld.pas
  37. 26 3
      compiler/node.pas
  38. 27 22
      compiler/nset.pas
  39. 19 2
      compiler/pass_1.pas
  40. 23 6
      compiler/pass_2.pas
  41. 20 3
      compiler/pexpr.pas
  42. 19 2
      compiler/ppu.pas
  43. 42 45
      compiler/pstatmnt.pas
  44. 32 64
      compiler/psub.pas
  45. 44 31
      compiler/regvars.pas
  46. 799 0
      compiler/rgobj.pas
  47. 21 62
      compiler/symdef.pas
  48. 696 0
      compiler/tgobj.pas
  49. 61 3
      compiler/utils/ppudump.pp

+ 64 - 7
compiler/cgbase.pas

@@ -44,9 +44,21 @@ unit cgbase;
        TOpCmp = (OC_NONE,OC_EQ,OC_GT,OC_LT,OC_GTE,OC_LTE,OC_NE,OC_BE,OC_B,
                  OC_AE,OC_A);
 
-       TCgSize = (OS_NO,OS_8,OS_16,OS_32,OS_64,OS_S8,OS_S16,OS_S32,OS_S64);
+       TCgSize = (OS_NO,OS_8,OS_16,OS_32,OS_64,OS_S8,OS_S16,OS_S32,OS_S64,
+                { single,double,extended,comp }
+                  OS_F32,OS_F64,OS_F80,OS_C64,
+                { multi-media sizes: split in byte, word, dword, ... }
+                { entities, then the signed counterparts             }
+                  OS_M8,OS_M16,OS_M32,OS_M64,OS_M128,OS_MS8,OS_MS16,OS_MS32,
+                  OS_MS64,OS_MS128);
 
     const
+      tfloat2tcgsize: array[tfloattype] of tcgsize =
+        (OS_F32,OS_F64,OS_F80,OS_C64);
+
+      tcgsize2tfloat: array[OS_F32..OS_C64] of tfloattype =
+        (s32real,s64real,s80real,s64comp);
+
        pi_uses_asm  = $1;       { set, if the procedure uses asm }
        pi_is_global = $2;       { set, if the procedure is exported by an unit }
        pi_do_call   = $4;       { set, if the procedure does a call }
@@ -59,23 +71,39 @@ unit cgbase;
        pi_needs_implicit_finally = $80; { set, if the procedure contains data which }
                                         { needs to be finalized              }
 
-       { defines the default address size for a processor }
-       { and defines the natural int size for a processor }
+       { defines the default address size for a processor, }
+       { the natural int size for a processor,             }
+       { the maximum float size for a processor,           }
+       { the size of a vector register for a processor     }
 {$ifdef i386}
        OS_ADDR = OS_32;
        OS_INT = OS_32;
+       OS_FLOAT = OS_F80;
+       OS_VECTOR = OS_M64;
 {$endif i386}
+{$ifdef m68k}
+       OS_ADDR = OS_32;
+       OS_INT = OS_32;
+       OS_FLOAT = OS_F??; { processor supports 64bit, but does the compiler? }
+       OS_VECTOR = OS_NO;
+{$endif m68k}
 {$ifdef alpha}
        OS_ADDR = OS_64;
        OS_INT = OS_64;
+       OS_FLOAT = OS_F??;
+       OS_VECTOR = OS_NO;
 {$endif alpha}
 {$ifdef powerpc}
        OS_ADDR = OS_32;
        OS_INT = OS_32;
+       OS_FLOAT = OS_F64;
+       OS_VECTOR = OS_M128;
 {$endif powercc}
 {$ifdef ia64}
        OS_ADDR = OS_64;
        OS_INT = OS_64;
+       OS_FLOAT = OS_F??;
+       OS_VECTOR = OS_NO; { the normal registers can also be used as vectors }
 {$endif ia64}
 
     type
@@ -445,10 +473,22 @@ implementation
 
 
     function def_cgsize(const p1: tdef): tcgsize;
+
       begin
-        result := int_cgsize(p1.size);
-        if is_signed(p1) then
-          result := tcgsize(ord(result)+(ord(OS_S8)-ord(OS_8)));
+        case p1.deftype of
+          orddef, enumdef, setdef:
+            begin
+              result := int_cgsize(p1.size);
+              if is_signed(p1) then
+                result := tcgsize(ord(result)+(ord(OS_S8)-ord(OS_8)));
+            end;
+          pointerdef, procvardef:
+            result := OS_ADDR;
+          floatdef:
+            result := tfloat2tcgsize[tfloatdef(p1).typ];
+          else
+            internalerror(200201131);
+        end;
       end;
 
     function int_cgsize(const l: aword): tcgsize;
@@ -507,7 +547,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.6  2002-03-04 19:10:11  peter
+  Revision 1.7  2002-03-31 20:26:33  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.6  2002/03/04 19:10:11  peter
     * removed compiler warnings
 
   Revision 1.5  2001/12/30 17:24:48  jonas

+ 68 - 8
compiler/cgobj.pas

@@ -131,6 +131,17 @@ unit cgobj;
           procedure a_load_loc_ref(list : taasmoutput;size : tcgsize;const loc: tlocation; const ref : treference);
           procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister);virtual; abstract;
 
+          { fpu move instructions }
+          procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); virtual; abstract;
+          procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); virtual; abstract;
+          procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); virtual; abstract;
+          procedure a_loadfpu_loc_reg(list: taasmoutput; size: tcgsize; const loc: tlocation; const reg: tregister);
+          procedure a_loadfpu_reg_loc(list: taasmoutput; size: tcgsize; const reg: tregister; const loc: tlocation);
+
+          { vector register move instructions }
+          procedure a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister); virtual; abstract;
+          procedure a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister); virtual; abstract;
+          procedure a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference); virtual; abstract;
 
           { basic arithmetic operations }
           { note: for operators which require only one argument (not, neg), use }
@@ -225,7 +236,7 @@ unit cgobj;
 
     uses
        strings,globals,globtype,options,gdb,systems,
-       ppu,verbose,types,{tgobj,}tgcpu,symdef,symsym,cga,tainst;
+       ppu,verbose,types,tgobj,symdef,symsym,cga,tainst,rgobj;
 
     const
       max_scratch_regs = high(scratch_regs) - low(scratch_regs) + 1;
@@ -400,7 +411,7 @@ unit cgobj;
     procedure tcg.g_decrstrref(list : taasmoutput;const ref : treference;t : tdef);
 
 {      var
-         pushedregs : tpushed; }
+         pushedregs : tpushedsaved; }
 
       begin
 (*
@@ -1087,7 +1098,7 @@ unit cgobj;
 {$ifdef i386}
               case size of
                 OS_8,OS_S8:
-                  tmpreg := reg32toreg8(getregisterint);
+                  tmpreg := reg32toreg8(rg.getregisterint(exprasmlist));
                 OS_16,OS_S16:
                   tmpreg := reg32toreg16(get_scratch_reg(list));
                 else
@@ -1100,7 +1111,7 @@ unit cgobj;
               a_load_reg_ref(list,size,tmpreg,ref);
 {$ifdef i386}
               if not (size in [OS_32,OS_S32]) then
-                ungetregister(tmpreg)
+                rg.ungetregister(exprasmlist,tmpreg)
               else
 {$endif i386}
               free_scratch_reg(list,tmpreg);
@@ -1113,6 +1124,34 @@ unit cgobj;
       end;
 
 
+    procedure tcg.a_loadfpu_loc_reg(list: taasmoutput; size: tcgsize; const loc: tlocation; const reg: tregister);
+
+      begin
+        case loc.loc of
+          LOC_REFERENCE, LOC_MEM:
+            a_loadfpu_ref_reg(list,size,loc.reference,reg);
+          LOC_FPU, LOC_CFPUREGISTER:
+            a_loadfpu_reg_reg(list,loc.register,reg);
+          else
+            internalerror(200203301);
+        end;
+      end;
+
+
+    procedure tcg.a_loadfpu_reg_loc(list: taasmoutput; size: tcgsize; const reg: tregister; const loc: tlocation);
+
+      begin
+        case loc.loc of
+          LOC_REFERENCE, LOC_MEM:
+            a_loadfpu_reg_ref(list,size,reg,loc.reference);
+          LOC_FPU, LOC_CFPUREGISTER:
+            a_loadfpu_reg_reg(list,reg,loc.register);
+          else
+            internalerror(48991);
+         end;
+      end;
+
+
     procedure tcg.a_op_const_ref(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; const ref: TReference);
 
       var
@@ -1289,7 +1328,7 @@ unit cgobj;
               { since all this is only necessary for the 80x86 (because EDI   }
               { doesn't have an 8bit component which is directly addressable) }
               if size in [OS_8,OS_S8] then
-                tmpreg := getregisterint
+                tmpreg := rg.getregisterint(exprasmlist)
               else
 {$endif i386}
               tmpreg := get_scratch_reg(list);
@@ -1300,7 +1339,7 @@ unit cgobj;
               a_cmp_ref_reg_label(list,size,cmp_op,ref,tmpreg,l);
 {$ifdef i386}
               if makereg32(tmpreg) <> R_EDI then
-                ungetregister(tmpreg)
+                rg.ungetregister(exprasmlist,tmpreg)
               else
 {$endif i386}
               free_scratch_reg(list,tmpreg);
@@ -1434,11 +1473,32 @@ finalization
 end.
 {
   $Log$
-  Revision 1.7  2002-03-04 19:10:11  peter
+  Revision 1.8  2002-03-31 20:26:33  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.7  2002/03/04 19:10:11  peter
     * removed compiler warnings
 
   Revision 1.6  2001/12/30 17:24:48  jonas
-    * range checking is now processor independent (part in cgobj, part in    cg64f32) and should work correctly again (it needed some changes after    the changes of the low and high of tordef's to int64)  * maketojumpbool() is now processor independent (in ncgutil)  * getregister32 is now called getregisterint
+    * range checking is now processor independent (part in cgobj, part in
+      cg64f32) and should work correctly again (it needed some changes after
+      the changes of the low and high of tordef's to int64)
+    * maketojumpbool() is now processor independent (in ncgutil)
+    * getregister32 is now called getregisterint
 
   Revision 1.5  2001/12/29 15:28:58  jonas
     * powerpc/cgcpu.pas compiles :)

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 144 - 234
compiler/i386/cga.pas


+ 179 - 8
compiler/i386/cgcpu.pas

@@ -27,7 +27,7 @@ unit cgcpu;
   interface
 
     uses
-       cgbase,cgobj,cg64f32,aasm,cpuasm,cpubase,cpuinfo;
+       cgbase,cgobj,cg64f32,aasm,cpuasm,cpubase,cpuinfo,symconst;
 
     type
       tcg386 = class(tcg64f32)
@@ -66,6 +66,16 @@ unit cgcpu;
         procedure a_load_reg_reg(list : taasmoutput;size : tcgsize;reg1,reg2 : tregister);override;
         procedure a_load_sym_ofs_reg(list: taasmoutput; const sym: tasmsymbol; ofs: longint; reg: tregister); override;
 
+        { fpu move instructions }
+        procedure a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
+        procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
+        procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
+
+        { vector register move instructions }
+        procedure a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister); override;
+        procedure a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister); override;
+        procedure a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference); override;
+
         {  comparison operations }
         procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
           l : tasmlabel);override;
@@ -99,6 +109,10 @@ unit cgcpu;
 
         procedure sizes2load(s1: tcgsize; s2: topsize; var op: tasmop; var s3: topsize);
 
+        procedure floatload(list: taasmoutput; t : tcgsize;const ref : treference);
+        procedure floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
+        procedure floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
+        procedure floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
 
       end;
 
@@ -111,14 +125,16 @@ unit cgcpu;
       TOpCmp2AsmCond: Array[topcmp] of TAsmCond = (C_NONE,C_E,C_G,
                            C_L,C_GE,C_LE,C_NE,C_BE,C_B,C_AE,C_A);
 
-      TCGSize2OpSize: Array[tcgsize] of topsize = (S_NO,S_B,S_W,S_L,S_L,
-                                                        S_B,S_W,S_L,S_L);
+      TCGSize2OpSize: Array[tcgsize] of topsize =
+        (S_NO,S_B,S_W,S_L,S_L,S_B,S_W,S_L,S_L,
+         S_FS,S_FL,S_FX,S_IQ,
+         S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO,S_NO);
 
 
   implementation
 
     uses
-       globtype,globals,verbose,systems,cutils,cga,tgcpu;
+       globtype,globals,verbose,systems,cutils,cga,rgobj,rgcpu;
 
 
     { we implement the following routines because otherwise we can't }
@@ -265,6 +281,66 @@ unit cgcpu;
         list.concat(taicpu.op_sym_ofs_reg(A_MOV,S_L,sym,ofs,reg));
       end;
 
+
+    { all fpu load routines expect that R_ST[0-7] means an fpu regvar and }
+    { R_ST means "the current value at the top of the fpu stack" (JM)     }
+    procedure tcg386.a_loadfpu_reg_reg(list: taasmoutput; reg1, reg2: tregister);
+
+       begin
+         if (reg1 <> R_ST) then
+           begin
+             list.concat(taicpu.op_reg(A_FLD,S_NO,
+               trgcpu(rg).correct_fpuregister(reg1,trgcpu(rg).fpuvaroffset)));
+             inc(trgcpu(rg).fpuvaroffset);
+           end;
+         if (reg2 <> R_ST) then
+           begin
+             list.concat(taicpu.op_reg(A_FSTP,S_NO,
+                 trgcpu(rg).correct_fpuregister(reg2,trgcpu(rg).fpuvaroffset)));
+             dec(trgcpu(rg).fpuvaroffset);
+           end;
+       end;
+
+
+    procedure tcg386.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
+
+       begin
+         floatload(list,size,ref);
+         if (reg <> R_ST) then
+           a_loadfpu_reg_reg(list,R_ST,reg);
+       end;
+
+
+    procedure tcg386.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
+
+       begin
+         if reg <> R_ST then
+           a_loadfpu_reg_reg(list,reg,R_ST);
+         floatstore(list,size,ref);
+       end;
+
+
+    procedure tcg386.a_loadmm_reg_reg(list: taasmoutput; reg1, reg2: tregister);
+
+       begin
+         list.concat(taicpu.op_reg_reg(A_MOVQ,S_NO,reg1,reg2));
+       end;
+
+
+    procedure tcg386.a_loadmm_ref_reg(list: taasmoutput; const ref: treference; reg: tregister);
+
+       begin
+         list.concat(taicpu.op_ref_reg(A_MOVQ,S_NO,newreference(ref),reg));
+       end;
+
+
+    procedure tcg386.a_loadmm_reg_ref(list: taasmoutput; reg: tregister; const ref: treference);
+
+       begin
+         list.concat(taicpu.op_reg_ref(A_MOVQ,S_NO,reg,newreference(ref)));
+       end;
+
+
     procedure tcg386.a_op_const_reg(list : taasmoutput; Op: TOpCG; a: AWord; reg: TRegister);
 
       var
@@ -450,10 +526,10 @@ unit cgcpu;
                     { is ecx still free (it's also free if it was allocated }
                     { to dst, since we've moved dst somewhere else already) }
                     if not((dst = R_ECX) or
-                           ((R_ECX in unused) and
+                           ((R_ECX in rg.unusedregsint) and
                             { this will always be true, it's just here to }
                             { allocate ecx                                }
-                            (getexplicitregister32(R_ECX) = R_ECX))) then
+                            (rg.getexplicitregisterint(list,R_ECX) = R_ECX))) then
                       begin
                         list.concat(taicpu.op_reg(A_PUSH,S_L,R_ECX));
                         popecx := true;
@@ -477,7 +553,7 @@ unit cgcpu;
                 if popecx then
                   list.concat(taicpu.op_reg(A_POP,S_L,R_ECX))
                 else if not (dst in [R_ECX,R_CX,R_CL]) then
-                  ungetregister32(R_ECX);
+                  rg.ungetregisterint(list,R_ECX);
               end;
             else
               begin
@@ -872,12 +948,107 @@ unit cgcpu;
        end;
 
 
+    procedure tcg386.floatloadops(t : tcgsize;var op : tasmop;var s : topsize);
+
+      begin
+         case t of
+            OS_F32 : begin
+                        op:=A_FLD;
+                        s:=S_FS;
+                     end;
+            OS_F64 : begin
+                        op:=A_FLD;
+                        { ???? }
+                        s:=S_FL;
+                     end;
+            OS_F80 : begin
+                        op:=A_FLD;
+                        s:=S_FX;
+                     end;
+            OS_C64 : begin
+                        op:=A_FILD;
+                        s:=S_IQ;
+                     end;
+            else internalerror(17);
+         end;
+      end;
+
+
+    procedure tcg386.floatload(list: taasmoutput; t : tcgsize;const ref : treference);
+
+      var
+         op : tasmop;
+         s : topsize;
+
+      begin
+         floatloadops(t,op,s);
+         list.concat(Taicpu.Op_ref(op,s,newreference(ref)));
+         inc(trgcpu(rg).fpuvaroffset);
+      end;
+
+
+    procedure tcg386.floatstoreops(t : tcgsize;var op : tasmop;var s : topsize);
+
+      begin
+         case t of
+            OS_F32 : begin
+                        op:=A_FSTP;
+                        s:=S_FS;
+                     end;
+            OS_F64 : begin
+                        op:=A_FSTP;
+                        s:=S_FL;
+                     end;
+            OS_F80 : begin
+                        op:=A_FSTP;
+                        s:=S_FX;
+                     end;
+            OS_C64 : begin
+                        op:=A_FISTP;
+                        s:=S_IQ;
+                     end;
+         else
+           internalerror(17);
+         end;
+      end;
+
+
+    procedure tcg386.floatstore(list: taasmoutput; t : tcgsize;const ref : treference);
+
+      var
+         op : tasmop;
+         s : topsize;
+
+      begin
+         floatstoreops(t,op,s);
+         list.concat(Taicpu.Op_ref(op,s,newreference(ref)));
+         dec(trgcpu(rg).fpuvaroffset);
+      end;
+
+
 begin
   cg := tcg386.create;
 end.
 {
   $Log$
-  Revision 1.7  2002-03-04 19:10:12  peter
+  Revision 1.8  2002-03-31 20:26:37  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.7  2002/03/04 19:10:12  peter
     * removed compiler warnings
 
   Revision 1.6  2001/12/30 17:24:46  jonas

+ 54 - 3
compiler/i386/cpubase.pas

@@ -528,9 +528,38 @@ type
 const
   general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
 
-  intregs = general_registers;
-  fpuregs = [];
+  { legend:                                                                }
+  { xxxregs = set of all possibly used registers of that type in the code  }
+  {           generator                                                    }
+  { usableregsxxx = set of all 32bit components of registers that can be   }
+  {           possible allocated to a regvar or using getregisterxxx (this }
+  {           excludes registers which can be only used for parameter      }
+  {           passing on ABI's that define this)                           }
+  { c_countusableregsxxx = amount of registers in the usableregsxxx set    }
+
+  intregs = [R_EAX..R_BL];
+  usableregsint = general_registers;
+  c_countusableregsint = 4;
+
+  fpuregs = [R_ST0..R_ST7];
+  usableregsfpu = [];
+  c_countusableregsfpu = 0;
+
   mmregs = [R_MM0..R_MM7];
+  usableregsmm = [R_MM0..R_MM7];
+  c_countusableregsmm  = 8;
+
+  firstsaveintreg = R_EAX;
+  lastsaveintreg = R_EBX;
+  firstsavefpureg = R_NO;
+  lastsavefpureg = R_NO;
+  firstsavemmreg = R_MM0;
+  lastsavemmreg = R_MM7;
+
+  lowsavereg = R_EAX;
+  highsavereg = R_MM7;
+
+  ALL_REGISTERS = [lowsavereg..highsavereg];
 
   lvaluelocations = [LOC_REFERENCE,LOC_CFPUREGISTER,
     LOC_CREGISTER,LOC_MMXREGISTER,LOC_CMMXREGISTER];
@@ -543,6 +572,10 @@ const
   self_pointer  = R_ESI;
   accumulator   = R_EAX;
   accumulatorhigh = R_EDX;
+  { WARNING: don't change to R_ST0!! See comments above implementation of }
+  { a_loadfpu* methods in rgcpu (JM)                                      }
+  fpuresultreg = R_ST;
+  mmresultreg = R_MM0;
   { the register where the vmt offset is passed to the destructor }
   { helper routine                                                }
   vmt_offset_reg = R_EDI;
@@ -564,6 +597,7 @@ const
   { sizes }
   pointersize   = 4;
   extended_size = 10;
+  mmreg_size = 8;
   sizepostfix_pointer = S_L;
 
 
@@ -957,7 +991,24 @@ end;
 end.
 {
   $Log$
-  Revision 1.10  2002-03-04 19:10:12  peter
+  Revision 1.11  2002-03-31 20:26:37  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.10  2002/03/04 19:10:12  peter
     * removed compiler warnings
 
   Revision 1.9  2001/12/30 17:24:46  jonas

+ 17 - 3
compiler/i386/cpunode.pas

@@ -33,13 +33,27 @@ unit cpunode;
        n386ld,n386add,n386cal,n386con,n386flw,n386mat,n386mem,
        n386set,n386inl,n386opt,
        { this not really a node }
-       n386obj;
+       n386obj, rgcpu;
 
 end.
 {
   $Log$
-  Revision 1.7  2001-09-30 16:17:18  jonas
-    * made most constant and mem handling processor independent
+  Revision 1.8  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
 
   Revision 1.6  2001/09/29 21:32:47  jonas
     * almost all second pass typeconvnode helpers are now processor independent

+ 97 - 55
compiler/i386/csopt386.pas

@@ -41,7 +41,7 @@ Implementation
 
 Uses
   {$ifdef replaceregdebug}cutils,{$endif}
-  globtype, verbose, cgbase, globals, daopt386, tgcpu, rropt386;
+  globtype, verbose, cgbase, globals, daopt386, rgobj, rropt386;
 
 {
 Function TaiInSequence(P: Tai; Const Seq: TContent): Boolean;
@@ -102,7 +102,7 @@ begin
       begin
         if (p.ops = 1) then
           begin
-            if is_reg_var[R_EDX] and
+            if rg.is_reg_var[R_EDX] and
                (not getNextInstruction(p,hp) or
                 not((hp.typ = ait_instruction) and
                     (hp.opcode = A_MOV) and
@@ -122,7 +122,7 @@ begin
         else
           { only possible for imul }
           { last operand is always destination }
-          if is_reg_var[reg32(p.oper[p.ops-1].reg)] then
+          if rg.is_reg_var[reg32(p.oper[p.ops-1].reg)] then
             for regCounter := R_EAX to R_EDI do
               begin
                 if writeDestroysContents(p.oper[p.ops-1],regCounter,c[regCounter]) then
@@ -186,7 +186,7 @@ function isSimpleMemLoc(const ref: treference): boolean;
 begin
   isSimpleMemLoc :=
     (ref.index = R_NO) and
-    not(ref.base in (usableregs+[R_EDI]));
+    not(ref.base in (rg.usableregsint+[R_EDI]));
 end;
 
 {checks whether the current instruction sequence (starting with p) and the
@@ -267,7 +267,7 @@ var
        (Taicpu(currentPrev).is_jmp));
     passedFlagsModifyingInstr := instrWritesFlags(currentPrev);
 
-    if (passedJump and not(reg in (usableregs+[R_EDI]))) or
+    if (passedJump and not(reg in (rg.usableregsint+[R_EDI]))) or
        not getLastInstruction(currentPrev,hp) then
       exit;
 
@@ -294,7 +294,7 @@ var
         if { do not load the self pointer or a regvar before a (conditional)  }
            { jump with a new value, since if the jump is taken, the old value }
            { is (probably) still necessary                                    }
-           (passedJump and not(reg in (usableregs+[R_EDI]))) or
+           (passedJump and not(reg in (rg.usableregsint+[R_EDI]))) or
            not getLastInstruction(hp,hp) then
           break;
       end;
@@ -678,49 +678,6 @@ begin
   Tai_align(p).reg := lastRemoved;
 End;
 
-Procedure RestoreRegContentsTo(reg: TRegister; const c: TContent; p, endP: Tai);
-var
-{$ifdef replaceregdebug}
-    hp: Tai;
-    l: longint;
-{$endif replaceregdebug}
-    tmpState: byte;
-begin
-{$ifdef replaceregdebug}
-  l := random(1000);
-  hp := Tai_asm_comment.Create(strpnew(
-          'restored '+att_reg2str[reg]+' with data from here... '+tostr(l))));
-  hp.next := p;
-  hp.previous := p.previous;
-  p.previous := hp;
-  if assigned(hp.previous) then
-    hp.previous^.next := hp;
-{$endif replaceregdebug}
-{  PTaiProp(p.optInfo)^.Regs[reg] := c;}
-  While (p <> endP) Do
-    Begin
-      PTaiProp(p.optInfo)^.Regs[reg] := c;
-      getNextInstruction(p,p);
-    end;
-  tmpState := PTaiProp(p.optInfo)^.Regs[reg].wState;
-  repeat
-    PTaiProp(p.optInfo)^.Regs[reg] := c;
-  until not getNextInstruction(p,p) or
-        (PTaiProp(p.optInfo)^.Regs[reg].wState <> tmpState);
-{$ifdef replaceregdebug}
-  if assigned(p) then
-    begin
-      hp := Tai_asm_comment.Create(strpnew(
-        'restored '+att_reg2str[reg]+' till here... '+tostr(l))));
-      hp.next := p;
-      hp.previous := p.previous;
-      p.previous := hp;
-      if assigned(hp.previous) then
-        hp.previous^.next := hp;
-    end;
-{$endif replaceregdebug}
-end;
-
 procedure clearmemwrites(p: tai; reg: tregister);
 var
   beginmemwrite: tai;
@@ -791,6 +748,52 @@ begin
 {$endif replaceregdebug}
 end;
 
+Procedure RestoreRegContentsTo(reg: TRegister; const c: TContent; p, endP: Tai);
+var
+{$ifdef replaceregdebug}
+    hp: Tai;
+    l: longint;
+{$endif replaceregdebug}
+    tmpState: byte;
+begin
+{$ifdef replaceregdebug}
+  l := random(1000);
+  hp := Tai_asm_comment.Create(strpnew(
+          'restored '+att_reg2str[reg]+' with data from here... '+tostr(l))));
+  hp.next := p;
+  hp.previous := p.previous;
+  p.previous := hp;
+  if assigned(hp.previous) then
+    hp.previous^.next := hp;
+{$endif replaceregdebug}
+{  PTaiProp(p.optInfo)^.Regs[reg] := c;}
+  While (p <> endP) Do
+    Begin
+      PTaiProp(p.optInfo)^.Regs[reg] := c;
+      getNextInstruction(p,p);
+    end;
+  tmpState := PTaiProp(p.optInfo)^.Regs[reg].wState;
+  repeat
+    PTaiProp(p.optInfo)^.Regs[reg] := c;
+  until not getNextInstruction(p,p) or
+        (PTaiProp(p.optInfo)^.Regs[reg].wState <> tmpState) or
+        (p.typ = ait_label);
+  if p.typ = ait_label then
+    clearRegContentsFrom(reg,p,p);
+{$ifdef replaceregdebug}
+  if assigned(p) then
+    begin
+      hp := Tai_asm_comment.Create(strpnew(
+        'restored '+att_reg2str[reg]+' till here... '+tostr(l))));
+      hp.next := p;
+      hp.previous := p.previous;
+      p.previous := hp;
+      if assigned(hp.previous) then
+        hp.previous^.next := hp;
+    end;
+{$endif replaceregdebug}
+end;
+
 function NoHardCodedRegs(p: Taicpu; orgReg, newReg: TRegister): boolean;
 var chCount: byte;
 begin
@@ -1310,7 +1313,7 @@ begin
          (rState = pTaiprop(startmod.optInfo)^.regs[reg].rState) and
          (not(check) or
           (not(regInInstruction(reg,p)) and
-           (not(reg in usableregs) and
+           (not(reg in rg.usableregsint) and
             (startmod.typ = ait_instruction) and
             ((Taicpu(startmod).opcode = A_MOV) or
              (Taicpu(startmod).opcode = A_MOVZX) or
@@ -1390,6 +1393,23 @@ begin
   memtoreg := R_NO;
 end;
 
+procedure removeLocalStores(const t1: tai);
+var
+  p: tai;
+  regcount: tregister;
+begin
+{
+  for regcount := LoGPReg to HiGPReg do
+    if assigned(pTaiProp(t1.optinfo)^.regs[regcount].memwrite) and
+       (taicpu(pTaiProp(t1.optinfo)^.regs[regcount].memwrite).oper[1].ref^.base
+         = procinfo^.framepointer) then
+      begin
+        pTaiProp(pTaiProp(t1.optinfo)^.regs[regcount].memwrite.optinfo)^.canberemoved := true;
+        clearmemwrites(pTaiProp(t1.optinfo)^.regs[regcount].memwrite,regcount);
+      end;
+}
+end;
+
 procedure DoCSE(AsmL: TAAsmOutput; First, Last: Tai; findPrevSeqs, doSubOpts: boolean);
 {marks the instructions that can be removed by RemoveInstructs. They're not
  removed immediately because sometimes an instruction needs to be checked in
@@ -1433,7 +1453,7 @@ Begin
                               orgNrOfMods := 0;
                             If (p = StartMod) And
                                GetLastInstruction (p, hp1) And
-                               (hp1.typ <> ait_marker) Then
+                               not(hp1.typ in [ait_marker,ait_label]) then
 {so we don't try to check a sequence when p is the first instruction of the block}
                               begin
 {$ifdef csdebug}
@@ -1550,7 +1570,7 @@ Begin
                                            Begin
                                              getLastInstruction(p,hp3);
                                              If (hp4 <> prevSeq) or
-                                                not(regCounter in usableRegs + [R_EDI,R_ESI]) or
+                                                not(regCounter in rg.usableregsint + [R_EDI,R_ESI]) or
                                                 not ReplaceReg(asmL,RegInfo.New2OldReg[RegCounter],
                                                       regCounter,hp3,
                                                       PTaiProp(PrevSeq.optInfo)^.Regs[regCounter],true,hp5) then
@@ -1656,7 +1676,7 @@ Begin
                         if (Taicpu(p).oper[0].typ = top_reg) and
                            (Taicpu(p).oper[1].typ = top_reg) and
                            { only remove if we're not storing something in a regvar }
-                           (Taicpu(p).oper[1].reg in (usableregs+[R_EDI])) and
+                           (Taicpu(p).oper[1].reg in (rg.usableregsint+[R_EDI])) and
                            (Taicpu(p).opcode = A_MOV) and
                            getLastInstruction(p,hp4) and
                           { we only have to start replacing from the instruction after the mov, }
@@ -1735,13 +1755,18 @@ Begin
                               begin
                                 Taicpu(p).loadreg(0,regCounter);
                                 allocRegBetween(AsmL,reg32(regCounter),
-                                  PTaiProp(hp1.optinfo)^.regs[regCounter].startMod,p);
+                                  PTaiProp(hp1.optinfo)^.regs[reg32(regCounter)].startMod,p);
                               end;
                         End;
                       End;
                   End;
 
                 End;
+              A_LEAVE:
+                begin
+                  if getlastinstruction(p,hp1) then
+                    removeLocalStores(hp1);
+                end;
               A_STD: If GetLastInstruction(p, hp1) And
                         (PTaiProp(hp1.OptInfo)^.DirFlag = F_Set) Then
                         PTaiProp(Tai(p).OptInfo)^.CanBeRemoved := True;
@@ -1956,7 +1981,24 @@ End.
 
 {
   $Log$
-  Revision 1.24  2002-03-04 19:10:12  peter
+  Revision 1.25  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.24  2002/03/04 19:10:12  peter
     * removed compiler warnings
 
   Revision 1.23  2001/12/04 15:58:13  jonas

+ 49 - 32
compiler/i386/daopt386.pas

@@ -226,7 +226,7 @@ Var
 Implementation
 
 Uses
-  globals, systems, verbose, cgbase, symconst, symsym, tainst, tgcpu;
+  globals, systems, verbose, cgbase, symconst, symsym, tainst, rgobj;
 
 Type
   TRefCompare = function(const r1, r2: TReference): Boolean;
@@ -430,8 +430,8 @@ begin
           end;
     end;
   for regCounter := R_EAX to R_EBX do
-    if not(regCounter in usableregs) then
-      regs := regs + [regCounter];
+    if not(regCounter in rg.usableregsint) then
+      include(regs,regCounter);
 end;
 
 Procedure AddRegDeallocFor(asmL: TAAsmOutput; reg: TRegister; p: Tai);
@@ -439,10 +439,10 @@ var hp1: Tai;
     funcResRegs: TRegset;
     funcResReg: boolean;
 begin
-  if not(reg in usableregs) then
+  if not(reg in rg.usableregsint) then
     exit;
   getNoDeallocRegs(funcResRegs);
-  funcResRegs := funcResRegs - usableregs;
+  funcResRegs := funcResRegs - rg.usableregsint;
   funcResReg := reg in funcResRegs;
   hp1 := p;
   while not(funcResReg and
@@ -1165,7 +1165,7 @@ var
   hp, start: Tai;
   lastRemovedWasDealloc, firstRemovedWasAlloc, first: boolean;
 Begin
-  If not(reg in usableregs+[R_EDI,R_ESI]) or
+  If not(reg in rg.usableregsint+[R_EDI,R_ESI]) or
      not(assigned(p1)) then
     { this happens with registers which are loaded implicitely, outside the }
     { current block (e.g. esi with self)                                    }
@@ -1356,24 +1356,22 @@ Begin
      (reg > high(NrOfInstrSinceLastMod)) then
     exit;
   NrOfInstrSinceLastMod[Reg] := 0;
-  if (reg >= R_EAX) and (reg <= R_EDI) then
+  with p1^.regs[reg] do
     begin
-      with p1^.regs[reg] do
+      if doIncState then
         begin
-          if doIncState then
-            begin
-              incState(wstate,1);
-              typ := con_unknown;
-            end
-          else
-            if typ in [con_ref,con_invalid] then
-              typ := con_invalid
-            { con_invalid and con_noRemoveRef = con_unknown }
-            else typ := con_unknown;
-          memwrite := nil;
-        end;
-      invalidateDependingRegs(p1,reg);
+          incState(wstate,1);
+          typ := con_unknown;
+          startmod := nil;
+        end
+      else
+        if typ in [con_ref,con_const,con_invalid] then
+          typ := con_invalid
+        { con_invalid and con_noRemoveRef = con_unknown }
+        else typ := con_unknown;
+      memwrite := nil;
     end;
+  invalidateDependingRegs(p1,reg);
 End;
 
 {Procedure AddRegsToSet(p: Tai; Var RegSet: TRegSet);
@@ -1876,13 +1874,14 @@ begin
     end;
 End;
 
-Procedure DestroyAllRegs(p: PTaiProp);
+Procedure DestroyAllRegs(p: PTaiProp; read, written: boolean);
 Var Counter: TRegister;
 Begin {initializes/desrtoys all registers}
   For Counter := R_EAX To R_EDI Do
     Begin
-      ReadReg(p, Counter);
-      DestroyReg(p, Counter, true);
+      if read then
+        ReadReg(p, Counter);
+      DestroyReg(p, Counter, written);
       p^.regs[counter].MemWrite := nil;
     End;
   p^.DirFlag := F_Unknown;
@@ -2044,8 +2043,8 @@ Begin
         ait_marker:;
         ait_label:
 {$Ifndef JumpAnal}
-          If not labelCanBeSkipped(Tai_label(p)) Then
-            DestroyAllRegs(CurProp);
+          if not labelCanBeSkipped(Tai_label(p)) then
+            DestroyAllRegs(CurProp,false,false);
 {$Else JumpAnal}
           Begin
            If not labelCanBeSkipped(Tai_label(p)) Then
@@ -2120,7 +2119,7 @@ Begin
                                   GetLastInstruction(p, hp);
                                   CurProp^.regs := PTaiProp(hp.OptInfo)^.Regs;
                                   CurProp.DirFlag := PTaiProp(hp.OptInfo)^.DirFlag;
-                                  DestroyAllRegs(PTaiProp(hp.OptInfo))
+                                  DestroyAllRegs(PTaiProp(hp.OptInfo),true,true)
                                 End
                           End
 {$EndIf AnalyzeLoops}
@@ -2130,7 +2129,7 @@ Begin
                     GetLastInstruction(p, hp);
                     CurProp^.regs := PTaiProp(hp.OptInfo)^.Regs;
                     CurProp.DirFlag := PTaiProp(hp.OptInfo)^.DirFlag;
-                    DestroyAllRegs(CurProp)
+                    DestroyAllRegs(CurProp,true,true)
                   End;
           End;
 {$EndIf JumpAnal}
@@ -2141,7 +2140,8 @@ Begin
         ait_align: ; { may destroy flags !!! }
         ait_instruction:
           Begin
-            if Taicpu(p).is_jmp then
+            if Taicpu(p).is_jmp or
+               (Taicpu(p).opcode = A_JMP) then
              begin
 {$IfNDef JumpAnal}
                 for tmpReg := R_EAX to R_EDI do
@@ -2477,7 +2477,7 @@ Begin
                               'destroying all regs for prev instruction')));
                             insertllitem(asml,p, p.next,hp);
 {$endif statedebug}
-                            DestroyAllRegs(CurProp);
+                            DestroyAllRegs(CurProp,true,true);
                             LastFlagsChangeProp := CurProp;
                           End;
                       End;
@@ -2494,7 +2494,7 @@ Begin
               'destroying all regs: unknown Tai: '+tostr(ord(p.typ)))));
             insertllitem(asml,p, p.next,hp);
 {$endif statedebug}
-            DestroyAllRegs(CurProp);
+            DestroyAllRegs(CurProp,true,true);
           End;
       End;
       Inc(InstrCnt);
@@ -2592,7 +2592,24 @@ End.
 
 {
   $Log$
-  Revision 1.26  2002-03-04 19:10:13  peter
+  Revision 1.27  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.26  2002/03/04 19:10:13  peter
     * removed compiler warnings
 
   Revision 1.25  2001/12/29 15:29:59  jonas

+ 160 - 157
compiler/i386/n386add.pas

@@ -46,10 +46,10 @@ interface
       globtype,systems,
       cutils,verbose,globals,widestr,
       symconst,symdef,aasm,types,htypechk,
-      cgbase,temp_gen,pass_2,regvars,
+      cgbase,pass_2,regvars,
       cpuasm,
       ncon,nset,
-      tainst,cga,ncgutil,n386util,tgcpu;
+      tainst,cga,ncgutil,n386util,tgobj,rgobj,rgcpu,cgobj;
 
     function ti386addnode.getresflags(unsigned : boolean) : tresflags;
 
@@ -104,11 +104,11 @@ interface
          if (left.resulttype.def.deftype<>stringdef) and
             ((left.resulttype.def.deftype<>setdef) or (tsetdef(left.resulttype.def).settype=smallset)) and
             (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
-           ungetiftemp(left.location.reference);
+           tg.ungetiftemp(exprasmlist,left.location.reference);
          if (right.resulttype.def.deftype<>stringdef) and
             ((right.resulttype.def.deftype<>setdef) or (tsetdef(right.resulttype.def).settype=smallset)) and
             (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
-           ungetiftemp(right.location.reference);
+           tg.ungetiftemp(exprasmlist,right.location.reference);
          { in case of comparison operation the put result in the flags }
          if cmpop then
            begin
@@ -154,10 +154,10 @@ interface
     procedure ti386addnode.second_addstring;
 
       var
-        pushedregs : tpushed;
+        regstopush : tregisterset;
+        pushedregs : tpushedsaved;
         href       : treference;
         cmpop      : boolean;
-        regstopush : byte;
       begin
         { string operations are not commutative }
         if nf_swaped in flags then
@@ -176,8 +176,8 @@ interface
                         { or a function result, so simply check for a        }
                         { temp of 256 bytes(JM)                                          }
 
-                        if not(istemp(left.location.reference) and
-                               (getsizeoftemp(left.location.reference) = 256)) and
+                        if not(tg.istemp(left.location.reference) and
+                               (tg.getsizeoftemp(left.location.reference) = 256)) and
                            not(nf_use_strconcat in flags) then
                           begin
 
@@ -185,12 +185,12 @@ interface
                              { string in register would be funny    }
                              { therefore produce a temporary string }
 
-                             gettempofsizereference(256,href);
+                             tg.gettempofsizereference(exprasmlist,256,href);
                              copyshortstring(href,left.location.reference,255,false,true);
                              { release the registers }
 {                             done by copyshortstring now (JM)           }
-{                             del_reference(left.location.reference); }
-                             ungetiftemp(left.location.reference);
+{                             rg.del_reference(exprasmlist,left.location.reference); }
+                             tg.ungetiftemp(exprasmlist,left.location.reference);
 
                              { does not hurt: }
                              clear_location(left.location);
@@ -206,41 +206,41 @@ interface
                         { push them (so the release is in the right place, }
                         { because emitpushreferenceaddr doesn't need extra }
                         { registers) (JM)                                  }
-                        regstopush := $ff;
+                        regstopush := all_registers;
                         remove_non_regvars_from_loc(right.location,
                           regstopush);
-                        pushusedregisters(pushedregs,regstopush);
+                        rg.saveusedregisters(exprasmlist,pushedregs,regstopush);
                        { push the maximum possible length of the result }
                         emitpushreferenceaddr(left.location.reference);
                        { the optimizer can more easily put the          }
                        { deallocations in the right place if it happens }
                        { too early than when it happens too late (if    }
                        { the pushref needs a "lea (..),edi; push edi")  }
-                        del_reference(right.location.reference);
+                        rg.del_reference(exprasmlist,right.location.reference);
                         emitpushreferenceaddr(right.location.reference);
-                        saveregvars(regstopush);
+                        rg.saveregvars(exprasmlist,regstopush);
                         emitcall('FPC_SHORTSTR_CONCAT');
-                        ungetiftemp(right.location.reference);
+                        tg.ungetiftemp(exprasmlist,right.location.reference);
                         maybe_loadself;
-                        popusedregisters(pushedregs);
+                        rg.restoreusedregisters(exprasmlist,pushedregs);
                         set_location(location,left.location);
                      end;
                    ltn,lten,gtn,gten,equaln,unequaln :
                      begin
                        cmpop := true;
-                       pushusedregisters(pushedregs,$ff);
+                       rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
                        secondpass(left);
                        emitpushreferenceaddr(left.location.reference);
-                       del_reference(left.location.reference);
+                       rg.del_reference(exprasmlist,left.location.reference);
                        secondpass(right);
                        emitpushreferenceaddr(right.location.reference);
-                       del_reference(right.location.reference);
-                       saveregvars($ff);
+                       rg.del_reference(exprasmlist,right.location.reference);
+                       rg.saveregvars(exprasmlist,all_registers);
                        emitcall('FPC_SHORTSTR_COMPARE');
                        maybe_loadself;
-                       popusedregisters(pushedregs);
-                       ungetiftemp(left.location.reference);
-                       ungetiftemp(right.location.reference);
+                       rg.restoreusedregisters(exprasmlist,pushedregs);
+                       tg.ungetiftemp(exprasmlist,left.location.reference);
+                       tg.ungetiftemp(exprasmlist,right.location.reference);
                      end;
                 end;
                 SetResultLocation(cmpop,true);
@@ -288,7 +288,8 @@ interface
 {$ifdef SUPPORT_MMX}
          mmxbase : tmmxtype;
 {$endif SUPPORT_MMX}
-         regstopush: byte;
+         pushedreg : tpushedsaved;
+         regstopush: tregisterset;
 
       procedure firstjmp64bitcmp;
 
@@ -566,10 +567,10 @@ interface
                                    { bts requires both elements to be registers }
                                      if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
                                       begin
-                                        ungetiftemp(left.location.reference);
-                                        del_location(left.location);
+                                        tg.ungetiftemp(exprasmlist,left.location.reference);
+                                        rg.del_location(exprasmlist,left.location);
 {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
-                                        hregister:=getregisterint;
+                                        hregister:=rg.getregisterint(exprasmlist);
                                         emit_ref_reg(A_MOV,opsize,
                                           newreference(left.location.reference),hregister);
                                         clear_location(left.location);
@@ -579,9 +580,9 @@ interface
                                       end;
                                      if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
                                       begin
-                                        ungetiftemp(right.location.reference);
-                                        del_location(right.location);
-                                        hregister:=getregisterint;
+                                        tg.ungetiftemp(exprasmlist,right.location.reference);
+                                        rg.del_location(exprasmlist,right.location);
+                                        hregister:=rg.getregisterint(exprasmlist);
                                         emit_ref_reg(A_MOV,opsize,
                                           newreference(right.location.reference),hregister);
                                         clear_location(right.location);
@@ -661,9 +662,9 @@ interface
                                         swapleftright;
                                       if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
                                         begin
-                                         ungetiftemp(left.location.reference);
-                                         del_reference(left.location.reference);
-                                         hregister:=getregisterint;
+                                         tg.ungetiftemp(exprasmlist,left.location.reference);
+                                         rg.del_reference(exprasmlist,left.location.reference);
+                                         hregister:=rg.getregisterint(exprasmlist);
                                          emit_ref_reg(A_MOV,opsize,
                                            newreference(left.location.reference),hregister);
                                          clear_location(left.location);
@@ -676,7 +677,7 @@ interface
                                         {save the register var in a temp register, because
                                           its value is going to be modified}
                                           begin
-                                            hregister := getregisterint;
+                                            hregister := rg.getregisterint(exprasmlist);
                                             emit_reg_reg(A_MOV,opsize,
                                               left.location.register,hregister);
                                              clear_location(left.location);
@@ -734,55 +735,57 @@ interface
                            { release left.location, since it's a   }
                            { constant (JM)                             }
                            release_loc(right.location);
-                           location.register := getregisterint;
+                           location.register := rg.getregisterint(exprasmlist);
                            emitloadord2reg(right.location,torddef(u32bittype.def),location.register,false);
                            emit_const_reg(A_SHL,S_L,power,location.register)
                          End
                        Else
                         Begin
 {$EndIf NoShlMul}
-                         regstopush := $ff;
+                         regstopush := ALL_REGISTERS;
                          remove_non_regvars_from_loc(right.location,regstopush);
                          remove_non_regvars_from_loc(left.location,regstopush);
                          { now, regstopush does NOT contain EAX and/or EDX if they are }
                          { used in either the left or the right location, excepts if   }
                          {they are regvars. It DOES contain them if they are used in   }
                          { another location (JM)                                       }
-                         if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
+                         if not(R_EAX in rg.unusedregsint) and
+                            (R_EAX in regstopush) then
                           begin
                            emit_reg(A_PUSH,S_L,R_EAX);
                            popeax:=true;
                           end;
-                         if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
+                         if not(R_EDX in rg.unusedregsint) and
+                            (R_EDX in regstopush) then
                           begin
                            emit_reg(A_PUSH,S_L,R_EDX);
                            popedx:=true;
                           end;
                          { left.location can be R_EAX !!! }
-                         getexplicitregister32(R_EDI);
+                         rg.getexplicitregisterint(exprasmlist,R_EDI);
                          { load the left value }
                          emitloadord2reg(left.location,torddef(u32bittype.def),R_EDI,true);
                          release_loc(left.location);
                          { allocate EAX }
-                         if R_EAX in unused then
+                         if R_EAX in rg.unusedregsint then
                            exprasmList.concat(Tairegalloc.Alloc(R_EAX));
                          { load he right value }
                          emitloadord2reg(right.location,torddef(u32bittype.def),R_EAX,true);
                          release_loc(right.location);
                          { allocate EAX if it isn't yet allocated (JM) }
-                         if (R_EAX in unused) then
+                         if (R_EAX in rg.unusedregsint) then
                            exprasmList.concat(Tairegalloc.Alloc(R_EAX));
                          { also allocate EDX, since it is also modified by }
                          { a mul (JM)                                      }
-                         if R_EDX in unused then
+                         if R_EDX in rg.unusedregsint then
                            exprasmList.concat(Tairegalloc.Alloc(R_EDX));
                          emit_reg(A_MUL,S_L,R_EDI);
-                         ungetregister32(R_EDI);
-                         if R_EDX in unused then
+                         rg.ungetregisterint(exprasmlist,R_EDI);
+                         if R_EDX in rg.unusedregsint then
                            exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
-                         if R_EAX in unused then
+                         if R_EAX in rg.unusedregsint then
                            exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
-                         location.register := getregisterint;
+                         location.register := rg.getregisterint(exprasmlist);
                          emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
                          if popedx then
                           emit_reg(A_POP,S_L,R_EDX);
@@ -825,8 +828,8 @@ interface
                              else
                                begin
                                   case opsize of
-                                     S_L : hregister:=getregisterint;
-                                     S_B : hregister:=reg32toreg8(getregisterint);
+                                     S_L : hregister:=rg.getregisterint(exprasmlist);
+                                     S_B : hregister:=reg32toreg8(rg.getregisterint(exprasmlist));
                                   end;
                                   emit_reg_reg(A_MOV,opsize,left.location.register,
                                     hregister);
@@ -834,8 +837,8 @@ interface
                           end
                         else
                           begin
-                             ungetiftemp(left.location.reference);
-                             del_reference(left.location.reference);
+                             tg.ungetiftemp(exprasmlist,left.location.reference);
+                             rg.del_reference(exprasmlist,left.location.reference);
                              if is_in_dest then
                                begin
                                   hregister:=location.register;
@@ -846,9 +849,9 @@ interface
                                begin
                                   { first give free, then demand new register }
                                   case opsize of
-                                     S_L : hregister:=getregisterint;
-                                     S_W : hregister:=reg32toreg16(getregisterint);
-                                     S_B : hregister:=reg32toreg8(getregisterint);
+                                     S_L : hregister:=rg.getregisterint(exprasmlist);
+                                     S_W : hregister:=reg32toreg16(rg.getregisterint(exprasmlist));
+                                     S_B : hregister:=reg32toreg8(rg.getregisterint(exprasmlist));
                                   end;
                                   emit_ref_reg(A_MOV,opsize,
                                     newreference(left.location.reference),hregister);
@@ -879,24 +882,24 @@ interface
                                begin
                                   if extra_not then
                                     emit_reg(A_NOT,opsize,location.register);
-                                  getexplicitregister32(R_EDI);
+                                  rg.getexplicitregisterint(exprasmlist,R_EDI);
                                   emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
                                   emit_reg_reg(op,opsize,location.register,R_EDI);
                                   emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
-                                  ungetregister32(R_EDI);
+                                  rg.ungetregisterint(exprasmlist,R_EDI);
                                end
                              else
                                begin
                                   if extra_not then
                                     emit_reg(A_NOT,opsize,location.register);
-                                  getexplicitregister32(R_EDI);
+                                  rg.getexplicitregisterint(exprasmlist,R_EDI);
                                   emit_ref_reg(A_MOV,opsize,
                                     newreference(right.location.reference),R_EDI);
                                   emit_reg_reg(op,opsize,location.register,R_EDI);
                                   emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
-                                  ungetregister32(R_EDI);
-                                  ungetiftemp(right.location.reference);
-                                  del_reference(right.location.reference);
+                                  rg.ungetregisterint(exprasmlist,R_EDI);
+                                  tg.ungetiftemp(exprasmlist,right.location.reference);
+                                  rg.del_reference(exprasmlist,right.location.reference);
                                end;
                           end
                         else
@@ -938,12 +941,12 @@ interface
                                     begin
                                        if extra_not then
                                          begin
-                                            getexplicitregister32(R_EDI);
+                                            rg.getexplicitregisterint(exprasmlist,R_EDI);
                                             emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
                                             emit_reg(A_NOT,S_L,R_EDI);
                                             emit_reg_reg(A_AND,S_L,R_EDI,
                                               location.register);
-                                            ungetregister32(R_EDI);
+                                            rg.ungetregisterint(exprasmlist,R_EDI);
                                          end
                                        else
                                          begin
@@ -955,21 +958,21 @@ interface
                                     begin
                                        if extra_not then
                                          begin
-                                            getexplicitregister32(R_EDI);
+                                            rg.getexplicitregisterint(exprasmlist,R_EDI);
                                             emit_ref_reg(A_MOV,S_L,newreference(
                                               right.location.reference),R_EDI);
                                             emit_reg(A_NOT,S_L,R_EDI);
                                             emit_reg_reg(A_AND,S_L,R_EDI,
                                               location.register);
-                                            ungetregister32(R_EDI);
+                                            rg.ungetregisterint(exprasmlist,R_EDI);
                                          end
                                        else
                                          begin
                                             emit_ref_reg(op,opsize,newreference(
                                               right.location.reference),location.register);
                                          end;
-                                       ungetiftemp(right.location.reference);
-                                       del_reference(right.location.reference);
+                                       tg.ungetiftemp(exprasmlist,right.location.reference);
+                                       rg.del_reference(exprasmlist,right.location.reference);
                                     end;
                                end;
                           end;
@@ -998,15 +1001,15 @@ interface
                                location.register);
                           end;
                         case opsize of
-                           S_L : ungetregister32(right.location.register);
-                           S_B : ungetregister32(reg8toreg32(right.location.register));
+                           S_L : rg.ungetregisterint(exprasmlist,right.location.register);
+                           S_B : rg.ungetregisterint(exprasmlist,reg8toreg32(right.location.register));
                         end;
                      end;
 
                    if cmpop then
                      case opsize of
-                        S_L : ungetregister32(location.register);
-                        S_B : ungetregister32(reg8toreg32(location.register));
+                        S_L : rg.ungetregisterint(exprasmlist,location.register);
+                        S_B : rg.ungetregisterint(exprasmlist,reg8toreg32(location.register));
                      end;
 
                    { only in case of overflow operations }
@@ -1055,17 +1058,17 @@ interface
                                hregister:=location.register
                              else
                                begin
-                                  hregister:=reg32toreg8(getregisterint);
+                                  hregister:=reg32toreg8(rg.getregisterint(exprasmlist));
                                   emit_reg_reg(A_MOV,S_B,location.register,
                                     hregister);
                                end;
                           end
                         else
                           begin
-                             del_reference(location.reference);
+                             rg.del_reference(exprasmlist,location.reference);
 
                              { first give free then demand new register }
-                             hregister:=reg32toreg8(getregisterint);
+                             hregister:=reg32toreg8(rg.getregisterint(exprasmlist));
                              emit_ref_reg(A_MOV,S_B,newreference(location.reference),
                                hregister);
                           end;
@@ -1095,16 +1098,16 @@ interface
                           begin
                              emit_ref_reg(A_CMP,S_B,newreference(
                                 right.location.reference),location.register);
-                             del_reference(right.location.reference);
+                             rg.del_reference(exprasmlist,right.location.reference);
                           end;
                      end
                    else
                      begin
                         emit_reg_reg(A_CMP,S_B,right.location.register,
                           location.register);
-                        ungetregister32(reg8toreg32(right.location.register));
+                        rg.ungetregisterint(exprasmlist,reg8toreg32(right.location.register));
                      end;
-                   ungetregister32(reg8toreg32(location.register));
+                   rg.ungetregisterint(exprasmlist,reg8toreg32(location.register));
                 end
               else
               { 16 bit enumeration type }
@@ -1130,17 +1133,17 @@ interface
                                hregister:=location.register
                              else
                                begin
-                                  hregister:=reg32toreg16(getregisterint);
+                                  hregister:=reg32toreg16(rg.getregisterint(exprasmlist));
                                   emit_reg_reg(A_MOV,S_W,location.register,
                                     hregister);
                                end;
                           end
                         else
                           begin
-                             del_reference(location.reference);
+                             rg.del_reference(exprasmlist,location.reference);
 
                              { first give free then demand new register }
-                             hregister:=reg32toreg16(getregisterint);
+                             hregister:=reg32toreg16(rg.getregisterint(exprasmlist));
                              emit_ref_reg(A_MOV,S_W,newreference(location.reference),
                                hregister);
                           end;
@@ -1170,16 +1173,16 @@ interface
                           begin
                              emit_ref_reg(A_CMP,S_W,newreference(
                                 right.location.reference),location.register);
-                             del_reference(right.location.reference);
+                             rg.del_reference(exprasmlist,right.location.reference);
                           end;
                      end
                    else
                      begin
                         emit_reg_reg(A_CMP,S_W,right.location.register,
                           location.register);
-                        ungetregister32(reg16toreg32(right.location.register));
+                        rg.ungetregisterint(exprasmlist,reg16toreg32(right.location.register));
                      end;
-                   ungetregister32(reg16toreg32(location.register));
+                   rg.ungetregisterint(exprasmlist,reg16toreg32(location.register));
                 end
               else
               { 64 bit types }
@@ -1270,8 +1273,8 @@ interface
                                     end
                                   else
                                     begin
-                                       hregister:=getregisterint;
-                                       hregister2:=getregisterint;
+                                       hregister:=rg.getregisterint(exprasmlist);
+                                       hregister2:=rg.getregisterint(exprasmlist);
                                        emit_reg_reg(A_MOV,S_L,left.location.registerlow,
                                          hregister);
                                        emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
@@ -1280,8 +1283,8 @@ interface
                                end
                              else
                                begin
-                                  ungetiftemp(left.location.reference);
-                                  del_reference(left.location.reference);
+                                  tg.ungetiftemp(exprasmlist,left.location.reference);
+                                  rg.del_reference(exprasmlist,left.location.reference);
                                   if is_in_dest then
                                     begin
                                        hregister:=location.registerlow;
@@ -1290,8 +1293,8 @@ interface
                                     end
                                   else
                                     begin
-                                       hregister:=getregisterint;
-                                       hregister2:=getregisterint;
+                                       hregister:=rg.getregisterint(exprasmlist);
+                                       hregister2:=rg.getregisterint(exprasmlist);
                                        emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
                                     end;
                                end;
@@ -1319,27 +1322,27 @@ interface
                                begin
                                   if right.location.loc=LOC_CREGISTER then
                                     begin
-                                       getexplicitregister32(R_EDI);
+                                       rg.getexplicitregisterint(exprasmlist,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
                                        emit_reg_reg(op,opsize,location.register,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
-                                       ungetregister32(R_EDI);
-                                       getexplicitregister32(R_EDI);
+                                       rg.ungetregisterint(exprasmlist,R_EDI);
+                                       rg.getexplicitregisterint(exprasmlist,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
                                        { the carry flag is still ok }
                                        emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
-                                       ungetregister32(R_EDI);
+                                       rg.ungetregisterint(exprasmlist,R_EDI);
                                     end
                                   else
                                     begin
-                                       getexplicitregister32(R_EDI);
+                                       rg.getexplicitregisterint(exprasmlist,R_EDI);
                                        emit_ref_reg(A_MOV,opsize,
                                          newreference(right.location.reference),R_EDI);
                                        emit_reg_reg(op,opsize,location.registerlow,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
-                                       ungetregister32(R_EDI);
-                                       getexplicitregister32(R_EDI);
+                                       rg.ungetregisterint(exprasmlist,R_EDI);
+                                       rg.getexplicitregisterint(exprasmlist,R_EDI);
                                        hr:=newreference(right.location.reference);
                                        inc(hr^.offset,4);
                                        emit_ref_reg(A_MOV,opsize,
@@ -1348,9 +1351,9 @@ interface
                                        emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
                                        emit_reg_reg(A_MOV,opsize,R_EDI,
                                          location.registerhigh);
-                                       ungetregister32(R_EDI);
-                                       ungetiftemp(right.location.reference);
-                                       del_reference(right.location.reference);
+                                       rg.ungetregisterint(exprasmlist,R_EDI);
+                                       tg.ungetiftemp(exprasmlist,right.location.reference);
+                                       rg.del_reference(exprasmlist,right.location.reference);
                                     end;
                                end
                              else if cmpop then
@@ -1379,8 +1382,8 @@ interface
 
                                        emitjmp(C_None,falselabel);
 
-                                       ungetiftemp(right.location.reference);
-                                       del_reference(right.location.reference);
+                                       tg.ungetiftemp(exprasmlist,right.location.reference);
+                                       rg.del_reference(exprasmlist,right.location.reference);
                                     end;
                                end
                              else
@@ -1418,8 +1421,8 @@ interface
                                             inc(hr^.offset,4);
                                             emit_ref_reg(op2,S_L,
                                               hr,location.registerhigh);
-                                            ungetiftemp(right.location.reference);
-                                            del_reference(right.location.reference);
+                                            tg.ungetiftemp(exprasmlist,right.location.reference);
+                                            rg.del_reference(exprasmlist,right.location.reference);
                                          end;
                                     end;
                                end;
@@ -1460,14 +1463,14 @@ interface
                                     right.location.registerhigh,
                                     location.registerhigh);
                                end;
-                             ungetregister32(right.location.registerlow);
-                             ungetregister32(right.location.registerhigh);
+                             rg.ungetregisterint(exprasmlist,right.location.registerlow);
+                             rg.ungetregisterint(exprasmlist,right.location.registerhigh);
                           end;
 
                         if cmpop then
                           begin
-                             ungetregister32(location.registerlow);
-                             ungetregister32(location.registerhigh);
+                             rg.ungetregisterint(exprasmlist,location.registerlow);
+                             rg.ungetregisterint(exprasmlist,location.registerhigh);
                           end;
 
                         { only in case of overflow operations }
@@ -1521,55 +1524,37 @@ interface
 
                     if (right.location.loc<>LOC_FPU) then
                       begin
-                         if right.location.loc=LOC_CFPUREGISTER then
-                           begin
-                              emit_reg( A_FLD,S_NO,
-                                correct_fpuregister(right.location.register,fpuvaroffset));
-                              inc(fpuvaroffset);
-                            end
-                         else
-                            begin
-                              floatload(tfloatdef(right.resulttype.def).typ,right.location.reference);
-                              if pushedfpu then
-                                ungetiftemp(right.location.reference);
-                            end;
+                         cg.a_loadfpu_loc_reg(exprasmlist,
+                           def_cgsize(right.resulttype.def),right.location,
+                           R_ST);
+                         if (right.location.loc <> LOC_CFPUREGISTER) and
+                            pushedfpu then
+                           tg.ungetiftemp(exprasmlist,right.location.reference);
+
                          if (left.location.loc<>LOC_FPU) then
                            begin
-                              if left.location.loc=LOC_CFPUREGISTER then
-                                begin
-                                   emit_reg( A_FLD,S_NO,
-                                     correct_fpuregister(left.location.register,fpuvaroffset));
-                                   inc(fpuvaroffset);
-                                end
-                              else
-                                begin
-                                  floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
-                                  if pushedfpu then
-                                     ungetiftemp(left.location.reference);
-                                end;
+                              cg.a_loadfpu_loc_reg(exprasmlist,
+                                def_cgsize(left.resulttype.def),
+                                left.location,R_ST);
+                              if (left.location.loc <> LOC_CFPUREGISTER) and
+                                 pushedfpu then
+                                tg.ungetiftemp(exprasmlist,left.location.reference);
                            end
                          { left was on the stack => swap }
                          else
                            toggleflag(nf_swaped);
 
                          { releases the right reference }
-                         del_reference(right.location.reference);
+                         rg.del_reference(exprasmlist,right.location.reference);
                       end
                     { the nominator in st0 }
                     else if (left.location.loc<>LOC_FPU) then
                       begin
-                         if left.location.loc=LOC_CFPUREGISTER then
-                           begin
-                              emit_reg( A_FLD,S_NO,
-                                correct_fpuregister(left.location.register,fpuvaroffset));
-                              inc(fpuvaroffset);
-                           end
-                         else
-                           begin
-                             floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
-                             if pushedfpu then
-                              ungetiftemp(left.location.reference);
-                           end;
+                         cg.a_loadfpu_loc_reg(exprasmlist,
+                           def_cgsize(left.resulttype.def),left.location,R_ST);
+                         if (left.location.loc <> LOC_CFPUREGISTER) and
+                            pushedfpu then
+                           tg.ungetiftemp(exprasmlist,left.location.reference);
                       end
                     { fpu operands are always in the wrong order on the stack }
                     else
@@ -1577,7 +1562,7 @@ interface
 
                     { releases the left reference }
                     if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
-                      del_reference(left.location.reference);
+                      rg.del_reference(exprasmlist,left.location.reference);
 
                     { if we swaped the tree nodes, then use the reverse operator }
                     if nf_swaped in flags then
@@ -1596,28 +1581,28 @@ interface
                     if op<>A_FCOMPP then
                       begin
                          emit_reg_reg(op,S_NO,R_ST,R_ST1);
-                         dec(fpuvaroffset);
+                         dec(trgcpu(rg).fpuvaroffset);
                       end
                     else
                       begin
                          emit_none(op,S_NO);
-                         dec(fpuvaroffset,2);
+                         dec(trgcpu(rg).fpuvaroffset,2);
                       end;
 
                     { on comparison load flags }
                     if cmpop then
                      begin
-                       if not(R_EAX in unused) then
+                       if not(R_EAX in rg.unusedregsint) then
                          begin
-                           getexplicitregister32(R_EDI);
+                           rg.getexplicitregisterint(exprasmlist,R_EDI);
                            emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
                          end;
                        emit_reg(A_FNSTSW,S_NO,R_AX);
                        emit_none(A_SAHF,S_NO);
-                       if not(R_EAX in unused) then
+                       if not(R_EAX in rg.unusedregsint) then
                          begin
                            emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
-                           ungetregister32(R_EDI);
+                           rg.ungetregisterint(exprasmlist,R_EDI);
                          end;
                        if nf_swaped in flags then
                         begin
@@ -1650,6 +1635,7 @@ interface
                      begin
                         clear_location(location);
                         location.loc:=LOC_FPU;
+                        location.register := R_ST;
                      end;
                  end
 {$ifdef SUPPORT_MMX}
@@ -1754,14 +1740,14 @@ interface
                                end
                              else
                                begin
-                                  hregister:=getregistermmx;
+                                  hregister:=rg.getregistermm(exprasmlist);
                                   emit_reg_reg(A_MOVQ,S_NO,left.location.register,
                                     hregister);
                                end
                           end
                         else
                           begin
-                             del_reference(left.location.reference);
+                             rg.del_reference(exprasmlist,left.location.reference);
 
                              if is_in_dest then
                                begin
@@ -1771,7 +1757,7 @@ interface
                                end
                              else
                                begin
-                                  hregister:=getregistermmx;
+                                  hregister:=rg.getregistermm(exprasmlist);
                                   emit_ref_reg(A_MOVQ,S_NO,
                                     newreference(left.location.reference),hregister);
                                end;
@@ -1809,7 +1795,7 @@ interface
                                     R_MM7);
                                   emit_reg_reg(A_MOVQ,S_NO,
                                     R_MM7,location.register);
-                                  del_reference(right.location.reference);
+                                  rg.del_reference(exprasmlist,right.location.reference);
                                end;
                           end
                         else
@@ -1823,7 +1809,7 @@ interface
                                begin
                                   emit_ref_reg(op,S_NO,newreference(
                                     right.location.reference),location.register);
-                                  del_reference(right.location.reference);
+                                  rg.del_reference(exprasmlist,right.location.reference);
                                end;
                           end;
                      end
@@ -1845,7 +1831,7 @@ interface
                                right.location.register,
                                location.register);
                           end;
-                        ungetregistermmx(right.location.register);
+                        rg.ungetregistermm(exprasmlist,right.location.register);
                      end;
                 end
 {$endif SUPPORT_MMX}
@@ -1859,7 +1845,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.29  2002-03-04 19:10:13  peter
+  Revision 1.30  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.29  2002/03/04 19:10:13  peter
     * removed compiler warnings
 
   Revision 1.28  2001/12/30 17:24:46  jonas

+ 126 - 133
compiler/i386/n386cal.pas

@@ -60,10 +60,10 @@ implementation
 {$ifdef GDB}
       gdb,
 {$endif GDB}
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       cpubase,cpuasm,
       nmem,nld,
-      tainst,cga,tgcpu,n386ld,n386util,regvars;
+      tainst,cga,cgobj,tgobj,n386ld,n386util,regvars,rgobj,rgcpu;
 
 {*****************************************************************************
                              TI386CALLPARANODE
@@ -119,7 +119,7 @@ implementation
                begin
                  inc(pushedparasize,4);
                  emitpushreferenceaddr(left.location.reference);
-                 del_reference(left.location.reference);
+                 rg.del_reference(exprasmlist,left.location.reference);
                end
              else
                push_value_para(left,inlined,is_cdecl,para_offset,para_alignment);
@@ -147,7 +147,7 @@ implementation
                     end
                   else
                     emit_reg(A_PUSH,S_L,left.location.register);
-                  ungetregister32(left.location.register);
+                  rg.ungetregisterint(exprasmlist,left.location.register);
                 end
               else
                 begin
@@ -157,16 +157,16 @@ implementation
                      begin
                        if inlined then
                          begin
-                           getexplicitregister32(R_EDI);
+                           rg.getexplicitregisterint(exprasmlist,R_EDI);
                            emit_ref_reg(A_LEA,S_L,
                              newreference(left.location.reference),R_EDI);
                            r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                            emit_reg_ref(A_MOV,S_L,R_EDI,r);
-                           ungetregister32(R_EDI);
+                           rg.ungetregisterint(exprasmlist,R_EDI);
                          end
                       else
                         emitpushreferenceaddr(left.location.reference);
-                        del_reference(left.location.reference);
+                        rg.del_reference(exprasmlist,left.location.reference);
                      end;
                 end;
            end
@@ -184,16 +184,16 @@ implementation
               inc(pushedparasize,4);
               if inlined then
                 begin
-                   getexplicitregister32(R_EDI);
+                   rg.getexplicitregisterint(exprasmlist,R_EDI);
                    emit_ref_reg(A_LEA,S_L,
                      newreference(left.location.reference),R_EDI);
                    r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                    emit_reg_ref(A_MOV,S_L,R_EDI,r);
-                   ungetregister32(R_EDI);
+                   rg.ungetregisterint(exprasmlist,R_EDI);
                 end
               else
                 emitpushreferenceaddr(left.location.reference);
-              del_reference(left.location.reference);
+              rg.del_reference(exprasmlist,left.location.reference);
            end
          else
            begin
@@ -216,16 +216,16 @@ implementation
                    inc(pushedparasize,4);
                    if inlined then
                      begin
-                        getexplicitregister32(R_EDI);
+                        rg.getexplicitregisterint(exprasmlist,R_EDI);
                         emit_ref_reg(A_LEA,S_L,
                           newreference(left.location.reference),R_EDI);
                         r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                         emit_reg_ref(A_MOV,S_L,R_EDI,r);
-                        ungetregister32(R_EDI);
+                        rg.ungetregisterint(exprasmlist,R_EDI);
                      end
                    else
                      emitpushreferenceaddr(left.location.reference);
-                   del_reference(left.location.reference);
+                   rg.del_reference(exprasmlist,left.location.reference);
                 end
               else
                 begin
@@ -254,9 +254,9 @@ implementation
 
     procedure ti386callnode.pass_2;
       var
-         unusedregisters : tregisterset;
-         usablecount : byte;
-         pushed : tpushed;
+         regs_to_push : tregisterset;
+         unusedstate: pointer;
+         pushed : tpushedsaved;
          funcretref,refcountedtemp : treference;
          hregister,hregister2 : tregister;
          oldpushedparasize : longint;
@@ -292,7 +292,6 @@ implementation
          push_size : longint;
 {$endif OPTALIGN}
          pop_allowed : boolean;
-         regs_to_push : byte;
          constructorfailed : tasmlabel;
 
       label
@@ -306,19 +305,18 @@ implementation
          inlined:=false;
          loadesi:=true;
          no_virtual_call:=false;
-         unusedregisters:=unused;
-         usablecount:=usablereg32;
+         rg.saveunusedstate(unusedstate);
 
          { if we allocate the temp. location for ansi- or widestrings }
          { already here, we avoid later a push/pop                    }
          if is_widestring(resulttype.def) then
            begin
-             gettempwidestringreference(refcountedtemp);
+             tg.gettempwidestringreference(exprasmlist,refcountedtemp);
              decrstringref(resulttype.def,refcountedtemp);
            end
          else if is_ansistring(resulttype.def) then
            begin
-             gettempansistringreference(refcountedtemp);
+             tg.gettempansistringreference(exprasmlist,refcountedtemp);
              decrstringref(resulttype.def,refcountedtemp);
            end;
 
@@ -344,7 +342,7 @@ implementation
                 the para's are stored there }
               tprocdef(procdefinition).parast.symtablelevel:=aktprocdef.localst.symtablelevel;
               if assigned(params) then
-                inlinecode.para_offset:=gettempofsizepersistant(inlinecode.para_size);
+                inlinecode.para_offset:=tg.gettempofsizepersistant(exprasmlist,inlinecode.para_size);
               store_parast_fixup:=tprocdef(procdefinition).parast.address_fixup;
               tprocdef(procdefinition).parast.address_fixup:=inlinecode.para_offset;
 {$ifdef extdebug}
@@ -378,16 +376,16 @@ implementation
 
               { save all used registers }
               regs_to_push := tprocdef(procdefinition).usedregisters;
-              pushusedregisters(pushed,regs_to_push);
+              rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
 
               { give used registers through }
-              usedinproc:=usedinproc or tprocdef(procdefinition).usedregisters;
+              rg.usedinproc:=rg.usedinproc + tprocdef(procdefinition).usedregisters;
            end
          else
            begin
-              regs_to_push := $ff;
-              pushusedregisters(pushed,regs_to_push);
-              usedinproc:=$ff;
+              regs_to_push := all_registers;
+              rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
+              rg.usedinproc:=all_registers;
               { no IO check for methods and procedure variables }
               iolabel:=nil;
            end;
@@ -470,7 +468,7 @@ implementation
                 if inlined then
                   begin
                      reset_reference(funcretref);
-                     funcretref.offset:=gettempofsizepersistant(resulttype.def.size);
+                     funcretref.offset:=tg.gettempofsizepersistant(exprasmlist,resulttype.def.size);
                      funcretref.base:=procinfo^.framepointer;
 {$ifdef extdebug}
                      Comment(V_debug,'function return value is at offset '
@@ -481,7 +479,7 @@ implementation
 {$endif extdebug}
                   end
                 else
-                  gettempofsizereference(resulttype.def.size,funcretref);
+                  tg.gettempofsizereference(exprasmlist,resulttype.def.size,funcretref);
            end;
          if assigned(params) then
            begin
@@ -504,7 +502,7 @@ implementation
                   para_alignment,para_offset);
            end;
          if inlined then
-           inlinecode.retoffset:=gettempofsizepersistant(Align(resulttype.def.size,aktalignment.paraalign));
+           inlinecode.retoffset:=tg.gettempofsizepersistant(exprasmlist,Align(resulttype.def.size,aktalignment.paraalign));
          if ret_in_param(resulttype.def) then
            begin
               { This must not be counted for C code
@@ -515,12 +513,12 @@ implementation
 {$endif not OLD_C_STACK}
               if inlined then
                 begin
-                   getexplicitregister32(R_EDI);
+                   rg.getexplicitregisterint(exprasmlist,R_EDI);
                    emit_ref_reg(A_LEA,S_L,
                      newreference(funcretref),R_EDI);
                    r:=new_reference(procinfo^.framepointer,inlinecode.retoffset);
                    emit_reg_ref(A_MOV,S_L,R_EDI,r);
-                   ungetregister32(R_EDI);
+                   rg.ungetregisterint(exprasmlist,R_EDI);
                 end
               else
                 emitpushreferenceaddr(funcretref);
@@ -537,7 +535,7 @@ implementation
                    { dirty trick to avoid the secondcall below }
                    methodpointer:=ccallparanode.create(nil,nil);
                    methodpointer.location.loc:=LOC_REGISTER;
-                   getexplicitregister32(R_ESI);
+                   rg.getexplicitregisterint(exprasmlist,R_ESI);
                    methodpointer.location.register:=R_ESI;
                    { ARGHHH this is wrong !!!
                      if we can init from base class for a child
@@ -602,7 +600,7 @@ implementation
                                          { way to accept virtual static functions (PM)     }
                                          loadesi:=true;
                                          { if no VMT just use $0 bug0214 PM }
-                                         getexplicitregister32(R_ESI);
+                                         rg.getexplicitregisterint(exprasmlist,R_ESI);
                                          if not(oo_has_vmt in tobjectdef(methodpointer.resulttype.def).objectoptions) then
                                            emit_const_reg(A_MOV,S_L,0,R_ESI)
                                          else
@@ -661,7 +659,7 @@ implementation
                                  begin
                                     { extended syntax of new }
                                     { ESI must be zero }
-                                    getexplicitregister32(R_ESI);
+                                    rg.getexplicitregisterint(exprasmlist,R_ESI);
                                     emit_reg_reg(A_XOR,S_L,R_ESI,R_ESI);
                                     emit_reg(A_PUSH,S_L,R_ESI);
                                     { insert the vmt }
@@ -675,10 +673,10 @@ implementation
 
                                     { destructor with extended syntax called from dispose }
                                     { hdisposen always deliver LOC_REFERENCE          }
-                                    getexplicitregister32(R_ESI);
+                                    rg.getexplicitregisterint(exprasmlist,R_ESI);
                                     emit_ref_reg(A_LEA,S_L,
                                       newreference(methodpointer.location.reference),R_ESI);
-                                    del_reference(methodpointer.location.reference);
+                                    rg.del_reference(exprasmlist,methodpointer.location.reference);
                                     emit_reg(A_PUSH,S_L,R_ESI);
                                     emit_sym(A_PUSH,S_L,
                                       newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname));
@@ -689,13 +687,13 @@ implementation
                                     if (symtableproc.symtabletype<>withsymtable) then
                                       begin
                                          secondpass(methodpointer);
-                                         getexplicitregister32(R_ESI);
+                                         rg.getexplicitregisterint(exprasmlist,R_ESI);
                                          case methodpointer.location.loc of
                                             LOC_CREGISTER,
                                             LOC_REGISTER:
                                               begin
                                                  emit_reg_reg(A_MOV,S_L,methodpointer.location.register,R_ESI);
-                                                 ungetregister32(methodpointer.location.register);
+                                                 rg.ungetregisterint(exprasmlist,methodpointer.location.register);
                                               end;
                                             else
                                               begin
@@ -706,7 +704,7 @@ implementation
                                                  else
                                                    emit_ref_reg(A_LEA,S_L,
                                                      newreference(methodpointer.location.reference),R_ESI);
-                                                 del_reference(methodpointer.location.reference);
+                                                 rg.del_reference(exprasmlist,methodpointer.location.reference);
                                               end;
                                          end;
                                       end;
@@ -718,7 +716,7 @@ implementation
                                            not(methodpointer.resulttype.def.deftype=classrefdef) then
                                           begin
                                              { class method needs current VMT }
-                                             getexplicitregister32(R_ESI);
+                                             rg.getexplicitregisterint(exprasmlist,R_ESI);
                                              new(r);
                                              reset_reference(r^);
                                              r^.base:=R_ESI;
@@ -779,7 +777,7 @@ implementation
                           ) then
                           begin
                              { class method needs current VMT }
-                             getexplicitregister32(R_ESI);
+                             rg.getexplicitregisterint(exprasmlist,R_ESI);
                              new(r);
                              reset_reference(r^);
                              r^.base:=R_ESI;
@@ -841,14 +839,14 @@ implementation
                      new(r);
                      reset_reference(r^);
                      r^.base:=R_ESI;
-                     getexplicitregister32(R_EDI);
+                     rg.getexplicitregisterint(exprasmlist,R_EDI);
                      emit_ref_reg(A_MOV,S_L,r,R_EDI);
                      new(r);
                      reset_reference(r^);
                      r^.offset:=72;
                      r^.base:=R_EDI;
                      emit_ref(A_CALL,S_NO,r);
-                     ungetregister32(R_EDI);
+                     rg.ungetregisterint(exprasmlist,R_EDI);
                   end;
 
               { push base pointer ?}
@@ -885,7 +883,7 @@ implementation
                        end
                      else if (lexlevel>(tprocdef(procdefinition).parast.symtablelevel)) then
                        begin
-                          hregister:=getregisterint;
+                          hregister:=rg.getregisterint(exprasmlist);
                           new(r);
                           reset_reference(r^);
                           r^.offset:=procinfo^.framepointer_offset;
@@ -902,13 +900,13 @@ implementation
                                emit_ref_reg(A_MOV,S_L,r,hregister);
                             end;
                           emit_reg(A_PUSH,S_L,hregister);
-                          ungetregister32(hregister);
+                          rg.ungetregisterint(exprasmlist,hregister);
                        end
                      else
                        internalerror(25000);
                   end;
 
-              saveregvars(regs_to_push);
+              rg.saveregvars(exprasmlist,regs_to_push);
 
               if (po_virtualmethod in procdefinition.procoptions) and
                  not(no_virtual_call) then
@@ -917,7 +915,7 @@ implementation
                    { also class methods                       }
                    { Here it is quite tricky because it also depends }
                    { on the methodpointer                        PM }
-                   getexplicitregister32(R_ESI);
+                   rg.getexplicitregisterint(exprasmlist,R_ESI);
                    if assigned(aktprocdef) then
                      begin
                        if (((sp_static in aktprocdef.procsym.symoptions) or
@@ -945,7 +943,7 @@ implementation
                             r^.base:=R_ESI;
                             { this is one point where we need vmt_offset (PM) }
                             r^.offset:= tprocdef(procdefinition)._class.vmt_offset;
-                            getexplicitregister32(R_EDI);
+                            rg.getexplicitregisterint(exprasmlist,R_EDI);
                             emit_ref_reg(A_MOV,S_L,r,R_EDI);
                             new(r);
                             reset_reference(r^);
@@ -986,7 +984,7 @@ implementation
                           end;
                      end;
                    emit_ref(A_CALL,S_NO,r);
-                   ungetregister32(R_EDI);
+                   rg.ungetregisterint(exprasmlist,R_EDI);
                 end
               else if not inlined then
                 begin
@@ -1006,7 +1004,7 @@ implementation
                    secondpass(inlinecode);
                    { free the args }
                    if tprocdef(procdefinition).parast.datasize>0 then
-                     ungetpersistanttemp(tprocdef(procdefinition).parast.address_fixup);
+                     tg.ungetpersistanttemp(exprasmlist,tprocdef(procdefinition).parast.address_fixup);
                 end;
            end
          else
@@ -1030,8 +1028,8 @@ implementation
                    if (right.location.reference.base=R_ESI) or
                       (right.location.reference.index=R_ESI) then
                      begin
-                        del_reference(right.location.reference);
-                        getexplicitregister32(R_EDI);
+                        rg.del_reference(exprasmlist,right.location.reference);
+                        rg.getexplicitregisterint(exprasmlist,R_EDI);
                         emit_ref_reg(A_MOV,S_L,
                           newreference(right.location.reference),R_EDI);
                         hregister:=R_EDI;
@@ -1042,7 +1040,7 @@ implementation
                      begin
                        { load ESI }
                        inc(right.location.reference.offset,4);
-                       getexplicitregister32(R_ESI);
+                       rg.getexplicitregisterint(exprasmlist,R_ESI);
                        emit_ref_reg(A_MOV,S_L,
                          newreference(right.location.reference),R_ESI);
                        dec(right.location.reference.offset,4);
@@ -1050,30 +1048,30 @@ implementation
                        emit_reg(A_PUSH,S_L,R_ESI);
                      end;
 
-                   saveregvars($ff);
+                   rg.saveregvars(exprasmlist,ALL_REGISTERS);
                    if hregister=R_NO then
                      emit_ref(A_CALL,S_NO,newreference(right.location.reference))
                    else
                      begin
                        emit_reg(A_CALL,S_NO,hregister);
-                       ungetregister32(hregister);
+                       rg.ungetregisterint(exprasmlist,hregister);
                      end;
 
-                   del_reference(right.location.reference);
+                   rg.del_reference(exprasmlist,right.location.reference);
                 end
               else
                 begin
-                   saveregvars($ff);
+                   rg.saveregvars(exprasmlist,ALL_REGISTERS);
                    case right.location.loc of
                       LOC_REGISTER,LOC_CREGISTER:
                          begin
                              emit_reg(A_CALL,S_NO,right.location.register);
-                             ungetregister32(right.location.register);
+                             rg.ungetregisterint(exprasmlist,right.location.register);
                          end
                       else
                          begin
                            emit_ref(A_CALL,S_NO,newreference(right.location.reference));
-                           del_reference(right.location.reference);
+                           rg.del_reference(exprasmlist,right.location.reference);
                          end;
                    end;
                 end;
@@ -1089,9 +1087,9 @@ implementation
                 { better than an add on all processors }
                 if pushedparasize=4 then
                   begin
-                    getexplicitregister32(R_EDI);
+                    rg.getexplicitregisterint(exprasmlist,R_EDI);
                     emit_reg(A_POP,S_L,R_EDI);
-                    ungetregister32(R_EDI);
+                    rg.ungetregisterint(exprasmlist,R_EDI);
                   end
                 { the pentium has two pipes and pop reg is pairable }
                 { but the registers must be different!        }
@@ -1100,9 +1098,9 @@ implementation
                   (aktoptprocessor=ClassP5) and
                   (procinfo^._class=nil) then
                     begin
-                       getexplicitregister32(R_EDI);
+                       rg.getexplicitregisterint(exprasmlist,R_EDI);
                        emit_reg(A_POP,S_L,R_EDI);
-                       ungetregister32(R_EDI);
+                       rg.ungetregisterint(exprasmlist,R_EDI);
                        exprasmList.concat(Tairegalloc.Alloc(R_ESI));
                        emit_reg(A_POP,S_L,R_ESI);
                        exprasmList.concat(Tairegalloc.DeAlloc(R_ESI));
@@ -1116,8 +1114,7 @@ implementation
 {$endif OPTALIGN}
       dont_call:
          pushedparasize:=oldpushedparasize;
-         unused:=unusedregisters;
-         usablereg32:=usablecount;
+         rg.restoreunusedstate(unusedstate);
 {$ifdef TEMPREGDEBUG}
          testregisters32;
 {$endif TEMPREGDEBUG}
@@ -1150,14 +1147,14 @@ implementation
               new(r);
               reset_reference(r^);
               r^.base:=R_ESI;
-              getexplicitregister32(R_EDI);
+              rg.getexplicitregisterint(exprasmlist,R_EDI);
               emit_ref_reg(A_MOV,S_L,r,R_EDI);
               new(r);
               reset_reference(r^);
               r^.offset:=68;
               r^.base:=R_EDI;
               emit_ref(A_CALL,S_NO,r);
-              ungetregister32(R_EDI);
+              rg.ungetregisterint(exprasmlist,R_EDI);
               exprasmList.concat(Tairegalloc.Alloc(R_EAX));
               emitlab(constructorfailed);
               emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
@@ -1197,7 +1194,8 @@ implementation
                         else
 {$endif test_dest_loc}
                           begin
-                             hregister:=getexplicitregister32(R_EAX);
+                             cg.a_reg_alloc(exprasmlist,R_EAX);
+                             hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                              emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
                              location.register:=hregister;
                           end;
@@ -1216,6 +1214,7 @@ implementation
                    if (resulttype.def.deftype in [orddef,enumdef]) then
                      begin
                         location.loc:=LOC_REGISTER;
+                        cg.a_reg_alloc(exprasmlist,R_EAX);
                         case resulttype.def.size of
                           4 :
                             begin
@@ -1225,7 +1224,7 @@ implementation
                                else
 {$endif test_dest_loc}
                                  begin
-                                    hregister:=getexplicitregister32(R_EAX);
+                                    hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                                     emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
                                     location.register:=hregister;
                                  end;
@@ -1238,7 +1237,7 @@ implementation
                                  else
 {$endif test_dest_loc}
                                    begin
-                                      hregister:=getexplicitregister32(R_EAX);
+                                      hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                                       emit_reg_reg(A_MOV,S_B,R_AL,reg32toreg8(hregister));
                                       location.register:=reg32toreg8(hregister);
                                    end;
@@ -1251,7 +1250,7 @@ implementation
                                else
 {$endif test_dest_loc}
                                  begin
-                                    hregister:=getexplicitregister32(R_EAX);
+                                    hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                                     emit_reg_reg(A_MOV,S_W,R_AX,reg32toreg16(hregister));
                                     location.register:=reg32toreg16(hregister);
                                  end;
@@ -1261,15 +1260,16 @@ implementation
 {$ifdef test_dest_loc}
 {$error Don't know what to do here}
 {$endif test_dest_loc}
-                                if R_EDX in unused then
+                                cg.a_reg_alloc(exprasmlist,R_EDX);
+                                if R_EDX in rg.unusedregsint then
                                   begin
-                                     hregister2:=getexplicitregister32(R_EDX);
-                                     hregister:=getexplicitregister32(R_EAX);
+                                     hregister2:=rg.getexplicitregisterint(exprasmlist,R_EDX);
+                                     hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                                   end
                                 else
                                   begin
-                                     hregister:=getexplicitregister32(R_EAX);
-                                     hregister2:=getexplicitregister32(R_EDX);
+                                     hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
+                                     hregister2:=rg.getexplicitregisterint(exprasmlist,R_EDX);
                                   end;
                                 emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
                                 emit_reg_reg(A_MOV,S_L,R_EDX,hregister2);
@@ -1283,13 +1283,16 @@ implementation
               else if (resulttype.def.deftype=floatdef) then
                 begin
                   location.loc:=LOC_FPU;
-                  inc(fpuvaroffset);
+                  location.register:=R_ST;
+                  inc(trgcpu(rg).fpuvaroffset);
                 end
               else if is_ansistring(resulttype.def) or
                 is_widestring(resulttype.def) then
                 begin
+                   cg.a_reg_alloc(exprasmlist,R_EAX);
                    emit_reg_ref(A_MOV,S_L,R_EAX,
                      newreference(refcountedtemp));
+                   cg.a_reg_dealloc(exprasmlist,R_EAX);
                    location.loc:=LOC_MEM;
                    location.reference:=refcountedtemp;
                 end
@@ -1302,7 +1305,8 @@ implementation
                    else
 {$endif test_dest_loc}
                     begin
-                       hregister:=getexplicitregister32(R_EAX);
+                       cg.a_reg_alloc(exprasmlist,R_EAX);
+                       hregister:=rg.getexplicitregisterint(exprasmlist,R_EAX);
                        emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
                        location.register:=hregister;
                     end;
@@ -1320,7 +1324,7 @@ implementation
            emit_const_reg(A_ADD,S_L,pop_size,R_ESP);
 
          { restore registers }
-         popusedregisters(pushed);
+         rg.restoreusedregisters(exprasmlist,pushed);
 
          { at last, restore instance pointer (SELF) }
          if loadesi then
@@ -1331,7 +1335,7 @@ implementation
               if assigned(pp.left) then
                 begin
                   if (pp.left.location.loc in [LOC_REFERENCE,LOC_MEM]) then
-                    ungetiftemp(pp.left.location.reference);
+                    tg.ungetiftemp(exprasmlist,pp.left.location.reference);
                 { process also all nodes of an array of const }
                   if pp.left.nodetype=arrayconstructorn then
                     begin
@@ -1341,7 +1345,7 @@ implementation
                          while assigned(hp) do
                           begin
                             if (tarrayconstructornode(tunarynode(hp).left).location.loc in [LOC_REFERENCE,LOC_MEM]) then
-                              ungetiftemp(tarrayconstructornode(hp).left.location.reference);
+                              tg.ungetiftemp(exprasmlist,tarrayconstructornode(hp).left.location.reference);
                             hp:=tbinarynode(hp).right;
                           end;
                        end;
@@ -1351,7 +1355,7 @@ implementation
            end;
          if inlined then
            begin
-             ungetpersistanttemp(inlinecode.retoffset);
+             tg.ungetpersistanttemp(exprasmlist,inlinecode.retoffset);
              tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
              right:=inlinecode;
            end;
@@ -1360,7 +1364,7 @@ implementation
 
          { from now on the result can be freed normally }
          if inlined and ret_in_param(resulttype.def) then
-           persistanttemptonormal(funcretref.offset);
+           tg.persistanttemptonormal(funcretref.offset);
 
          { if return value is not used }
          if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
@@ -1371,14 +1375,14 @@ implementation
                    if (resulttype.def.needs_inittable) then
                       finalize(resulttype.def,location.reference,false);
                    { release unused temp }
-                   ungetiftemp(location.reference)
+                   tg.ungetiftemp(exprasmlist,location.reference)
                 end
               else if location.loc=LOC_FPU then
                 begin
                   { release FPU stack }
-                  emit_reg(A_FSTP,S_NO,R_ST0);
+                  emit_reg(A_FSTP,S_NO,R_ST);
                   {
-                    dec(fpuvaroffset);
+                    dec(trgcpu(rg).fpuvaroffset);
                     do NOT decrement as the increment before
                     is not called for unused results PM }
                 end;
@@ -1402,15 +1406,7 @@ implementation
            nostackframe,make_global : boolean;
            inlineentrycode,inlineexitcode : TAAsmoutput;
            oldexitlabel,oldexit2label,oldquickexitlabel:tasmlabel;
-           oldunused,oldusableregs : tregisterset;
-           oldc_usableregs : longint;
-           oldreg_pushes : regvar_longintarray;
-           oldregvar_loaded,
-           oldis_reg_var       : regvar_booleanarray;
-{$ifdef TEMPREGDEBUG}
-           oldreg_user   : regvar_ptreearray;
-           oldreg_releaser : regvar_ptreearray;
-{$endif TEMPREGDEBUG}
+           oldregstate: pointer;
 {$ifdef GDB}
            startlabel,endlabel : tasmlabel;
            pp : pchar;
@@ -1424,35 +1420,24 @@ implementation
                 for i := 1 to maxvarregs do
                   if assigned(regvars[i]) then
                     store_regvar(exprasmlist,regvars[i].reg);
-              oldunused := unused;
-              oldusableregs := usableregs;
-              oldc_usableregs := c_usableregs;
-              oldreg_pushes := reg_pushes;
-              oldis_reg_var := is_reg_var;
-              oldregvar_loaded := regvar_loaded;
-{$ifdef TEMPREGDEBUG}
-              oldreg_user := reg_user;
-              oldreg_releaser := reg_releaser;
-{$endif TEMPREGDEBUG}
+              rg.saveStateForInline(oldregstate);
               { make sure the register allocator knows what the regvars in the }
               { inlined code block are (JM)                                    }
-              resetusableregisters;
-              clearregistercount;
-              cleartempgen;
+              rg.resetusableregisters;
+              rg.clearregistercount;
+              rg.cleartempgen;
               if assigned(inlineprocdef.regvarinfo) then
                 with pregvarinfo(inlineprocdef.regvarinfo)^ do
-                 for i := 1 to maxvarregs do
-                  if assigned(regvars[i]) then
-                    begin
-                      case regsize(regvars[i].reg) of
-                        S_B: tmpreg := reg8toreg32(regvars[i].reg);
-                        S_W: tmpreg := reg16toreg32(regvars[i].reg);
-                        S_L: tmpreg := regvars[i].reg;
+                  for i := 1 to maxvarregs do
+                    if assigned(regvars[i]) then
+                      begin
+                        case regsize(regvars[i].reg) of
+                          S_B: tmpreg := reg8toreg32(regvars[i].reg);
+                          S_W: tmpreg := reg16toreg32(regvars[i].reg);
+                          S_L: tmpreg := regvars[i].reg;
+                        end;
+                        rg.makeregvar(tmpreg);
                       end;
-                      usableregs:=usableregs-[tmpreg];
-                      is_reg_var[tmpreg]:=true;
-                      dec(c_usableregs);
-                    end;
             end;
           oldinlining_procedure:=inlining_procedure;
           oldexitlabel:=aktexitlabel;
@@ -1477,7 +1462,7 @@ implementation
           st.symtablelevel:=oldprocdef.localst.symtablelevel;
           if st.datasize>0 then
             begin
-              st.address_fixup:=gettempofsizepersistant(st.datasize)+st.datasize;
+              st.address_fixup:=tg.gettempofsizepersistant(exprasmlist,st.datasize)+st.datasize;
 {$ifdef extdebug}
               Comment(V_debug,'local symtable is at offset '+tostr(st.address_fixup));
               exprasmList.concat(Tai_asm_comment.Create(strpnew(
@@ -1540,7 +1525,7 @@ implementation
           {we can free the local data now, reset also the fixup address }
           if st.datasize>0 then
             begin
-              ungetpersistanttemp(st.address_fixup-st.datasize);
+              tg.ungetpersistanttemp(exprasmlist,st.address_fixup-st.datasize);
               st.address_fixup:=0;
             end;
           { restore procinfo }
@@ -1572,16 +1557,7 @@ implementation
           { procedure (JM)                                                     }
           if assigned(aktprocdef.regvarinfo) then
             begin
-              unused := oldunused;
-              usableregs := oldusableregs;
-              c_usableregs := oldc_usableregs;
-              reg_pushes := oldreg_pushes;
-              is_reg_var := oldis_reg_var;
-              regvar_loaded := oldregvar_loaded;
-{$ifdef TEMPREGDEBUG}
-              reg_user := oldreg_user;
-              reg_releaser := oldreg_releaser;
-{$endif TEMPREGDEBUG}
+              rg.restoreStateAfterInline(oldregstate);
             end;
        end;
 
@@ -1593,7 +1569,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.41  2002-03-04 19:10:13  peter
+  Revision 1.42  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.41  2002/03/04 19:10:13  peter
     * removed compiler warnings
 
   Revision 1.40  2001/12/31 09:53:15  jonas

+ 48 - 26
compiler/i386/n386cnv.pas

@@ -60,10 +60,10 @@ implementation
    uses
       verbose,systems,
       symconst,symdef,aasm,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       ncon,ncal,
       cpubase,
-      cgobj,cga,tgcpu,n386util;
+      cgobj,cga,tgobj,rgobj,rgcpu,n386util;
 
 
 {*****************************************************************************
@@ -95,7 +95,7 @@ implementation
                end;
                { we can release the upper register }
                if is_64bitint(left.resulttype.def) then
-                 ungetregister32(left.location.registerhigh);
+                 rg.ungetregisterint(exprasmlist,left.location.registerhigh);
              end;
           end
 
@@ -105,9 +105,9 @@ implementation
             { remove reference }
             if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
               begin
-                del_reference(left.location.reference);
+                rg.del_reference(exprasmlist,left.location.reference);
                 { we can do this here as we need no temp inside }
-                ungetiftemp(left.location.reference);
+                tg.ungetiftemp(exprasmlist,left.location.reference);
               end;
 
             { get op and opsize, handle separate for constants, because
@@ -133,7 +133,7 @@ implementation
              end;
             { load the register we need }
             if left.location.loc<>LOC_REGISTER then
-              hregister:=getregisterint
+              hregister:=rg.getregisterint(exprasmlist)
             else
               hregister:=left.location.register;
 
@@ -144,7 +144,7 @@ implementation
             { do we need a second register for a 64 bit type ? }
             if is_64bitint(resulttype.def) then
               begin
-                 hregister2:=getregisterint;
+                 hregister2:=rg.getregisterint(exprasmlist);
                  location.registerhigh:=hregister2;
               end;
             case resulttype.def.size of
@@ -205,7 +205,7 @@ implementation
             (left.location.loc=LOC_CREGISTER) then
            begin
               if not (torddef(left.resulttype.def).typ in [u32bit,s32bit,u64bit,s64bit]) then
-                getexplicitregister32(R_EDI);
+                rg.getexplicitregisterint(exprasmlist,R_EDI);
               case torddef(left.resulttype.def).typ of
                  s8bit : emit_reg_reg(A_MOVSX,S_BL,left.location.register,R_EDI);
                  u8bit : emit_reg_reg(A_MOVZX,S_BL,left.location.register,R_EDI);
@@ -219,12 +219,12 @@ implementation
                       hregister:=left.location.registerlow;
                    end;
               end;
-              ungetregister(left.location.register);
+              rg.ungetregister(exprasmlist,left.location.register);
            end
          else
            begin
               r:=newreference(left.location.reference);
-              getexplicitregister32(R_EDI);
+              rg.getexplicitregisterint(exprasmlist,R_EDI);
               case torddef(left.resulttype.def).typ of
                  s8bit:
                    emit_ref_reg(A_MOVSX,S_BL,r,R_EDI);
@@ -245,13 +245,13 @@ implementation
                       emit_ref_reg(A_MOV,S_L,r,R_EDI);
                    end;
               end;
-              del_reference(left.location.reference);
-              ungetiftemp(left.location.reference);
+              rg.del_reference(exprasmlist,left.location.reference);
+              tg.ungetiftemp(exprasmlist,left.location.reference);
            end;
          { for 64 bit integers, the high dword is already pushed }
          emit_reg(A_PUSH,S_L,hregister);
          if hregister = R_EDI then
-           ungetregister32(R_EDI);
+           rg.ungetregisterint(exprasmlist,R_EDI);
          r:=new_reference(R_ESP,0);
          case torddef(left.resulttype.def).typ of
            u32bit:
@@ -271,12 +271,12 @@ implementation
                 { if it is 1 then we add $80000000 000000000 }
                 { as double                                  }
                 inc(r^.offset,4);
-                getexplicitregister32(R_EDI);
+                rg.getexplicitregisterint(exprasmlist,R_EDI);
                 emit_ref_reg(A_MOV,S_L,r,R_EDI);
                 r:=new_reference(R_ESP,4);
                 emit_const_ref(A_AND,S_L,$7fffffff,r);
                 emit_const_reg(A_TEST,S_L,longint($80000000),R_EDI);
-                ungetregister32(R_EDI);
+                rg.ungetregisterint(exprasmlist,R_EDI);
                 r:=new_reference(R_ESP,0);
                 emit_ref(A_FILD,S_IQ,r);
                 getdatalabel(l1);
@@ -295,14 +295,15 @@ implementation
            else
              begin
                 emit_ref(A_FILD,S_IL,r);
-                getexplicitregister32(R_EDI);
+                rg.getexplicitregisterint(exprasmlist,R_EDI);
                 emit_reg(A_POP,S_L,R_EDI);
-                ungetregister32(R_EDI);
+                rg.ungetregisterint(exprasmlist,R_EDI);
              end;
          end;
-         inc(fpuvaroffset);
+         inc(trgcpu(rg).fpuvaroffset);
          clear_location(location);
          location.loc:=LOC_FPU;
+         location.register:=R_ST;
       end;
 
 
@@ -324,14 +325,14 @@ implementation
               exit;
            end;
          location.loc:=LOC_REGISTER;
-         del_location(left.location);
+         rg.del_location(exprasmlist,left.location);
          opsize:=def_opsize(left.resulttype.def);
          case left.location.loc of
             LOC_MEM,LOC_REFERENCE :
               begin
                 if is_64bitint(left.resulttype.def) then
                  begin
-                   hregister:=getregisterint;
+                   hregister:=rg.getregisterint(exprasmlist);
                    emit_ref_reg(A_MOV,opsize,
                      newreference(left.location.reference),hregister);
                    pref:=newreference(left.location.reference);
@@ -350,7 +351,7 @@ implementation
               end;
             LOC_FLAGS :
               begin
-                hregister:=getregisterint;
+                hregister:=rg.getregisterint(exprasmlist);
                 resflags:=left.location.resflags;
               end;
             LOC_REGISTER,LOC_CREGISTER :
@@ -463,23 +464,23 @@ implementation
                            r^.base:=p^.location.register
                           else
                             begin
-                               getexplicitregister32(R_EDI);
+                               rg.getexplicitregisterint(exprasmlist,R_EDI);
                                emit_mov_loc_reg(p^.location,R_EDI);
                                r^.base:=R_EDI;
                             end;
                           { NIL must be accepted !! }
                           emit_reg_reg(A_OR,S_L,r^.base,r^.base);
-                          ungetregister32(R_EDI);
+                          rg.ungetregisterint(exprasmlist,R_EDI);
                           getlabel(nillabel);
                           emitjmp(C_E,nillabel);
                           { this is one point where we need vmt_offset (PM) }
                           r^.offset:= tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_offset;
-                          getexplicitregister32(R_EDI);
+                          rg.getexplicitregisterint(exprasmlist,R_EDI);
                           emit_ref_reg(A_MOV,S_L,r,R_EDI);
                           emit_sym(A_PUSH,S_L,
                             newasmsymbol(tobjectdef(tpointerdef(p^.resulttype.def).definition).vmt_mangledname));
                           emit_reg(A_PUSH,S_L,R_EDI);
-                          ungetregister32(R_EDI);
+                          rg.ungetregister32(exprasmlist,R_EDI);
                           emitcall('FPC_CHECK_OBJECT_EXT');
                           emitlab(nillabel);
                        end;
@@ -492,7 +493,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.30  2002-03-04 19:10:13  peter
+  Revision 1.31  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.30  2002/03/04 19:10:13  peter
     * removed compiler warnings
 
   Revision 1.29  2001/12/30 17:24:46  jonas
@@ -541,7 +559,11 @@ end.
   Revision 1.21  2001/08/28 13:24:47  jonas
     + compilerproc implementation of most string-related type conversions
     - removed all code from the compiler which has been replaced by
+<<<<<<< n386cnv.pas
+      compilerproc implementations (using "$ifdef hascompilerproc" is not
+=======
       compilerproc implementations (using $ifdef hascompilerproc is not
+>>>>>>> 1.30
       necessary in the compiler)
 
   Revision 1.20  2001/08/26 13:36:57  florian

+ 21 - 6
compiler/i386/n386con.pas

@@ -39,9 +39,8 @@ implementation
 
     uses
       systems,
-      temp_gen,
       cpubase,
-      cga,tgcpu;
+      cga,rgobj,rgcpu;
 
 {*****************************************************************************
                            TI386REALCONSTNODE
@@ -66,13 +65,15 @@ implementation
            begin
               emit_none(A_FLD1,S_NO);
               location.loc:=LOC_FPU;
-              inc(fpuvaroffset);
+              location.register:=R_ST;
+              inc(trgcpu(rg).fpuvaroffset);
            end
          else if (value_real=0.0) then
            begin
               emit_none(A_FLDZ,S_NO);
               location.loc:=LOC_FPU;
-              inc(fpuvaroffset);
+              location.register:=R_ST;
+              inc(trgcpu(rg).fpuvaroffset);
            end
          else
            inherited pass_2;
@@ -84,8 +85,22 @@ begin
 end.
 {
   $Log$
-  Revision 1.11  2001-09-30 16:17:17  jonas
-    * made most constant and mem handling processor independent
+  Revision 1.12  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
 
   Revision 1.10  2001/08/26 13:36:57  florian
     * some cg reorganisation

+ 41 - 24
compiler/i386/n386flw.pas

@@ -56,10 +56,10 @@ implementation
     uses
       verbose,systems,
       symsym,aasm,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       cpubase,cpuasm,
       nld,ncon,
-      tainst,cga,tgcpu;
+      tainst,cga,tgobj,rgobj;
 
 {*****************************************************************************
                              SecondRaise
@@ -176,7 +176,7 @@ implementation
          oldendexceptlabel:=endexceptlabel;
 
          { we modify EAX }
-         usedinproc:=usedinproc or ($80 shr byte(R_EAX));
+         include(rg.usedinproc,R_EAX);
 
          { save the old labels for control flow statements }
          oldaktexitlabel:=aktexitlabel;
@@ -203,8 +203,8 @@ implementation
          getlabel(endexceptlabel);
          getlabel(lastonlabel);
 
-         gettempofsizereferencepersistant(24,tempbuf);
-         gettempofsizereferencepersistant(12,tempaddr);
+         tg.gettempofsizereferencepersistant(exprasmlist,24,tempbuf);
+         tg.gettempofsizereferencepersistant(exprasmlist,12,tempaddr);
          emitpushreferenceaddr(tempaddr);
          emitpushreferenceaddr(tempbuf);
          push_int (1); { push type of exceptionframe }
@@ -238,8 +238,8 @@ implementation
 
          emitlab(exceptlabel);
          emitcall('FPC_POPADDRSTACK');
-         ungetpersistanttempreference(tempaddr);
-         ungetpersistanttempreference(tempbuf);
+         tg.ungetpersistanttempreference(exprasmlist,tempaddr);
+         tg.ungetpersistanttempreference(exprasmlist,tempbuf);
 
          exprasmList.concat(Tairegalloc.Alloc(R_EAX));
          emit_reg(A_POP,S_L,R_EAX);
@@ -280,8 +280,8 @@ implementation
               getlabel(doobjectdestroy);
               getlabel(doobjectdestroyandreraise);
 
-              gettempofsizereferencepersistant(12,tempaddr);
-              gettempofsizereferencepersistant(24,tempbuf);
+              tg.gettempofsizereferencepersistant(exprasmlist,12,tempaddr);
+              tg.gettempofsizereferencepersistant(exprasmlist,24,tempbuf);
               emitpushreferenceaddr(tempaddr);
               emitpushreferenceaddr(tempbuf);
               exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,1));
@@ -304,8 +304,8 @@ implementation
 
               emitlab(doobjectdestroyandreraise);
               emitcall('FPC_POPADDRSTACK');
-              ungetpersistanttempreference(tempaddr);
-              ungetpersistanttempreference(tempbuf);
+              tg.ungetpersistanttempreference(exprasmlist,tempaddr);
+              tg.ungetpersistanttempreference(exprasmlist,tempbuf);
 
               exprasmList.concat(Tairegalloc.Alloc(R_EAX));
               exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
@@ -434,7 +434,7 @@ implementation
          emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
          emitjmp(C_E,nextonlabel);
          ref.symbol:=nil;
-         gettempofsizereference(4,ref);
+         tg.gettempofsizereference(exprasmlist,4,ref);
 
          { what a hack ! }
          if assigned(exceptsymtable) then
@@ -449,8 +449,8 @@ implementation
          { we've to destroy the old one                }
          getlabel(doobjectdestroyandreraise);
 
-         gettempofsizereferencepersistant(12,tempaddr);
-         gettempofsizereferencepersistant(24,tempbuf);
+         tg.gettempofsizereferencepersistant(exprasmlist,12,tempaddr);
+         tg.gettempofsizereferencepersistant(exprasmlist,24,tempbuf);
          emitpushreferenceaddr(tempaddr);
          emitpushreferenceaddr(tempbuf);
          exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,1));
@@ -490,8 +490,8 @@ implementation
          getlabel(doobjectdestroy);
          emitlab(doobjectdestroyandreraise);
          emitcall('FPC_POPADDRSTACK');
-         ungetpersistanttempreference(tempaddr);
-         ungetpersistanttempreference(tempbuf);
+         tg.ungetpersistanttempreference(exprasmlist,tempaddr);
+         tg.ungetpersistanttempreference(exprasmlist,tempbuf);
 
          exprasmList.concat(Tairegalloc.Alloc(R_EAX));
          exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
@@ -510,7 +510,7 @@ implementation
          emitlab(doobjectdestroy);
          cleanupobjectstack;
          { clear some stuff }
-         ungetiftemp(ref);
+         tg.ungetiftemp(exprasmlist,ref);
          emitjmp(C_None,endexceptlabel);
 
          if assigned(right) then
@@ -551,7 +551,7 @@ implementation
          { next on node }
          if assigned(left) then
            begin
-              cleartempgen;
+              rg.cleartempgen;
               secondpass(left);
            end;
       end;
@@ -581,7 +581,7 @@ implementation
          oldflowcontrol:=flowcontrol;
          flowcontrol:=[];
          { we modify EAX }
-         usedinproc:=usedinproc or ($80 shr byte(R_EAX));
+         include(rg.usedinproc,R_EAX);
          getlabel(finallylabel);
          getlabel(endfinallylabel);
          getlabel(reraiselabel);
@@ -603,8 +603,8 @@ implementation
             aktbreaklabel:=breakfinallylabel;
           end;
 
-         gettempofsizereferencepersistant(12,tempaddr);
-         gettempofsizereferencepersistant(24,tempbuf);
+         tg.gettempofsizereferencepersistant(exprasmlist,12,tempaddr);
+         tg.gettempofsizereferencepersistant(exprasmlist,24,tempbuf);
          emitpushreferenceaddr(tempaddr);
          emitpushreferenceaddr(tempbuf);
          push_int(1); { Type of stack-frame must be pushed}
@@ -631,8 +631,8 @@ implementation
 
          emitlab(finallylabel);
          emitcall('FPC_POPADDRSTACK');
-         ungetpersistanttempreference(tempaddr);
-         ungetpersistanttempreference(tempbuf);
+         tg.ungetpersistanttempreference(exprasmlist,tempaddr);
+         tg.ungetpersistanttempreference(exprasmlist,tempbuf);
 
          { finally code }
          flowcontrol:=[];
@@ -737,7 +737,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.19  2001-12-29 15:29:58  jonas
+  Revision 1.20  2002-03-31 20:26:38  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.19  2001/12/29 15:29:58  jonas
     * powerpc/cgcpu.pas compiles :)
     * several powerpc-related fixes
     * cpuasm unit is now based on common tainst unit

+ 62 - 42
compiler/i386/n386inl.pas

@@ -40,10 +40,10 @@ implementation
       globtype,systems,
       cutils,verbose,globals,fmodule,
       symconst,symtype,symdef,aasm,types,
-      cgbase,temp_gen,pass_1,pass_2,
+      cgbase,pass_1,pass_2,
       cpubase,
       nbas,ncon,ncal,ncnv,nld,
-      cgobj,cga,tgcpu,n386util,ncgutil;
+      cga,tgobj,n386util,ncgutil,cgobj,rgobj,rgcpu;
 
 
 {*****************************************************************************
@@ -62,7 +62,7 @@ implementation
          opsize : topsize;
          op,
          asmop : tasmop;
-         pushed : tpushed;
+         pushed : tpushedsaved;
          {inc/dec}
          addconstant : boolean;
          addvalue : longint;
@@ -126,7 +126,7 @@ implementation
                  { for both cases load vmt }
                  if left.nodetype=typen then
                    begin
-                      location.register:=getregisterint;
+                      location.register:=rg.getregisterint(exprasmlist);
                       emit_sym_ofs_reg(A_MOV,
                         S_L,newasmsymbol(tobjectdef(left.resulttype.def).vmt_mangledname),0,
                         location.register);
@@ -134,9 +134,9 @@ implementation
                  else
                    begin
                       secondpass(left);
-                      del_reference(left.location.reference);
+                      rg.del_reference(exprasmlist,left.location.reference);
                       location.loc:=LOC_REGISTER;
-                      location.register:=getregisterint;
+                      location.register:=rg.getregisterint(exprasmlist);
                       { load VMT pointer }
                       inc(left.location.reference.offset,
                         tobjectdef(left.resulttype.def).vmt_offset);
@@ -164,8 +164,8 @@ implementation
                   begin
                     if left.location.loc<>LOC_REGISTER then
                      begin
-                       del_location(left.location);
-                       hregister:=getregisterint;
+                       rg.del_location(exprasmlist,left.location);
+                       hregister:=rg.getregisterint(exprasmlist);
                        emit_mov_loc_reg(left.location,hregister);
                      end
                     else
@@ -211,8 +211,8 @@ implementation
                         begin
                            if left.location.loc=LOC_CREGISTER then
                              begin
-                                location.registerlow:=getregisterint;
-                                location.registerhigh:=getregisterint;
+                                location.registerlow:=rg.getregisterint(exprasmlist);
+                                location.registerhigh:=rg.getregisterint(exprasmlist);
                                 emit_reg_reg(A_MOV,opsize,left.location.registerlow,
                                   location.registerlow);
                                 emit_reg_reg(A_MOV,opsize,left.location.registerhigh,
@@ -220,9 +220,9 @@ implementation
                              end
                            else
                              begin
-                                del_reference(left.location.reference);
-                                location.registerlow:=getregisterint;
-                                location.registerhigh:=getregisterint;
+                                rg.del_reference(exprasmlist,left.location.reference);
+                                location.registerlow:=rg.getregisterint(exprasmlist);
+                                location.registerhigh:=rg.getregisterint(exprasmlist);
                                 emit_ref_reg(A_MOV,opsize,newreference(left.location.reference),
                                   location.registerlow);
                                 r:=newreference(left.location.reference);
@@ -257,9 +257,9 @@ implementation
                         begin
                            { first, we've to release the source location ... }
                            if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
-                             del_reference(left.location.reference);
+                             rg.del_reference(exprasmlist,left.location.reference);
 
-                           location.register:=getregisterint;
+                           location.register:=rg.getregisterint(exprasmlist);
                            if (resulttype.def.size=2) then
                              location.register:=reg32toreg16(location.register);
                            if (resulttype.def.size=1) then
@@ -331,8 +331,8 @@ implementation
                   LOC_CREGISTER : hregister:=tcallparanode(tcallparanode(left).right).left.location.register;
                         LOC_MEM,
                   LOC_REFERENCE : begin
-                                    del_reference(tcallparanode(tcallparanode(left).right).left.location.reference);
-                                    hregister:=getregisterint;
+                                    rg.del_reference(exprasmlist,tcallparanode(tcallparanode(left).right).left.location.reference);
+                                    hregister:=rg.getregisterint(exprasmlist);
                                     emit_ref_reg(A_MOV,S_L,
                                       newreference(tcallparanode(tcallparanode(left).right).left.location.reference),hregister);
                                   end;
@@ -390,7 +390,7 @@ implementation
                       S_B : hregister:=reg8toreg32(hregister);
                       S_W : hregister:=reg16toreg32(hregister);
                     end;
-                   ungetregister32(hregister);
+                   rg.ungetregisterint(exprasmlist,hregister);
                  end;
                 emitoverflowcheck(tcallparanode(left).left);
                 cg.g_rangecheck(exprasmlist,tcallparanode(left).left,tcallparanode(left).left.resulttype.def);
@@ -398,7 +398,7 @@ implementation
 
             in_typeinfo_x:
                begin
-                  location.register:=getregisterint;
+                  location.register:=rg.getregisterint(exprasmlist);
                   new(r);
                   reset_reference(r^);
                   r^.symbol:=tstoreddef(ttypenode(tcallparanode(left).left).resulttype.def).get_rtti_label(fullrtti);
@@ -407,7 +407,7 @@ implementation
 
              in_finalize_x:
                begin
-                  pushusedregisters(pushed,$ff);
+                  rg.saveusedregisters(exprasmlist,pushed,all_registers);
                   { if a count is passed, push size, typeinfo and count }
                   if assigned(tcallparanode(left).right) then
                     begin
@@ -428,12 +428,12 @@ implementation
                   if codegenerror then
                     exit;
                   emitpushreferenceaddr(tcallparanode(left).left.location.reference);
-                  saveregvars($ff);
+                  rg.saveregvars(exprasmlist,all_registers);
                   if assigned(tcallparanode(left).right) then
                     emitcall('FPC_FINALIZEARRAY')
                   else
                     emitcall('FPC_FINALIZE');
-                  popusedregisters(pushed);
+                  rg.restoreusedregisters(exprasmlist,pushed);
                end;
 
             in_assigned_x :
@@ -445,19 +445,19 @@ implementation
                       emit_reg_reg(A_OR,S_L,
                         tcallparanode(left).left.location.register,
                         tcallparanode(left).left.location.register);
-                      ungetregister32(tcallparanode(left).left.location.register);
+                      rg.ungetregisterint(exprasmlist,tcallparanode(left).left.location.register);
                    end
                  else
                    begin
                       emit_const_ref(A_CMP,S_L,0,
                         newreference(tcallparanode(left).left.location.reference));
-                      del_reference(tcallparanode(left).left.location.reference);
+                      rg.del_reference(exprasmlist,tcallparanode(left).left.location.reference);
                    end;
                  location.resflags:=F_NE;
               end;
             in_setlength_x:
                begin
-                  pushusedregisters(pushed,$ff);
+                  rg.saveusedregisters(exprasmlist,pushed,all_registers);
                   l:=0;
                   { push dimensions }
                   hp:=left;
@@ -471,7 +471,7 @@ implementation
                   if is_dynamic_array(def) then
                     begin
                        { get temp. space }
-                       gettempofsizereference(l*4,hr);
+                       tg.gettempofsizereference(exprasmlist,l*4,hr);
                        { keep data start }
                        hr2:=hr;
                        { copy dimensions }
@@ -513,9 +513,9 @@ implementation
                        hr2.symbol:=tstoreddef(def).get_rtti_label(initrtti);
                        emitpushreferenceaddr(hr2);
                        emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
-                       saveregvars($ff);
+                       rg.saveregvars(exprasmlist,all_registers);
                        emitcall('FPC_DYNARR_SETLENGTH');
-                       ungetiftemp(hr);
+                       tg.ungetiftemp(exprasmlist,hr);
                     end
                   else
                     { must be string }
@@ -524,23 +524,23 @@ implementation
                           st_widestring:
                             begin
                               emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
-                              saveregvars($ff);
+                              rg.saveregvars(exprasmlist,all_registers);
                               emitcall('FPC_WIDESTR_SETLENGTH');
                             end;
                           st_ansistring:
                             begin
                               emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
-                              saveregvars($ff);
+                              rg.saveregvars(exprasmlist,all_registers);
                               emitcall('FPC_ANSISTR_SETLENGTH');
                             end;
                           st_shortstring:
                             begin
-                              saveregvars($ff);
+                              rg.saveregvars(exprasmlist,all_registers);
                               emitcall('FPC_SHORTSTR_SETLENGTH');
                             end;
                        end;
                     end;
-                  popusedregisters(pushed);
+                  rg.restoreusedregisters(exprasmlist,pushed);
                   maybe_loadself;
                end;
             in_include_x_y,
@@ -566,7 +566,7 @@ implementation
                              (tordconstnode(tcallparanode(tcallparanode(left).right).left).value div 32)*4);
                            emit_const_ref(asmop,S_L,
                              l,newreference(tcallparanode(left).left.location.reference));
-                           del_reference(tcallparanode(left).left.location.reference);
+                           rg.del_reference(exprasmlist,tcallparanode(left).left.location.reference);
                         end
                       else
                         { LOC_CREGISTER }
@@ -605,7 +605,7 @@ implementation
                         end
                       else
                         begin
-                           getexplicitregister32(R_EDI);
+                           rg.getexplicitregisterint(exprasmlist,R_EDI);
                            hregister:=R_EDI;
                            opsize:=def2def_opsize(
                              tcallparanode(tcallparanode(left).right).left.resulttype.def,u32bittype.def);
@@ -624,13 +624,14 @@ implementation
                         emit_reg_reg(asmop,S_L,hregister,
                           tcallparanode(left).left.location.register);
                       if hregister = R_EDI then
-                        ungetregister32(R_EDI);
+                        rg.ungetregisterint(exprasmlist,R_EDI);
                    end;
               end;
             in_pi:
               begin
                 emit_none(A_FLDPI,S_NO);
-                inc(fpuvaroffset);
+                inc(trgcpu(rg).fpuvaroffset);
+                location.register := R_ST;
               end;
             in_sin_extended,
             in_arctan_extended,
@@ -641,19 +642,21 @@ implementation
             in_cos_extended:
               begin
                  secondpass(left);
+                 location.register := R_ST;
                  case left.location.loc of
                     LOC_FPU:
                       ;
                     LOC_CFPUREGISTER:
                       begin
-                         emit_reg(A_FLD,S_NO,
-                           correct_fpuregister(left.location.register,fpuvaroffset));
-                         inc(fpuvaroffset);
+                         cg.a_loadfpu_reg_reg(exprasmlist,
+                           left.location.register,location.register);
                       end;
                     LOC_REFERENCE,LOC_MEM:
                       begin
-                         floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
-                         del_reference(left.location.reference);
+                         cg.a_loadfpu_ref_reg(exprasmlist,
+                           def_cgsize(left.resulttype.def),
+                           left.location.reference,location.register);
+                         rg.del_reference(exprasmlist,left.location.reference);
                       end
                     else
                       internalerror(309991);
@@ -729,7 +732,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.32  2002-03-04 19:10:14  peter
+  Revision 1.33  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.32  2002/03/04 19:10:14  peter
     * removed compiler warnings
 
   Revision 1.31  2001/12/30 17:24:46  jonas

+ 79 - 99
compiler/i386/n386ld.pas

@@ -52,10 +52,10 @@ implementation
       systems,
       verbose,globals,
       symconst,symtype,symdef,symsym,symtable,aasm,types,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       nmem,ncon,ncnv,
       cpubase,cpuasm,
-      cga,tgcpu,n386cnv,n386util,regvars;
+      cga,tgobj,n386cnv,n386util,regvars,cgobj,rgobj,rgcpu;
 
 {*****************************************************************************
                              SecondLoad
@@ -111,7 +111,7 @@ implementation
                     { DLL variable }
                     else if (vo_is_dll_var in tvarsym(symtableentry).varoptions) then
                       begin
-                         hregister:=getregisterint;
+                         hregister:=rg.getregisterint(exprasmlist);
                          location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
                          emit_ref_reg(A_MOV,S_L,newreference(location.reference),hregister);
                          location.reference.symbol:=nil;
@@ -125,7 +125,7 @@ implementation
                     { thread variable }
                     else if (vo_is_thread_var in tvarsym(symtableentry).varoptions) then
                       begin
-                         popeax:=not(R_EAX in unused);
+                         popeax:=not(R_EAX in rg.unusedregsint);
                          if popeax then
                            emit_reg(A_PUSH,S_L,R_EAX);
                          location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
@@ -135,7 +135,7 @@ implementation
                          emitcall('FPC_RELOCATE_THREADVAR');
 
                          reset_reference(location.reference);
-                         location.reference.base:=getregisterint;
+                         location.reference.base:=rg.getregisterint(exprasmlist);
                          emit_reg_reg(A_MOV,S_L,R_EAX,location.reference.base);
                          if popeax then
                            emit_reg(A_POP,S_L,R_EAX);
@@ -155,18 +155,18 @@ implementation
                                 end
                               else
                                 if not(makereg32(tvarsym(symtableentry).reg) in [R_EAX..R_EBX]) or
-                                   regvar_loaded[tvarsym(symtableentry).reg] then
+                                   rg.regvar_loaded[makereg32(tvarsym(symtableentry).reg)] then
                                 begin
                                    location.loc:=LOC_CREGISTER;
                                    location.register:=tvarsym(symtableentry).reg;
-                                   unused:=unused-[tvarsym(symtableentry).reg];
+                                   exclude(rg.unusedregsint,makereg32(tvarsym(symtableentry).reg));
                                 end
                               else
                                 begin
                                   load_regvar(exprasmlist,tvarsym(symtableentry));
                                   location.loc:=LOC_CREGISTER;
                                   location.register:=tvarsym(symtableentry).reg;
-                                  unused:=unused-[tvarsym(symtableentry).reg];
+                                  exclude(rg.unusedregsint,makereg32(tvarsym(symtableentry).reg));
                                 end
                            end
                          else
@@ -194,7 +194,7 @@ implementation
                                      end;
                                    if (lexlevel>(symtable.symtablelevel)) then
                                      begin
-                                        hregister:=getregisterint;
+                                        hregister:=rg.getregisterint(exprasmlist);
 
                                         { make a reference }
                                         hp:=new_reference(procinfo^.framepointer,
@@ -228,7 +228,7 @@ implementation
                                      end;
                                    objectsymtable:
                                      begin
-                                        getexplicitregister32(R_ESI);
+                                        rg.getexplicitregisterint(exprasmlist,R_ESI);
                                         if (sp_static in tvarsym(symtableentry).symoptions) then
                                           begin
                                              location.reference.symbol:=newasmsymbol(tvarsym(symtableentry).mangledname);
@@ -256,7 +256,7 @@ implementation
                                          end
                                         else
                                          begin
-                                           hregister:=getregisterint;
+                                           hregister:=rg.getregisterint(exprasmlist);
                                            location.reference.base:=hregister;
                                            emit_ref_reg(A_MOV,S_L,
                                              newreference(twithnode(twithsymtable(symtable).withnode).withreference^),
@@ -276,7 +276,7 @@ implementation
                            begin
                               simple_loadn:=false;
                               if hregister=R_NO then
-                                hregister:=getregisterint;
+                                hregister:=rg.getregisterint(exprasmlist);
                               if location.loc=LOC_CREGISTER then
                                 begin
                                    emit_reg_reg(A_MOV,S_L,
@@ -299,12 +299,12 @@ implementation
                     if assigned(left) then
                       begin
                          location.loc:=LOC_MEM;
-                         gettempofsizereference(8,location.reference);
+                         tg.gettempofsizereference(exprasmlist,8,location.reference);
                          if left.nodetype=typen then
                           begin
                             if left.resulttype.def.deftype<>objectdef then
                              internalerror(200103261);
-                            getexplicitregister32(R_EDI);
+                            rg.getexplicitregisterint(exprasmlist,R_EDI);
                             hregister:=R_EDI;
                             new(hp);
                             emit_sym_ofs_reg(A_MOV,S_L,
@@ -321,7 +321,7 @@ implementation
                                LOC_REGISTER:
                                  begin
                                     hregister:=left.location.register;
-                                    ungetregister32(left.location.register);
+                                    rg.ungetregisterint(exprasmlist,left.location.register);
                                     if is_object(left.resulttype.def) then
                                       CGMessage(cg_e_illegal_expression);
                                  end;
@@ -329,7 +329,7 @@ implementation
                                LOC_MEM,
                                LOC_REFERENCE:
                                  begin
-                                    getexplicitregister32(R_EDI);
+                                    rg.getexplicitregisterint(exprasmlist,R_EDI);
                                     hregister:=R_EDI;
                                     if is_class_or_interface(left.resulttype.def) then
                                       emit_ref_reg(A_MOV,S_L,
@@ -337,8 +337,8 @@ implementation
                                     else
                                       emit_ref_reg(A_LEA,S_L,
                                         newreference(left.location.reference),R_EDI);
-                                    del_reference(left.location.reference);
-                                    ungetiftemp(left.location.reference);
+                                    rg.del_reference(exprasmlist,left.location.reference);
+                                    tg.ungetiftemp(exprasmlist,left.location.reference);
                                  end;
                                else internalerror(26019);
                             end;
@@ -361,7 +361,7 @@ implementation
                               emit_ref_reg(A_MOV,S_L,
                                 hp,R_EDI);
 {$IfDef regallocfix}
-                              del_reference(hp^);
+                              rg.del_reference(exprasmlist,hp^);
 {$EndIf regallocfix}
                               { load method address }
                               new(hp);
@@ -374,11 +374,11 @@ implementation
                               { ... and store it }
                               emit_reg_ref(A_MOV,S_L,
                                 R_EDI,newreference(location.reference));
-                              ungetregister32(R_EDI);
+                              rg.ungetregisterint(exprasmlist,R_EDI);
                            end
                          else
                            begin
-                              ungetregister32(R_EDI);
+                              rg.ungetregisterint(exprasmlist,R_EDI);
                               s:=newasmsymbol(tprocdef(resulttype.def).mangledname);
                               emit_sym_ofs_ref(A_MOV,S_L,s,0,
                                 newreference(location.reference));
@@ -405,6 +405,7 @@ implementation
 
     procedure ti386assignmentnode.pass_2;
       var
+         regs_to_push: tregisterset;
          opsize : topsize;
          otlabel,hlabel,oflabel : tasmlabel;
          fputyp : tfloattype;
@@ -413,8 +414,7 @@ implementation
          ai : taicpu;
          op : tasmop;
          pushed : boolean;
-         regspushed : tpushed;
-         regs_to_push: byte;
+         regspushed : tpushedsaved;
          ungettemp : boolean;
 
       begin
@@ -492,39 +492,39 @@ implementation
                   { problems with the optimizer (JM)                            }
                   ungettemp:=false;
                   { Find out which registers have to be pushed (JM) }
-                  regs_to_push := $ff;
+                  regs_to_push := all_registers;
                   remove_non_regvars_from_loc(right.location,regs_to_push);
                   remove_non_regvars_from_loc(left.location,regs_to_push);
                   { And push them (JM) }
-                  pushusedregisters(regspushed,regs_to_push);
+                  rg.saveusedregisters(exprasmlist,regspushed,regs_to_push);
                   case right.location.loc of
                      LOC_REGISTER,LOC_CREGISTER:
                        begin
                           exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,right.location.register));
-                          ungetregister32(right.location.register);
+                          rg.ungetregisterint(exprasmlist,right.location.register);
                        end;
                      LOC_REFERENCE,LOC_MEM:
                        begin
                           { First release the registers because emit_push_mem may  }
                           { load the reference in edi before pushing and then the  }
                           { dealloc is too late (and optimizations are missed (JM) }
-                          del_reference(right.location.reference);
+                          rg.del_reference(exprasmlist,right.location.reference);
                           { This one doesn't need extra registers (JM) }
                           emit_push_mem(right.location.reference);
                           ungettemp:=true;
                        end;
                   end;
                   emitpushreferenceaddr(left.location.reference);
-                  del_reference(left.location.reference);
-                  saveregvars($ff);
+                  rg.del_reference(exprasmlist,left.location.reference);
+                  rg.saveregvars(exprasmlist,all_registers);
                   if is_ansistring(left.resulttype.def) then
                     emitcall('FPC_ANSISTR_ASSIGN')
                   else
                     emitcall('FPC_WIDESTR_ASSIGN');
                   maybe_loadself;
-                  popusedregisters(regspushed);
+                  rg.restoreusedregisters(exprasmlist,regspushed);
                   if ungettemp then
-                    ungetiftemp(right.location.reference);
+                    tg.ungetiftemp(exprasmlist,right.location.reference);
                 end
               else
               if is_shortstring(left.resulttype.def) and
@@ -537,7 +537,7 @@ implementation
                         begin
                           emit_const_ref(A_MOV,S_B,
                             0,newreference(left.location.reference));
-                          del_reference(left.location.reference);
+                          rg.del_reference(exprasmlist,left.location.reference);
                         end
                       else
                         loadansi2short(right,left);
@@ -545,11 +545,11 @@ implementation
                   else
                     begin
                        { we do not need destination anymore }
-                       del_reference(left.location.reference);
-                       {del_reference(right.location.reference);
+                       rg.del_reference(exprasmlist,left.location.reference);
+                       {rg.del_reference(exprasmlist,right.location.reference);
                         done in loadshortstring }
                        loadshortstring(right,left);
-                       ungetiftemp(right.location.reference);
+                       tg.ungetiftemp(exprasmlist,right.location.reference);
                     end;
                 end
               else if is_longstring(left.resulttype.def) then
@@ -559,7 +559,7 @@ implementation
               else
                 begin
                   { its the only thing we have to do }
-                  del_reference(right.location.reference);
+                  rg.del_reference(exprasmlist,right.location.reference);
                 end
            end
         else if is_interfacecom(left.resulttype.def) then
@@ -594,7 +594,7 @@ implementation
                                          left.location.registerhigh);
                                     end;
 {$IfDef regallocfix}
-                                  del_reference(right.location.reference);
+                                  rg.del_reference(exprasmlist,right.location.reference);
 {$EndIf regallocfix}
                                 end
                               else
@@ -616,7 +616,7 @@ implementation
                                          newreference(left.location.reference));
                                     end;
 {$IfDef regallocfix}
-                                  del_reference(left.location.reference);
+                                  rg.del_reference(exprasmlist,left.location.reference);
 {$EndIf regallocfix}
                                 {emit_const_loc(A_MOV,opsize,
                                     right.location.reference.offset,
@@ -626,11 +626,10 @@ implementation
                            end
                          else if loc=LOC_CFPUREGISTER then
                            begin
-                              floatloadops(tfloatdef(right.resulttype.def).typ,op,opsize);
-                              emit_ref(op,opsize,
-                                newreference(right.location.reference));
-                              emit_reg(A_FSTP,S_NO,
-                                correct_fpuregister(left.location.register,fpuvaroffset+1));
+                              cg.a_loadfpu_ref_reg(exprasmlist,
+                                def_cgsize(right.resulttype.def),
+                                right.location.reference,
+                                left.location.register);
                            end
                          else
                            begin
@@ -659,10 +658,10 @@ implementation
 
                               concatcopy(right.location.reference,
                                 left.location.reference,left.resulttype.def.size,true,false);
-                              del_reference(left.location.reference);
+                              rg.del_reference(exprasmlist,left.location.reference);
                               { done by concatcopy
-                              del_reference(right.location.reference);
-                              ungetiftemp(right.location.reference); }
+                              rg.del_reference(exprasmlist,right.location.reference);
+                              tg.ungetiftemp(exprasmlist,right.location.reference); }
                            end;
                       end;
 {$ifdef SUPPORT_MMX}
@@ -691,16 +690,16 @@ implementation
                                   emit_reg_reg(A_MOV,opsize,
                                     right.location.register,
                                     left.location.register);
-                                 ungetregister(right.location.register);
+                                 rg.ungetregister(exprasmlist,right.location.register);
                                 end
                               else
                                 Begin
                                   emit_reg_ref(A_MOV,opsize,
                                     right.location.register,
                                     newreference(left.location.reference));
-                                  ungetregister(right.location.register);
+                                  rg.ungetregister(exprasmlist,right.location.register);
 {$IfDef regallocfix}
-                                  del_reference(left.location.reference);
+                                  rg.del_reference(exprasmlist,left.location.reference);
 {$EndIf regallocfix}
                                 end;
                               if is_64bitint(right.resulttype.def) then
@@ -722,33 +721,9 @@ implementation
                                   right.location.register,
                                   left.location);      }
 
-                           end;
-            LOC_FPU : begin
-                              if (left.resulttype.def.deftype=floatdef) then
-                               fputyp:=tfloatdef(left.resulttype.def).typ
-                              else
-                               if (right.resulttype.def.deftype=floatdef) then
-                                fputyp:=tfloatdef(right.resulttype.def).typ
-                              else
-                               if (right.nodetype=typeconvn) and
-                                  (ttypeconvnode(right).left.resulttype.def.deftype=floatdef) then
-                                fputyp:=tfloatdef(ttypeconvnode(right).left.resulttype.def).typ
-                              else
-                                fputyp:=s32real;
-                              case loc of
-                                 LOC_CFPUREGISTER:
-                                   begin
-                                      emit_reg(A_FSTP,S_NO,
-                                        correct_fpuregister(left.location.register,fpuvaroffset));
-                                      dec(fpuvaroffset);
-                                   end;
-                                 LOC_REFERENCE:
-                                   floatstore(fputyp,left.location.reference);
-                                 else
-                                   internalerror(48991);
-                              end;
-                           end;
-            LOC_CFPUREGISTER: begin
+                            end;
+            LOC_FPU, LOC_CFPUREGISTER :
+                            begin
                               if (left.resulttype.def.deftype=floatdef) then
                                fputyp:=tfloatdef(left.resulttype.def).typ
                               else
@@ -760,21 +735,9 @@ implementation
                                 fputyp:=tfloatdef(ttypeconvnode(right).left.resulttype.def).typ
                               else
                                 fputyp:=s32real;
-                              emit_reg(A_FLD,S_NO,
-                                correct_fpuregister(right.location.register,fpuvaroffset));
-                              inc(fpuvaroffset);
-                              case loc of
-                                 LOC_CFPUREGISTER:
-                                   begin
-                                      emit_reg(A_FSTP,S_NO,
-                                        correct_fpuregister(right.location.register,fpuvaroffset));
-                                      dec(fpuvaroffset);
-                                   end;
-                                 LOC_REFERENCE:
-                                   floatstore(fputyp,left.location.reference);
-                                 else
-                                   internalerror(48992);
-                              end;
+                              cg.a_loadfpu_reg_loc(exprasmlist,
+                                tfloat2tcgsize[fputyp],
+                                right.location.register,left.location);
                            end;
             LOC_JUMP     : begin
                               opsize:=def_opsize(left.resulttype.def);
@@ -801,7 +764,7 @@ implementation
                                   emit_const_ref(A_MOV,opsize,
                                     0,newreference(left.location.reference));
 {$IfDef regallocfix}
-                                  del_reference(left.location.reference);
+                                  rg.del_reference(exprasmlist,left.location.reference);
 {$EndIf regallocfix}
                                  end;
                               emitlab(hlabel);
@@ -816,7 +779,7 @@ implementation
                                   exprasmList.concat(ai);
                                 end;
 {$IfDef regallocfix}
-                              del_reference(left.location.reference);
+                              rg.del_reference(exprasmlist,left.location.reference);
 {$EndIf regallocfix}
                            end;
          end;
@@ -842,7 +805,7 @@ implementation
          if (not inlining_procedure) and
             (lexlevel<>funcretsym.owner.symtablelevel) then
            begin
-              hr:=getregisterint;
+              hr:=rg.getregisterint(exprasmlist);
               hr_valid:=true;
               hp:=new_reference(procinfo^.framepointer,procinfo^.framepointer_offset);
               emit_ref_reg(A_MOV,S_L,hp,hr);
@@ -868,7 +831,7 @@ implementation
          if ret_in_param(resulttype.def) then
            begin
               if not hr_valid then
-                hr:=getregisterint;
+                hr:=rg.getregisterint(exprasmlist);
               emit_ref_reg(A_MOV,S_L,newreference(location.reference),hr);
               location.reference.base:=hr;
               location.reference.offset:=0;
@@ -922,9 +885,9 @@ implementation
            { Allocate always a temp, also if no elements are required, to
              be sure that location is valid (PFV) }
             if tarraydef(resulttype.def).highrange=-1 then
-              gettempofsizereference(elesize,location.reference)
+              tg.gettempofsizereference(exprasmlist,elesize,location.reference)
             else
-              gettempofsizereference((tarraydef(resulttype.def).highrange+1)*elesize,location.reference);
+              tg.gettempofsizereference(exprasmlist,(tarraydef(resulttype.def).highrange+1)*elesize,location.reference);
            href:=location.reference;
          end;
         hp:=self;
@@ -1018,7 +981,7 @@ implementation
                      begin
                        emit_to_mem(hp.left.location,hp.left.resulttype.def);
                        emit_push_lea_loc(hp.left.location,freetemp);
-                       del_reference(hp.left.location.reference);
+                       rg.del_reference(exprasmlist,hp.left.location.reference);
                      end
                     else
                      emit_push_loc(hp.left.location);
@@ -1091,7 +1054,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.29  2002-03-04 19:10:14  peter
+  Revision 1.30  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.29  2002/03/04 19:10:14  peter
     * removed compiler warnings
 
   Revision 1.28  2001/12/30 17:24:46  jonas

+ 120 - 104
compiler/i386/n386mat.pas

@@ -53,10 +53,10 @@ implementation
       globtype,systems,
       cutils,verbose,globals,
       symconst,symdef,aasm,types,
-      cgbase,temp_gen,pass_1,pass_2,
+      cgbase,pass_1,pass_2,
       ncon,
       cpubase,
-      cga,tgcpu,n386util,ncgutil;
+      cga,tgobj,n386util,ncgutil,cgobj,rgobj,rgcpu;
 
 {*****************************************************************************
                              TI386MODDIVNODE
@@ -90,13 +90,13 @@ implementation
                 begin
                    if left.location.loc=LOC_CREGISTER then
                      begin
-                       hreg1:=getregisterint;
+                       hreg1:=rg.getregisterint(exprasmlist);
                        emit_reg_reg(A_MOV,S_L,left.location.register,hreg1);
                      end
                    else
                      begin
-                       del_reference(left.location.reference);
-                       hreg1:=getregisterint;
+                       rg.del_reference(exprasmlist,left.location.reference);
+                       hreg1:=rg.getregisterint(exprasmlist);
                        emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
                          hreg1);
                      end;
@@ -122,14 +122,14 @@ implementation
                           begin
                           { no jumps, but more operations }
                             if (hreg1 = R_EAX) and
-                               (R_EDX in unused) then
+                               (R_EDX in rg.unusedregsint) then
                               begin
-                                hreg2 := getexplicitregister32(R_EDX);
+                                hreg2 := rg.getexplicitregisterint(exprasmlist,R_EDX);
                                 emit_none(A_CDQ,S_NO);
                               end
                             else
                               begin
-                                getexplicitregister32(R_EDI);
+                                rg.getexplicitregisterint(exprasmlist,R_EDI);
                                 hreg2 := R_EDI;
                                 emit_reg_reg(A_MOV,S_L,hreg1,R_EDI);
                               { if the left value is signed, R_EDI := $ffffffff,
@@ -142,7 +142,7 @@ implementation
                             emit_reg_reg(A_ADD,S_L,hreg2,hreg1);
                           { release EDX if we used it }
                           { also releas EDI }
-                          ungetregister32(hreg2);
+                          rg.ungetregisterint(exprasmlist,hreg2);
                           { do the shift }
                             emit_const_reg(A_SAR,S_L,power,hreg1);
                           end
@@ -169,50 +169,50 @@ implementation
                       { EDI is always free, it's }
                       { only used for temporary  }
                       { purposes              }
-                   getexplicitregister32(R_EDI);
+                   rg.getexplicitregisterint(exprasmlist,R_EDI);
                    if (right.location.loc<>LOC_REGISTER) and
                       (right.location.loc<>LOC_CREGISTER) then
                      begin
-                       del_reference(right.location.reference);
+                       rg.del_reference(exprasmlist,right.location.reference);
                        left.location.loc:=LOC_REGISTER;
                        emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),R_EDI);
                      end
                    else
                      begin
                         emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
-                        ungetregister32(right.location.register);
+                        rg.ungetregisterint(exprasmlist,right.location.register);
                      end;
                    popedx:=false;
                    popeax:=false;
                    if hreg1=R_EDX then
                      begin
-                       if not(R_EAX in unused) then
+                       if not(R_EAX in rg.unusedregsint) then
                           begin
                              emit_reg(A_PUSH,S_L,R_EAX);
                              popeax:=true;
                           end
                         else
-                          getexplicitregister32(R_EAX);
+                          rg.getexplicitregisterint(exprasmlist,R_EAX);
                        emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX);
                      end
                    else
                      begin
-                        if not(R_EDX in unused) then
+                        if not(R_EDX in rg.unusedregsint) then
                           begin
                              emit_reg(A_PUSH,S_L,R_EDX);
                              popedx:=true;
                           end
                         else
-                          getexplicitregister32(R_EDX);
+                          rg.getexplicitregisterint(exprasmlist,R_EDX);
                         if hreg1<>R_EAX then
                           begin
-                             if not(R_EAX in unused) then
+                             if not(R_EAX in rg.unusedregsint) then
                                begin
                                   emit_reg(A_PUSH,S_L,R_EAX);
                                   popeax:=true;
                                end
                              else
-                               getexplicitregister32(R_EAX);
+                               rg.getexplicitregisterint(exprasmlist,R_EAX);
                              emit_reg_reg(A_MOV,S_L,hreg1,R_EAX);
                           end;
                      end;
@@ -227,11 +227,11 @@ implementation
                      emit_reg(A_DIV,S_L,R_EDI)
                    else
                      emit_reg(A_IDIV,S_L,R_EDI);
-                   ungetregister32(R_EDI);
+                   rg.ungetregisterint(exprasmlist,R_EDI);
                    if nodetype=divn then
                      begin
                         if not popedx and (hreg1 <> R_EDX) then
-                          ungetregister(R_EDX);
+                          rg.ungetregister(exprasmlist,R_EDX);
                         { if result register is busy then copy }
                         if popeax then
                           begin
@@ -242,7 +242,7 @@ implementation
                         else
                           if hreg1<>R_EAX then
                             Begin
-                              ungetregister32(hreg1);
+                              rg.ungetregisterint(exprasmlist,hreg1);
                               { no need to allocate eax, that's already done before }
                               { the div (JM)                                        }
                               hreg1 := R_EAX;
@@ -251,7 +251,7 @@ implementation
                    else
                      begin
                        if not popeax and (hreg1 <> R_EAX)then
-                         ungetregister(R_EAX);
+                         rg.ungetregister(exprasmlist,R_EAX);
                        if popedx then
                         {the mod was done by an (i)div (so the result is now in
                          edx), but edx was occupied prior to the division, so
@@ -260,7 +260,7 @@ implementation
                        else
                          Begin
                            if hreg1 <> R_EDX then
-                             ungetregister32(hreg1);
+                             rg.ungetregisterint(exprasmlist,hreg1);
                            hreg1 := R_EDX
                          End;
                      end;
@@ -274,8 +274,8 @@ implementation
                { since it was acquired with getregister), the others also }
                { use both EAX and EDX (JM)                                }
                 Begin
-                  usedinproc:=usedinproc or ($80 shr byte(R_EAX));
-                  usedinproc:=usedinproc or ($80 shr byte(R_EDX));
+                  include(rg.usedinproc,R_EAX);
+                  include(rg.usedinproc,R_EDX);
                 End;
               clear_location(location);
               location.loc:=LOC_REGISTER;
@@ -318,8 +318,8 @@ implementation
                 begin
                    if left.location.loc=LOC_CREGISTER then
                      begin
-                        hregisterlow:=getregisterint;
-                        hregisterhigh:=getregisterint;
+                        hregisterlow:=rg.getregisterint(exprasmlist);
+                        hregisterhigh:=rg.getregisterint(exprasmlist);
                         emit_reg_reg(A_MOV,S_L,left.location.registerlow,
                           hregisterlow);
                         emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
@@ -327,9 +327,9 @@ implementation
                      end
                    else
                      begin
-                        del_reference(left.location.reference);
-                        hregisterlow:=getregisterint;
-                        hregisterhigh:=getregisterint;
+                        rg.del_reference(exprasmlist,left.location.reference);
+                        hregisterlow:=rg.getregisterint(exprasmlist);
+                        hregisterhigh:=rg.getregisterint(exprasmlist);
                         emit_mov_ref_reg64(left.location.reference,
                           hregisterlow,
                           hregisterhigh);
@@ -394,14 +394,14 @@ implementation
                      begin
                        if right.location.loc=LOC_CREGISTER then
                           begin
-                             hregister2:=getexplicitregister32(R_ECX);
+                             hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
                              emit_reg_reg(A_MOV,S_L,right.location.register,
                                hregister2);
                           end
                         else
                           begin
-                             del_reference(right.location.reference);
-                             hregister2:=getexplicitregister32(R_ECX);
+                             rg.del_reference(exprasmlist,right.location.reference);
+                             hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
                              emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),
                                hregister2);
                           end;
@@ -433,18 +433,18 @@ implementation
                    else if (hregister2<>R_ECX) then
                      begin
                         { ECX occupied then push it }
-                        if not (R_ECX in unused) then
+                        if not (R_ECX in rg.unusedregsint) then
                          begin
                            popecx:=true;
                            emit_reg(A_PUSH,S_L,R_ECX);
                          end
                         else
-                          getexplicitregister32(R_ECX);
+                          rg.getexplicitregisterint(exprasmlist,R_ECX);
                         emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
                      end;
 
                    if hregister2 <> R_ECX then
-                     ungetregister32(hregister2);
+                     rg.ungetregisterint(exprasmlist,hregister2);
 
                    { the damned shift instructions work only til a count of 32 }
                    { so we've to do some tricks here                           }
@@ -505,7 +505,7 @@ implementation
                    { maybe put ECX back }
                    if popecx then
                      emit_reg(A_POP,S_L,R_ECX)
-                   else ungetregister32(R_ECX);
+                   else rg.ungetregisterint(exprasmlist,R_ECX);
 
                    location.registerlow:=hregisterlow;
                    location.registerhigh:=hregisterhigh;
@@ -518,14 +518,14 @@ implementation
                 begin
                    if left.location.loc=LOC_CREGISTER then
                      begin
-                        hregister1:=getregisterint;
+                        hregister1:=rg.getregisterint(exprasmlist);
                         emit_reg_reg(A_MOV,S_L,left.location.register,
                           hregister1);
                      end
                    else
                      begin
-                        del_reference(left.location.reference);
-                        hregister1:=getregisterint;
+                        rg.del_reference(exprasmlist,left.location.reference);
+                        hregister1:=rg.getregisterint(exprasmlist);
                         emit_ref_reg(A_MOV,S_L,newreference(left.location.reference),
                           hregister1);
                      end;
@@ -556,14 +556,14 @@ implementation
                      begin
                        if right.location.loc=LOC_CREGISTER then
                           begin
-                             hregister2:=getexplicitregister32(R_ECX);
+                             hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
                              emit_reg_reg(A_MOV,S_L,right.location.register,
                                hregister2);
                           end
                         else
                           begin
-                             del_reference(right.location.reference);
-                             hregister2:=getexplicitregister32(R_ECX);
+                             rg.del_reference(exprasmlist,right.location.reference);
+                             hregister2:=rg.getexplicitregisterint(exprasmlist,R_ECX);
                              emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),
                                hregister2);
                           end;
@@ -586,23 +586,23 @@ implementation
                    else if (hregister2<>R_ECX) then
                      begin
                         { ECX occupied then push it }
-                        if not (R_ECX in unused) then
+                        if not (R_ECX in rg.unusedregsint) then
                          begin
                            popecx:=true;
                            emit_reg(A_PUSH,S_L,R_ECX);
                          end
                         else
-                          getexplicitregister32(R_ECX);
+                          rg.getexplicitregisterint(exprasmlist,R_ECX);
                         emit_reg_reg(A_MOV,S_L,hregister2,R_ECX);
                      end;
-                   ungetregister32(hregister2);
+                   rg.ungetregisterint(exprasmlist,hregister2);
                    { right operand is in ECX }
                    emit_reg_reg(op,S_L,R_CL,hregister1);
                    { maybe ECX back }
                    if popecx then
                      emit_reg(A_POP,S_L,R_ECX)
                    else
-                     ungetregister32(R_ECX);
+                     rg.ungetregisterint(exprasmlist,R_ECX);
                    location.register:=hregister1;
                 end;
            end;
@@ -704,16 +704,16 @@ implementation
                   end;
                 LOC_CREGISTER :
                   begin
-                     location.registerlow:=getregisterint;
-                     location.registerhigh:=getregisterint;
+                     location.registerlow:=rg.getregisterint(exprasmlist);
+                     location.registerhigh:=rg.getregisterint(exprasmlist);
                      emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow);
                      emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh);
                   end;
                 LOC_REFERENCE,LOC_MEM :
                   begin
-                     del_reference(left.location.reference);
-                     location.registerlow:=getregisterint;
-                     location.registerhigh:=getregisterint;
+                     rg.del_reference(exprasmlist,left.location.reference);
+                     location.registerlow:=rg.getregisterint(exprasmlist);
+                     location.registerhigh:=rg.getregisterint(exprasmlist);
                      emit_mov_ref_reg64(left.location.reference,
                        location.registerlow,
                        location.registerhigh);
@@ -740,7 +740,7 @@ implementation
                    end;
                  LOC_CREGISTER:
                    begin
-                      location.register:=getregisterint;
+                      location.register:=rg.getregisterint(exprasmlist);
                       emit_reg_reg(A_MOV,S_L,location.register,
                         location.register);
                       emit_reg(A_NEG,S_L,location.register);
@@ -754,7 +754,7 @@ implementation
                    end;
                  LOC_CMMXREGISTER:
                    begin
-                      location.register:=getregistermmx;
+                      location.register:=rg.getregistermm(exprasmlist);
                       emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
                       emit_reg_reg(A_MOVQ,S_NO,left.location.register,
                         location.register);
@@ -762,46 +762,45 @@ implementation
                    end;
 {$endif SUPPORT_MMX}
                  LOC_REFERENCE,LOC_MEM:
-                                begin
-                                   del_reference(left.location.reference);
-                                   if (left.resulttype.def.deftype=floatdef) then
-                                     begin
-                                        location.loc:=LOC_FPU;
-                                        floatload(tfloatdef(left.resulttype.def).typ,
-                                          left.location.reference);
-                                        emit_none(A_FCHS,S_NO);
-                                     end
+                   begin
+                      rg.del_reference(exprasmlist,left.location.reference);
+                      if (left.resulttype.def.deftype=floatdef) then
+                        begin
+                           location.loc:=LOC_FPU;
+                           location.register := R_ST;
+                           cg.a_loadfpu_ref_reg(exprasmlist,
+                             def_cgsize(left.resulttype.def),
+                             left.location.reference,
+                             R_ST);
+                           emit_none(A_FCHS,S_NO);
+                        end
 {$ifdef SUPPORT_MMX}
-                                   else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
-                                     begin
-                                        location.register:=getregistermmx;
-                                        emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
-                                        emit_ref_reg(A_MOVQ,S_NO,
-                                          newreference(left.location.reference),
-                                          location.register);
-                                        do_mmx_neg;
-                                     end
+                      else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then
+                        begin
+                           location.register:=rg.getregistermm(exprasmlist);
+                           emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7);
+                           emit_ref_reg(A_MOVQ,S_NO,
+                             newreference(left.location.reference),
+                             location.register);
+                           do_mmx_neg;
+                        end
 {$endif SUPPORT_MMX}
-                                   else
-                                     begin
-                                        location.register:=getregisterint;
-                                        emit_ref_reg(A_MOV,S_L,
-                                          newreference(left.location.reference),
-                                          location.register);
-                                        emit_reg(A_NEG,S_L,location.register);
-                                     end;
-                                end;
-                 LOC_FPU:
-                   begin
-                      location.loc:=LOC_FPU;
-                      emit_none(A_FCHS,S_NO);
+                      else
+                        begin
+                           location.register:=rg.getregisterint(exprasmlist);
+                           emit_ref_reg(A_MOV,S_L,
+                             newreference(left.location.reference),
+                             location.register);
+                           emit_reg(A_NEG,S_L,location.register);
+                        end;
                    end;
-                 LOC_CFPUREGISTER:
+                 LOC_FPU,LOC_CFPUREGISTER:
                    begin
-                      emit_reg(A_FLD,S_NO,
-                        correct_fpuregister(left.location.register,fpuvaroffset));
-                      inc(fpuvaroffset);
+                      { "load st,st" is ignored by the code generator }
+                      cg.a_loadfpu_reg_reg(exprasmlist,
+                        left.location.register,R_ST);
                       location.loc:=LOC_FPU;
+                      location.register := R_ST;
                       emit_none(A_FCHS,S_NO);
                    end;
               end;
@@ -858,20 +857,20 @@ implementation
                   location.resflags:=F_E;
                   emit_reg_reg(A_TEST,opsize,
                     left.location.register,left.location.register);
-                  ungetregister(left.location.register);
+                  rg.ungetregister(exprasmlist,left.location.register);
                 end;
               LOC_REFERENCE,
               LOC_MEM :
                 begin
                   clear_location(location);
                   location.loc:=LOC_REGISTER;
-                  del_reference(left.location.reference);
+                  rg.del_reference(exprasmlist,left.location.reference);
                   { this was placed before del_ref => internaalerror(10) }
                   location.register:=def_getreg(resulttype.def);
                   emit_ref_reg(A_MOV,opsize,
                     newreference(left.location.reference),location.register);
                   emit_reg_reg(A_TEST,opsize,location.register,location.register);
-                  ungetregister(location.register);
+                  rg.ungetregister(exprasmlist,location.register);
                   location.loc:=LOC_FLAGS;
                   location.resflags:=F_E;
                 end;
@@ -884,7 +883,7 @@ implementation
              secondpass(left);
              location.loc:=LOC_MMXREGISTER;
              { prepare EDI }
-             getexplicitregister32(R_EDI);
+             rg.getexplicitregisterint(exprasmlist,R_EDI);
              emit_const_reg(A_MOV,S_L,longint($ffffffff),R_EDI);
              { load operand }
              case left.location.loc of
@@ -892,20 +891,20 @@ implementation
                  set_location(location,left.location);
                LOC_CMMXREGISTER:
                  begin
-                   location.register:=getregistermmx;
+                   location.register:=rg.getregistermm(exprasmlist);
                    emit_reg_reg(A_MOVQ,S_NO,left.location.register,location.register);
                  end;
                LOC_REFERENCE,LOC_MEM:
                  begin
-                   del_reference(left.location.reference);
-                   location.register:=getregistermmx;
+                   rg.del_reference(exprasmlist,left.location.reference);
+                   location.register:=rg.getregistermm(exprasmlist);
                    emit_ref_reg(A_MOVQ,S_NO,
                      newreference(left.location.reference),location.register);
                  end;
              end;
              { load mask }
              emit_reg_reg(A_MOVD,S_NO,R_EDI,R_MM7);
-             ungetregister32(R_EDI);
+             rg.ungetregisterint(exprasmlist,R_EDI);
              { lower 32 bit }
              emit_reg_reg(A_PXOR,S_D,R_MM7,location.register);
              { shift mask }
@@ -929,8 +928,8 @@ implementation
                   end;
                 LOC_CREGISTER :
                   begin
-                     location.registerlow:=getregisterint;
-                     location.registerhigh:=getregisterint;
+                     location.registerlow:=rg.getregisterint(exprasmlist);
+                     location.registerhigh:=rg.getregisterint(exprasmlist);
                      emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow);
                      emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh);
                      emit_reg(A_NOT,S_L,location.registerlow);
@@ -938,9 +937,9 @@ implementation
                   end;
                 LOC_REFERENCE,LOC_MEM :
                   begin
-                     del_reference(left.location.reference);
-                     location.registerlow:=getregisterint;
-                     location.registerhigh:=getregisterint;
+                     rg.del_reference(exprasmlist,left.location.reference);
+                     location.registerlow:=rg.getregisterint(exprasmlist);
+                     location.registerhigh:=rg.getregisterint(exprasmlist);
                      emit_mov_ref_reg64(left.location.reference,
                        location.registerlow,
                        location.registerhigh);
@@ -969,7 +968,7 @@ implementation
                 end;
               LOC_REFERENCE,LOC_MEM :
                 begin
-                  del_reference(left.location.reference);
+                  rg.del_reference(exprasmlist,left.location.reference);
                   location.register:=def_getreg(resulttype.def);
                   emit_ref_reg(A_MOV,opsize,
                     newreference(left.location.reference),location.register);
@@ -988,7 +987,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.23  2002-03-04 19:10:14  peter
+  Revision 1.24  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.23  2002/03/04 19:10:14  peter
     * removed compiler warnings
 
   Revision 1.22  2001/12/30 17:24:47  jonas

+ 79 - 41
compiler/i386/n386mem.pas

@@ -59,10 +59,10 @@ implementation
       globtype,systems,
       cutils,verbose,globals,
       symconst,symtype,symdef,symsym,symtable,aasm,types,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       pass_1,nld,ncon,nadd,
       cpubase,cpuasm,
-      cgobj,cga,tgcpu,n386util;
+      cgobj,cga,tgobj,n386util,rgobj;
 
 {*****************************************************************************
                             TI386NEWNODE
@@ -70,7 +70,8 @@ implementation
 
     procedure ti386newnode.pass_2;
       var
-         pushed : tpushed;
+         pushed : tpushedsaved;
+         regstopush: tregisterset;
          r : preference;
       begin
          if assigned(left) then
@@ -80,14 +81,16 @@ implementation
            end
          else
            begin
-              pushusedregisters(pushed,$ff);
+              regstopush := all_registers;
+              remove_non_regvars_from_loc(location,regstopush);
+              rg.saveusedregisters(exprasmlist,pushed,regstopush);
 
-              gettempofsizereference(target_info.size_of_pointer,location.reference);
+              tg.gettempofsizereference(exprasmlist,target_info.size_of_pointer,location.reference);
 
               { determines the size of the mem block }
               push_int(tpointerdef(resulttype.def).pointertype.def.size);
               emit_push_lea_loc(location,false);
-              saveregvars($ff);
+              rg.saveregvars(exprasmlist,all_registers);
               emitcall('FPC_GETMEM');
 
               if tpointerdef(resulttype.def).pointertype.def.needs_inittable then
@@ -102,7 +105,7 @@ implementation
                    emit_push_loc(location);
                    emitcall('FPC_INITIALIZE');
                 end;
-              popusedregisters(pushed);
+              rg.restoreusedregisters(exprasmlist,pushed);
               { may be load ESI }
               maybe_loadself;
            end;
@@ -131,22 +134,29 @@ implementation
     procedure ti386simplenewdisposenode.pass_2;
 
       var
-         pushed : tpushed;
+         regstopush: tregisterset;
+         pushed : tpushedsaved;
          r : preference;
-
+         oldleft: tnode;
       begin
+         oldleft := nil;
+         if tpointerdef(left.resulttype.def).pointertype.def.needs_inittable then
+           { we need to secondpass left twice in this case -> get a copy }
+           oldleft := left.getcopy;
          secondpass(left);
          if codegenerror then
            exit;
 
-         pushusedregisters(pushed,$ff);
-         saveregvars($ff);
+         regstopush := all_registers;
+         remove_non_regvars_from_loc(left.location,regstopush);
+         rg.saveusedregisters(exprasmlist,pushed,regstopush);
+         rg.saveregvars(exprasmlist,all_registers);
 
          { call the mem handling procedures }
          case nodetype of
            simpledisposen:
              begin
-                if tpointerdef(left.resulttype.def).pointertype.def.needs_inittable then
+                if assigned(oldleft) then
                   begin
                      new(r);
                      reset_reference(r^);
@@ -155,9 +165,14 @@ implementation
                      dispose(r);
                      { push pointer adress }
                      emit_push_loc(left.location);
+                     rg.del_location(exprasmlist,left.location);
                      emitcall('FPC_FINALIZE');
+                     { reload registers for left!! }
+                     secondpass(oldleft);
+                     oldleft.free;
                   end;
                 emit_push_loc(left.location);
+                rg.del_location(exprasmlist,left.location);
                 emitcall('FPC_FREEMEM');
              end;
            simplenewn:
@@ -165,20 +180,26 @@ implementation
                 { determines the size of the mem block }
                 push_int(tpointerdef(left.resulttype.def).pointertype.def.size);
                 emit_push_lea_loc(left.location,true);
+                if not assigned(oldleft) then
+                  rg.del_location(exprasmlist,left.location);
                 emitcall('FPC_GETMEM');
-                if tpointerdef(left.resulttype.def).pointertype.def.needs_inittable then
+                if assigned(oldleft) then
                   begin
+                     { reload registers for left!! }
+                     secondpass(oldleft);
+                     oldleft.free;
                      new(r);
                      reset_reference(r^);
                      r^.symbol:=tstoreddef(tpointerdef(left.resulttype.def).pointertype.def).get_rtti_label(initrtti);
                      emitpushreferenceaddr(r^);
                      dispose(r);
                      emit_push_loc(left.location);
+                     rg.del_location(exprasmlist,left.location);
                      emitcall('FPC_INITIALIZE');
                   end;
              end;
          end;
-         popusedregisters(pushed);
+         rg.restoreusedregisters(exprasmlist,pushed);
          { may be load ESI }
          maybe_loadself;
       end;
@@ -256,7 +277,7 @@ implementation
          href : treference;
          tai : Taicpu;
          srsym : tsym;
-         pushed : tpushed;
+         pushed : tpushedsaved;
          hightree : tnode;
          hl,otl,ofl : tasmlabel;
       begin
@@ -275,15 +296,15 @@ implementation
                         CGMessage(cg_e_illegal_expression);
                         exit;
                      end;
-                   pushusedregisters(pushed,$ff);
+                   rg.saveusedregisters(exprasmlist,pushed,all_registers);
                    emitpushreferenceaddr(left.location.reference);
-                   saveregvars($ff);
+                   rg.saveregvars(exprasmlist,all_registers);
                    if is_ansistring(left.resulttype.def) then
                      emitcall('FPC_ANSISTR_UNIQUE')
                    else
                      emitcall('FPC_WIDESTR_UNIQUE');
                    maybe_loadself;
-                   popusedregisters(pushed);
+                   rg.restoreusedregisters(exprasmlist,pushed);
                 end;
 
               if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
@@ -292,8 +313,8 @@ implementation
                 end
               else
                 begin
-                   del_reference(left.location.reference);
-                   location.reference.base:=getregisterint;
+                   rg.del_reference(exprasmlist,left.location.reference);
+                   location.reference.base:=rg.getregisterint(exprasmlist);
                    emit_ref_reg(A_MOV,S_L,
                      newreference(left.location.reference),
                      location.reference.base);
@@ -303,12 +324,12 @@ implementation
                 we can use the ansistring routine here }
               if (cs_check_range in aktlocalswitches) then
                 begin
-                   pushusedregisters(pushed,$ff);
+                   rg.saveusedregisters(exprasmlist,pushed,all_registers);
                    emit_reg(A_PUSH,S_L,location.reference.base);
-                   saveregvars($ff);
+                   rg.saveregvars(exprasmlist,all_registers);
                    emitcall('FPC_ANSISTR_CHECKZERO');
                    maybe_loadself;
-                   popusedregisters(pushed);
+                   rg.restoreusedregisters(exprasmlist,pushed);
                 end;
 
               if is_ansistring(left.resulttype.def) then
@@ -337,8 +358,8 @@ implementation
                 end
               else
                 begin
-                   del_reference(left.location.reference);
-                   location.reference.base:=getregisterint;
+                   rg.del_reference(exprasmlist,left.location.reference);
+                   location.reference.base:=rg.getregisterint(exprasmlist);
                    emit_ref_reg(A_MOV,S_L,
                      newreference(left.location.reference),
                      location.reference.base);
@@ -348,12 +369,12 @@ implementation
                 we can use the ansistring routine here }
               if (cs_check_range in aktlocalswitches) then
                 begin
-                   pushusedregisters(pushed,$ff);
+                   rg.saveusedregisters(exprasmlist,pushed,all_registers);
                    emit_reg(A_PUSH,S_L,location.reference.base);
-                   saveregvars($ff);
+                   rg.saveregvars(exprasmlist,all_registers);
                    emitcall('FPC_ANSISTR_CHECKZERO');
                    maybe_loadself;
-                   popusedregisters(pushed);
+                   rg.restoreusedregisters(exprasmlist,pushed);
                 end;
 
               { we've also to keep left up-to-date, because it is used   }
@@ -406,14 +427,14 @@ implementation
                         st_widestring,
                         st_ansistring:
                           begin
-                             pushusedregisters(pushed,$ff);
+                             rg.saveusedregisters(exprasmlist,pushed,all_registers);
                              push_int(tordconstnode(right).value);
                              hp:=newreference(location.reference);
                              dec(hp^.offset,7);
                              emit_ref(A_PUSH,S_L,hp);
-                             saveregvars($ff);
+                             rg.saveregvars(exprasmlist,all_registers);
                              emitcall('FPC_ANSISTR_RANGECHECK');
-                             popusedregisters(pushed);
+                             rg.restoreusedregisters(exprasmlist,pushed);
                              maybe_loadself;
                           end;
 
@@ -569,7 +590,7 @@ implementation
                    end;
                  LOC_CREGISTER:
                    begin
-                      ind:=getregisterint;
+                      ind:=rg.getregisterint(exprasmlist);
                       case right.resulttype.def.size of
                          1:
                            emit_reg_reg(A_MOVZX,S_BL,right.location.register,ind);
@@ -581,13 +602,13 @@ implementation
                    end;
                  LOC_FLAGS:
                    begin
-                      ind:=getregisterint;
+                      ind:=rg.getregisterint(exprasmlist);
                       emit_flag2reg(right.location.resflags,reg32toreg8(ind));
                       emit_reg_reg(A_MOVZX,S_BL,reg32toreg8(ind),ind);
                    end;
                  LOC_JUMP :
                    begin
-                     ind:=getregisterint;
+                     ind:=rg.getregisterint(exprasmlist);
                      emitlab(truelabel);
                      truelabel:=otl;
                      emit_const_reg(A_MOV,S_L,1,ind);
@@ -600,8 +621,8 @@ implementation
                    end;
                  LOC_REFERENCE,LOC_MEM :
                    begin
-                      del_reference(right.location.reference);
-                      ind:=getregisterint;
+                      rg.del_reference(exprasmlist,right.location.reference);
+                      ind:=rg.getregisterint(exprasmlist);
                       { Booleans are stored in an 8 bit memory location, so
                         the use of MOVL is not correct }
                       case right.resulttype.def.size of
@@ -629,14 +650,14 @@ implementation
                          st_widestring,
                          st_ansistring:
                            begin
-                              pushusedregisters(pushed,$ff);
+                              rg.saveusedregisters(exprasmlist,pushed,all_registers);
                               emit_reg(A_PUSH,S_L,ind);
                               hp:=newreference(location.reference);
                               dec(hp^.offset,7);
                               emit_ref(A_PUSH,S_L,hp);
-                              saveregvars($ff);
+                              rg.saveregvars(exprasmlist,all_registers);
                               emitcall('FPC_ANSISTR_RANGECHECK');
-                              popusedregisters(pushed);
+                              rg.restoreusedregisters(exprasmlist,pushed);
                               maybe_loadself;
                            end;
                          st_shortstring:
@@ -674,7 +695,7 @@ implementation
                     emit_ref_reg(
                       A_LEA,S_L,newreference(location.reference),
                       location.reference.index);
-                    ungetregister32(location.reference.base);
+                    rg.ungetregisterint(exprasmlist,location.reference.base);
                     { the symbol offset is loaded,             }
                     { so release the symbol name and set symbol  }
                     { to nil                                 }
@@ -701,7 +722,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.20  2002-03-04 19:10:14  peter
+  Revision 1.21  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.20  2002/03/04 19:10:14  peter
     * removed compiler warnings
 
   Revision 1.19  2001/12/30 17:24:47  jonas

+ 19 - 3
compiler/i386/n386obj.pas

@@ -36,9 +36,8 @@ uses
   symconst,symtype,symdef,symsym,
   fmodule,
   nobj,
-  temp_gen,
   cpubase,
-  cga, tgcpu;
+  cga, tgobj;
 
    type
      ti386classheader=class(tclassheader)
@@ -223,7 +222,24 @@ initialization
 end.
 {
   $Log$
-  Revision 1.4  2001-10-25 21:22:41  peter
+  Revision 1.5  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.4  2001/10/25 21:22:41  peter
     * calling convention rewrite
 
   Revision 1.3  2001/09/19 11:04:41  michael

+ 44 - 27
compiler/i386/n386opt.pas

@@ -41,8 +41,8 @@ type
 
 implementation
 
-uses pass_1, types, htypechk, cgbase, temp_gen, cpubase, cga,
-     tgcpu, aasm, ncnv, ncon, pass_2, symdef;
+uses pass_1, types, htypechk, cgbase, cpubase, cga,
+     tgobj, aasm, ncnv, ncon, pass_2, symdef, rgobj;
 
 
 {*****************************************************************************
@@ -91,14 +91,14 @@ begin
   { first, we have to more or less replicate some code from }
   { ti386addnode.pass_2                                     }
   secondpass(left);
-  if not(istemp(left.location.reference) and
-         (getsizeoftemp(left.location.reference) = 256)) and
+  if not(tg.istemp(left.location.reference) and
+         (tg.getsizeoftemp(left.location.reference) = 256)) and
      not(nf_use_strconcat in flags) then
     begin
-       gettempofsizereference(256,href);
+       tg.gettempofsizereference(exprasmlist,256,href);
        copyshortstring(href,left.location.reference,255,false,true);
        { release the registers }
-       ungetiftemp(left.location.reference);
+       tg.ungetiftemp(exprasmlist,left.location.reference);
        { does not hurt: }
        clear_location(left.location);
        left.location.loc:=LOC_MEM;
@@ -117,22 +117,22 @@ begin
     if right.location.loc in [LOC_REFERENCE,LOC_MEM] then
       begin
         { free the registers of right }
-        del_reference(right.location.reference);
+        rg.del_reference(exprasmlist,right.location.reference);
         { get register for the char }
-        hreg := reg32toreg8(getregisterint);
+        hreg := reg32toreg8(rg.getregisterint(exprasmlist));
         emit_ref_reg(A_MOV,S_B,
           newreference(right.location.reference),hreg);
        { I don't think a temp char exists, but it won't hurt (JM) }
-       ungetiftemp(right.location.reference);
+       tg.ungetiftemp(exprasmlist,right.location.reference);
       end
     else hreg := right.location.register;
 
   { load the current string length }
-  lengthreg := getregisterint;
+  lengthreg := rg.getregisterint(exprasmlist);
   emit_ref_reg(A_MOVZX,S_BL,newreference(left.location.reference),lengthreg);
 
   { do we have to check the length ? }
-  if istemp(left.location.reference) then
+  if tg.istemp(left.location.reference) then
     checklength := curmaxlen = 255
   else
     checklength := curmaxlen >= tstringdef(left.resulttype.def).len;
@@ -140,7 +140,7 @@ begin
     begin
       { is it already maximal? }
       getlabel(l);
-      if istemp(left.location.reference) then
+      if tg.istemp(left.location.reference) then
         emit_const_reg(A_CMP,S_L,255,lengthreg)
       else
         emit_const_reg(A_CMP,S_L,tstringdef(left.resulttype.def).len,lengthreg);
@@ -179,7 +179,7 @@ begin
       { no new_reference(href2) because it's only }
       { used once (JM)                            }
       emit_reg_ref(A_MOV,S_B,hreg,href2);
-      ungetregister(hreg);
+      rg.ungetregister(exprasmlist,hreg);
     end
   else
     emit_const_ref(A_MOV,S_B,tordconstnode(right).value,href2);
@@ -187,7 +187,7 @@ begin
   emit_reg(A_INC,S_B,reg32toreg8(lengthreg));
   emit_reg_ref(A_MOV,S_B,reg32toreg8(lengthreg),
                  newreference(left.location.reference));
-  ungetregister32(lengthreg);
+  rg.ungetregisterint(exprasmlist,lengthreg);
   if checklength then
     emitlab(l);
   set_location(location,left.location);
@@ -196,20 +196,20 @@ end;
 procedure ti386addsstringcsstringoptnode.pass_2;
 var
   href: treference;
-  pushedregs: tpushed;
-  regstopush: byte;
+  pushedregs: tpushedsaved;
+  regstopush: tregisterset;
 begin
   { first, we have to more or less replicate some code from }
   { ti386addnode.pass_2                                     }
   secondpass(left);
-  if not(istemp(left.location.reference) and
-         (getsizeoftemp(left.location.reference) = 256)) and
+  if not(tg.istemp(left.location.reference) and
+         (tg.getsizeoftemp(left.location.reference) = 256)) and
      not(nf_use_strconcat in flags) then
     begin
-       gettempofsizereference(256,href);
+       tg.gettempofsizereference(exprasmlist,256,href);
        copyshortstring(href,left.location.reference,255,false,true);
        { release the registers }
-       ungetiftemp(left.location.reference);
+       tg.ungetiftemp(exprasmlist,left.location.reference);
        { does not hurt: }
        clear_location(left.location);
        left.location.loc:=LOC_MEM;
@@ -221,23 +221,23 @@ begin
   { push them (so the release is in the right place, }
   { because emitpushreferenceaddr doesn't need extra }
   { registers) (JM)                                  }
-  regstopush := $ff;
+  regstopush := all_registers;
   remove_non_regvars_from_loc(right.location,
     regstopush);
-  pushusedregisters(pushedregs,regstopush);
+  rg.saveusedregisters(exprasmlist,pushedregs,regstopush);
   { push the maximum possible length of the result }
   emitpushreferenceaddr(left.location.reference);
   { the optimizer can more easily put the          }
   { deallocations in the right place if it happens }
   { too early than when it happens too late (if    }
   { the pushref needs a "lea (..),edi; push edi")  }
-  del_reference(right.location.reference);
+  rg.del_reference(exprasmlist,right.location.reference);
   emitpushreferenceaddr(right.location.reference);
-  saveregvars(regstopush);
+  rg.saveregvars(exprasmlist,regstopush);
   emitcall('FPC_SHORTSTR_CONCAT');
-  ungetiftemp(right.location.reference);
+  tg.ungetiftemp(exprasmlist,right.location.reference);
   maybe_loadself;
-  popusedregisters(pushedregs);
+  rg.restoreusedregisters(exprasmlist,pushedregs);
   set_location(location,left.location);
 end;
 
@@ -248,7 +248,24 @@ end.
 
 {
   $Log$
-  Revision 1.6  2001-12-31 09:53:15  jonas
+  Revision 1.7  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.6  2001/12/31 09:53:15  jonas
     * changed remaining "getregister32" calls to "getregisterint"
 
   Revision 1.5  2001/08/26 13:37:00  florian

+ 57 - 40
compiler/i386/n386set.pas

@@ -47,10 +47,10 @@ implementation
       globtype,systems,cpuinfo,
       verbose,globals,
       symconst,symdef,aasm,types,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       ncon,
       cpubase,
-      cga,tgcpu,n386util,regvars;
+      cga,tgobj,n386util,regvars,rgobj;
 
      const
        bytes2Sxx:array[1..8] of Topsize=(S_B,S_W,S_NO,S_L,S_NO,S_NO,S_NO,S_Q);
@@ -236,7 +236,7 @@ implementation
             else
              begin
                { load the value in a register }
-               pleftreg := getexplicitregister32(R_EDI);
+               pleftreg := rg.getexplicitregisterint(exprasmlist,R_EDI);
                opsize := S_L;
                emit_ref_reg(A_MOVZX,S_BL,newreference(left.location.reference),
                             pleftreg);
@@ -274,8 +274,8 @@ implementation
                       if (pleftreg <> R_EDI) and
                          (left.location.loc = LOC_CREGISTER) then
                         begin
-                          ungetregister(pleftreg);
-                          getexplicitregister32(R_EDI);
+                          rg.ungetregister(exprasmlist,pleftreg);
+                          rg.getexplicitregisterint(exprasmlist,R_EDI);
                           emit_ref_reg(A_LEA,S_L,
                             new_reference(pleftreg,-setparts[i].start),R_EDI);
                           { only now change pleftreg since previous value is }
@@ -338,11 +338,11 @@ implementation
              emitlab(l);
              case left.location.loc of
             LOC_REGISTER,
-           LOC_CREGISTER : ungetregister(pleftreg);
+           LOC_CREGISTER : rg.ungetregister(exprasmlist,pleftreg);
              else
                begin
-                del_reference(left.location.reference);
-                ungetregister(R_EDI);
+                rg.del_reference(exprasmlist,left.location.reference);
+                rg.ungetregister(exprasmlist,R_EDI);
                end
              end
           end
@@ -361,13 +361,13 @@ implementation
                       begin
                          emit_const_reg(A_TEST,S_L,
                            1 shl (tordconstnode(left).value and 31),right.location.register);
-                         ungetregister32(right.location.register);
+                         rg.ungetregisterint(exprasmlist,right.location.register);
                        end
                   else
                    begin
                      emit_const_ref(A_TEST,S_L,1 shl (tordconstnode(left).value and 31),
                        newreference(right.location.reference));
-                     del_reference(right.location.reference);
+                     rg.del_reference(exprasmlist,right.location.reference);
                    end;
                   end;
                 end
@@ -385,11 +385,11 @@ implementation
                       { the set element isn't never samller than a byte  }
                       { and because it's a small set we need only 5 bits }
                       { but 8 bits are easier to load               }
-                      getexplicitregister32(R_EDI);
+                      rg.getexplicitregisterint(exprasmlist,R_EDI);
                       emit_ref_reg(A_MOVZX,S_BL,
                         newreference(left.location.reference),R_EDI);
                       hr:=R_EDI;
-                      del_reference(left.location.reference);
+                      rg.del_reference(exprasmlist,left.location.reference);
                     end;
                   end;
 
@@ -399,20 +399,20 @@ implementation
                           begin
                             emit_reg_reg(A_BT,S_L,hr,
                               right.location.register);
-                            ungetregister32(right.location.register);
+                            rg.ungetregisterint(exprasmlist,right.location.register);
                           end
                   else
                     begin
-                      del_reference(right.location.reference);
+                      rg.del_reference(exprasmlist,right.location.reference);
                       if right.location.reference.is_immediate then
                        begin
                        { We have to load the value into a register because
                          btl does not accept values only refs or regs (PFV) }
-                         hr2:=getregisterint;
+                         hr2:=rg.getregisterint(exprasmlist);
                          emit_const_reg(A_MOV,S_L,
                            right.location.reference.offset,hr2);
                          emit_reg_reg(A_BT,S_L,hr,hr2);
-                         ungetregister32(hr2);
+                         rg.ungetregisterint(exprasmlist,hr2);
                        end
                       else
                         emit_reg_ref(A_BT,S_L,hr,
@@ -420,7 +420,7 @@ implementation
                     end;
                   end;
                   { simply to indicate EDI is deallocated here too (JM) }
-                  ungetregister32(hr);
+                  rg.ungetregisterint(exprasmlist,hr);
                   location.loc:=LOC_FLAGS;
                   location.resflags:=F_C;
                 end;
@@ -436,7 +436,7 @@ implementation
                   { Is this treated in firstpass ?? }
                   if left.nodetype=ordconstn then
                     begin
-                      hr:=getregisterint;
+                      hr:=rg.getregisterint(exprasmlist);
                       left.location.loc:=LOC_REGISTER;
                       left.location.register:=hr;
                       emit_const_reg(A_MOV,S_L,
@@ -456,10 +456,10 @@ implementation
                           emitlab(l);
                         { We have to load the value into a register because
                           btl does not accept values only refs or regs (PFV) }
-                          hr2:=getregisterint;
+                          hr2:=rg.getregisterint(exprasmlist);
                           emit_const_reg(A_MOV,S_L,right.location.reference.offset,hr2);
                           emit_reg_reg(A_BT,S_L,hr,hr2);
-                          ungetregister32(hr2);
+                          rg.ungetregisterint(exprasmlist,hr2);
                        end;
                   else
                     begin
@@ -482,17 +482,17 @@ implementation
                        emit_none(A_CLC,S_NO);
                        emitjmp(C_NONE,l2);
                        emitlab(l);
-                       del_reference(left.location.reference);
-                       hr:=getregisterint;
+                       rg.del_reference(exprasmlist,left.location.reference);
+                       hr:=rg.getregisterint(exprasmlist);
                        emit_ref_reg(A_MOV,S_L,
                          newreference(left.location.reference),hr);
                      { We have to load the value into a register because
                        btl does not accept values only refs or regs (PFV) }
-                       hr2:=getregisterint;
+                       hr2:=rg.getregisterint(exprasmlist);
                        emit_const_reg(A_MOV,S_L,
                          right.location.reference.offset,hr2);
                        emit_reg_reg(A_BT,S_L,hr,hr2);
-                       ungetregister32(hr2);
+                       rg.ungetregisterint(exprasmlist,hr2);
                     end;
                   end;
                   emitlab(l2);
@@ -505,20 +505,20 @@ implementation
                   inc(right.location.reference.offset,tordconstnode(left).value shr 3);
                   emit_const_ref(A_TEST,S_B,1 shl (tordconstnode(left).value and 7),
                     newreference(right.location.reference));
-                  del_reference(right.location.reference);
+                  rg.del_reference(exprasmlist,right.location.reference);
                 end
                else
                 begin
                   if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
                     begin
-                      pleftreg := getexplicitregister32(R_EDI);
+                      pleftreg := rg.getexplicitregisterint(exprasmlist,R_EDI);
                       opsize := def2def_opsize(left.resulttype.def,u32bittype.def);
                       if opsize = S_L then
                         emit_ref_reg(A_MOV,opsize,newreference(left.location.reference),pleftreg)
                       else
                         emit_ref_reg(A_MOVZX,opsize,newreference(left.location.reference),pleftreg);
-                      ungetiftemp(left.location.reference);
-                      del_reference(left.location.reference);
+                      tg.ungetiftemp(exprasmlist,left.location.reference);
+                      rg.del_reference(exprasmlist,left.location.reference);
                     end
                   else
                     begin
@@ -532,16 +532,16 @@ implementation
                          emit_to_reg32(pleftreg)
                     end;
                   emit_reg_ref(A_BT,S_L,pleftreg,newreference(right.location.reference));
-                  ungetregister(pleftreg);
-                  del_reference(right.location.reference);
-                  { ungetiftemp(right.location.reference) happens below }
+                  rg.ungetregister(exprasmlist,pleftreg);
+                  rg.del_reference(exprasmlist,right.location.reference);
+                  { tg.ungetiftemp(exprasmlist,right.location.reference) happens below }
                   location.loc:=LOC_FLAGS;
                   location.resflags:=F_C;
                 end;
              end;
           end;
           if (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
-            ungetiftemp(right.location.reference);
+            tg.ungetiftemp(exprasmlist,right.location.reference);
        end;
 
 
@@ -885,7 +885,7 @@ implementation
               jmp_le:=C_B;
               jmp_lee:=C_BE;
            end;
-         cleartempgen;
+         rg.cleartempgen;
          { save current truelabel and falselabel (they are restored in }
          { locjump2reg) (JM)                                           }
          if left.location.loc=LOC_JUMP then
@@ -922,7 +922,7 @@ implementation
               end;
             LOC_CREGISTER:
               begin
-                 hregister:=getregisterint;
+                 hregister:=rg.getregisterint(exprasmlist);
                  case opsize of
                     S_B:
                       hregister:=reg32toreg8(hregister);
@@ -944,8 +944,8 @@ implementation
               end;
             LOC_MEM,LOC_REFERENCE:
               begin
-                 del_reference(left.location.reference);
-                 hregister:=getregisterint;
+                 rg.del_reference(exprasmlist,left.location.reference);
+                 hregister:=rg.getregisterint(exprasmlist);
                  case opsize of
                     S_B:
                       hregister:=reg32toreg8(hregister);
@@ -1059,13 +1059,13 @@ implementation
                 genlinearlist(nodes);
            end;
 
-         ungetregister(hregister);
+         rg.ungetregister(exprasmlist,hregister);
 
          { now generate the instructions }
          hp:=right;
          while assigned(hp) do
            begin
-              cleartempgen;
+              rg.cleartempgen;
               secondpass(tbinarynode(hp).right);
               { don't come back to case line }
               aktfilepos:=exprasmList.getlasttaifilepos^;
@@ -1077,7 +1077,7 @@ implementation
          { ...and the else block }
          if assigned(elseblock) then
            begin
-              cleartempgen;
+              rg.cleartempgen;
               secondpass(elseblock);
               load_all_regvars(exprasmlist);
            end;
@@ -1092,7 +1092,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.19  2001-12-31 09:53:15  jonas
+  Revision 1.20  2002-03-31 20:26:39  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.19  2001/12/31 09:53:15  jonas
     * changed remaining "getregister32" calls to "getregisterint"
 
   Revision 1.18  2001/12/03 21:48:43  peter

+ 121 - 126
compiler/i386/n386util.pas

@@ -63,8 +63,8 @@ implementation
        types,
        ncon,nld,
        pass_1,pass_2,
-       cgbase,tgcpu,temp_gen,
-       cga,regvars;
+       cgbase,tgobj,
+       cga,regvars,cgobj,rgobj,rgcpu;
 
 
 {*****************************************************************************
@@ -84,14 +84,14 @@ implementation
              maybe_push := true;
              exit;
            end;
-         if needed>usablereg32 then
+         if needed>rg.countunusedregsint then
            begin
               if (p.location.loc=LOC_REGISTER) then
                 begin
                    if isint64 then
                      begin
 {$ifdef TEMPS_NOT_PUSH}
-                        gettempofsizereference(href,8);
+                        tg.gettempofsizereference(exprasmlist,href,8);
                         p.temp_offset:=href.offset;
                         href.offset:=href.offset+4;
                         exprasmList.concat(Taicpu.Op_reg(A_MOV,S_L,p.location.registerhigh,href));
@@ -99,12 +99,12 @@ implementation
 {$else TEMPS_NOT_PUSH}
                         exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.registerhigh));
 {$endif TEMPS_NOT_PUSH}
-                        ungetregister32(p.location.registerhigh);
+                        rg.ungetregisterint(exprasmlist,p.location.registerhigh);
                      end
 {$ifdef TEMPS_NOT_PUSH}
                    else
                      begin
-                        gettempofsizereference(href,4);
+                        tg.gettempofsizereference(exprasmlist,href,4);
                         p.temp_offset:=href.offset;
                      end
 {$endif TEMPS_NOT_PUSH}
@@ -115,24 +115,24 @@ implementation
 {$else TEMPS_NOT_PUSH}
                    exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.register));
 {$endif TEMPS_NOT_PUSH}
-                   ungetregister32(p.location.register);
+                   rg.ungetregisterint(exprasmlist,p.location.register);
                 end
               else if (p.location.loc in [LOC_MEM,LOC_REFERENCE]) and
                       ((p.location.reference.base<>R_NO) or
                        (p.location.reference.index<>R_NO)
                       ) then
                   begin
-                     del_reference(p.location.reference);
-                     getexplicitregister32(R_EDI);
+                     rg.del_reference(exprasmlist,p.location.reference);
+                     rg.getexplicitregisterint(exprasmlist,R_EDI);
                      emit_ref_reg(A_LEA,S_L,newreference(p.location.reference),R_EDI);
 {$ifdef TEMPS_NOT_PUSH}
-                     gettempofsizereference(href,4);
+                     tg.gettempofsizereference(exprasmlist,href,4);
                      exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href));
                      p.temp_offset:=href.offset;
 {$else TEMPS_NOT_PUSH}
                      exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
 {$endif TEMPS_NOT_PUSH}
-                     ungetregister32(R_EDI);
+                     rg.ungetregisterint(exprasmlist,R_EDI);
                      pushed:=true;
                   end
               else pushed:=false;
@@ -167,40 +167,40 @@ implementation
          href : treference;
 
       begin
-         if needed>usablereg32 then
+         if needed>rg.unusedregsint then
            begin
               if (p^.location.loc=LOC_REGISTER) then
                 begin
                    if isint64(p^.resulttype.def) then
                      begin
-                        gettempofsizereference(href,8);
+                        tg.gettempofsizereference(exprasmlist,href,8);
                         p^.temp_offset:=href.offset;
                         href.offset:=href.offset+4;
                         exprasmList.concat(Taicpu.Op_reg(A_MOV,S_L,p^.location.registerhigh,href));
                         href.offset:=href.offset-4;
-                        ungetregister32(p^.location.registerhigh);
+                        rg.ungetregisterint(exprasmlist,p^.location.registerhigh);
                      end
                    else
                      begin
-                        gettempofsizereference(href,4);
+                        tg.gettempofsizereference(exprasmlist,href,4);
                         p^.temp_offset:=href.offset;
                      end;
                    pushed:=true;
                    exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p^.location.register,href));
-                   ungetregister32(p^.location.register);
+                   rg.ungetregisterint(exprasmlist,p^.location.register);
                 end
               else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
                       ((p^.location.reference.base<>R_NO) or
                        (p^.location.reference.index<>R_NO)
                       ) then
                   begin
-                     del_reference(p^.location.reference);
-                     getexplicitregister32(R_EDI);
+                     rg.del_reference(exprasmlist,p^.location.reference);
+                     rg.getexplicitregisterint(exprasmlist,R_EDI);
                      emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
                        R_EDI);
-                     gettempofsizereference(href,4);
+                     tg.gettempofsizereference(exprasmlist,href,4);
                      exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href));
-                     ungetregister32(R_EDI);
+                     rg.ungetregisterint(exprasmlist,R_EDI);
                      p^.temp_offset:=href.offset;
                      pushed:=true;
                   end
@@ -224,7 +224,7 @@ implementation
              load_regvar_reg(exprasmlist,p.location.register);
              exit;
            end;
-         hregister:=getregisterint;
+         hregister:=rg.getregisterint(exprasmlist);
 {$ifdef TEMPS_NOT_PUSH}
          reset_reference(href);
          href.base:=procinfo^.frame_pointer;
@@ -238,7 +238,7 @@ implementation
               p.location.register:=hregister;
               if isint64 then
                 begin
-                   p.location.registerhigh:=getregisterint;
+                   p.location.registerhigh:=rg.getregisterint(exprasmlist);
 {$ifdef TEMPS_NOT_PUSH}
                    href.offset:=p.temp_offset+4;
                    emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
@@ -260,7 +260,7 @@ implementation
               set_location(p.left^.location,p.location);}
            end;
 {$ifdef TEMPS_NOT_PUSH}
-         ungetiftemp(href);
+         tg.ungetiftemp(exprasmlist,href);
 {$endif TEMPS_NOT_PUSH}
       end;
 
@@ -272,7 +272,7 @@ implementation
          href : treference;
 
       begin
-         hregister:=getregisterint;
+         hregister:=rg.getregisterint(exprasmlist);
          reset_reference(href);
          href.base:=procinfo^.frame_pointer;
          href.offset:=p.temp_offset;
@@ -282,7 +282,7 @@ implementation
               p.location.register:=hregister;
               if isint64 then
                 begin
-                   p.location.registerhigh:=getregisterint;
+                   p.location.registerhigh:=rg.getregisterint(exprasmlist);
                    href.offset:=p.temp_offset+4;
                    emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
                    { set correctly for release ! }
@@ -297,7 +297,7 @@ implementation
                 because otherwise secondload fails PM
               set_location(p^.left^.location,p^.location);}
            end;
-         ungetiftemp(href);
+         tg.ungetiftemp(exprasmlist,href);
       end;
 {$endif TEMPS_NOT_PUSH}
 
@@ -342,7 +342,7 @@ implementation
                    exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,hr32))
                  else
                    exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,hr16));
-                 ungetregister32(hr32);
+                 rg.ungetregisterint(exprasmlist,hr32);
                end;
            else
              begin
@@ -350,7 +350,7 @@ implementation
                { because this may cross a page boundary and you'll get a }
                { sigsegv (JM)                                            }
                emit_push_mem_size(p.location.reference,1);
-               del_reference(p.location.reference);
+               rg.del_reference(exprasmlist,p.location.reference);
              end;
            end;
          end;
@@ -386,8 +386,8 @@ implementation
                            exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerhigh));
                            exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerlow));
                          end;
-                       ungetregister32(p.location.registerhigh);
-                       ungetregister32(p.location.registerlow);
+                       rg.ungetregisterint(exprasmlist,p.location.registerhigh);
+                       rg.ungetregisterint(exprasmlist,p.location.registerlow);
                     end
                   else case p.location.register of
                    R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
@@ -401,7 +401,7 @@ implementation
                          end
                         else
                          exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.register));
-                        ungetregister32(p.location.register);
+                        rg.ungetregisterint(exprasmlist,p.location.register);
                       end;
                    R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
                       begin
@@ -424,7 +424,7 @@ implementation
                           end
                         else
                           exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
-                        ungetregister32(reg16toreg32(p.location.register));
+                        rg.ungetregisterint(exprasmlist,reg16toreg32(p.location.register));
                       end;
                    R_AL,R_BL,R_CL,R_DL:
                       begin
@@ -448,12 +448,12 @@ implementation
                           end
                         else
                           exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
-                        ungetregister32(reg8toreg32(p.location.register));
+                        rg.ungetregisterint(exprasmlist,reg8toreg32(p.location.register));
                       end;
                    else internalerror(1899);
                 end;
              end;
-           LOC_FPU:
+           LOC_FPU, LOC_CFPUREGISTER:
              begin
                 size:=align(tfloatdef(p.resulttype.def).size,alignment);
                 inc(pushedparasize,size);
@@ -465,43 +465,21 @@ implementation
                   exprasmList.concat(Tai_force_line.Create);
 {$endif GDB}
                 r:=new_reference(R_ESP,0);
-                floatstoreops(tfloatdef(p.resulttype.def).typ,op,opsize);
                 { this is the easiest case for inlined !! }
                 if inlined then
                   begin
                      r^.base:=procinfo^.framepointer;
                      r^.offset:=para_offset-pushedparasize;
                   end;
-                exprasmList.concat(Taicpu.Op_ref(op,opsize,r));
-                dec(fpuvaroffset);
-             end;
-           LOC_CFPUREGISTER:
-             begin
-                exprasmList.concat(Taicpu.Op_reg(A_FLD,S_NO,
-                  correct_fpuregister(p.location.register,fpuvaroffset)));
-                size:=align(tfloatdef(p.resulttype.def).size,alignment);
-                inc(pushedparasize,size);
-                if not inlined then
-                 emit_const_reg(A_SUB,S_L,size,R_ESP);
-{$ifdef GDB}
-                if (cs_debuginfo in aktmoduleswitches) and
-                   (exprasmList.first=exprasmList.last) then
-                  exprasmList.concat(Tai_force_line.Create);
-{$endif GDB}
-                r:=new_reference(R_ESP,0);
-                floatstoreops(tfloatdef(p.resulttype.def).typ,op,opsize);
-                { this is the easiest case for inlined !! }
-                if inlined then
-                  begin
-                     r^.base:=procinfo^.framepointer;
-                     r^.offset:=para_offset-pushedparasize;
-                  end;
-                exprasmList.concat(Taicpu.Op_ref(op,opsize,r));
+
+                cg.a_loadfpu_reg_ref(exprasmlist,
+                  def_cgsize(p.resulttype.def),p.location.register,r^);
+                dispose(r);
              end;
            LOC_REFERENCE,LOC_MEM:
              begin
                 tempreference:=p.location.reference;
-                del_reference(p.location.reference);
+                rg.del_reference(exprasmlist,p.location.reference);
                 case p.resulttype.def.deftype of
                   enumdef,
                   orddef :
@@ -511,19 +489,19 @@ implementation
                              inc(pushedparasize,8);
                              if inlined then
                                begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
-                                 getexplicitregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  inc(tempreference.offset,4);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                                end
                              else
                                begin
@@ -537,12 +515,12 @@ implementation
                              inc(pushedparasize,4);
                              if inlined then
                                begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                                end
                              else
                                emit_push_mem(tempreference);
@@ -562,12 +540,12 @@ implementation
                               end;
                              if inlined then
                               begin
-                                getexplicitregister32(R_EDI);
+                                rg.getexplicitregisterint(exprasmlist,R_EDI);
                                 emit_ref_reg(A_MOV,opsize,
                                   newreference(tempreference),hreg);
                                 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                 exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
-                                ungetregister32(R_EDI);
+                                rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                              else
                               emit_push_mem_size(tempreference,p.resulttype.def.size);
@@ -584,12 +562,12 @@ implementation
                              inc(pushedparasize,4);
                              if inlined then
                                begin
-                                  getexplicitregister32(R_EDI);
+                                  rg.getexplicitregisterint(exprasmlist,R_EDI);
                                   emit_ref_reg(A_MOV,S_L,
                                     newreference(tempreference),R_EDI);
                                   r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                   exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                  ungetregister32(R_EDI);
+                                  rg.ungetregisterint(exprasmlist,R_EDI);
                                end
                              else
                                emit_push_mem(tempreference);
@@ -601,12 +579,12 @@ implementation
                             inc(tempreference.offset,4);
                             if inlined then
                               begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                             else
                               emit_push_mem(tempreference);
@@ -614,12 +592,12 @@ implementation
                             dec(tempreference.offset,4);
                             if inlined then
                               begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                             else
                               emit_push_mem(tempreference);
@@ -633,12 +611,12 @@ implementation
                               inc(tempreference.offset,6);
                             if inlined then
                               begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                             else
                               emit_push_mem(tempreference);
@@ -646,12 +624,12 @@ implementation
                             inc(pushedparasize,4);
                             if inlined then
                               begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,S_L,
                                    newreference(tempreference),R_EDI);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                             else
                               emit_push_mem(tempreference);
@@ -671,12 +649,12 @@ implementation
                               end;
                             if inlined then
                               begin
-                                 getexplicitregister32(R_EDI);
+                                 rg.getexplicitregisterint(exprasmlist,R_EDI);
                                  emit_ref_reg(A_MOV,opsize,
                                    newreference(tempreference),hreg);
                                  r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                                  exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
-                                 ungetregister32(R_EDI);
+                                 rg.ungetregisterint(exprasmlist,R_EDI);
                               end
                             else
                               exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,
@@ -691,12 +669,12 @@ implementation
                        inc(pushedparasize,4);
                        if inlined then
                          begin
-                            getexplicitregister32(R_EDI);
+                            rg.getexplicitregisterint(exprasmlist,R_EDI);
                             emit_ref_reg(A_MOV,S_L,
                               newreference(tempreference),R_EDI);
                             r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
                             exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
-                            ungetregister32(R_EDI);
+                            rg.ungetregisterint(exprasmlist,R_EDI);
                          end
                        else
                          emit_push_mem(tempreference);
@@ -802,9 +780,9 @@ implementation
              end;
            LOC_FLAGS:
              begin
-                if not(R_EAX in unused) then
+                if not(R_EAX in rg.unusedregsint) then
                   begin
-                    getexplicitregister32(R_EDI);
+                    rg.getexplicitregisterint(exprasmlist,R_EDI);
                     emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
                   end;
                 emit_flag2reg(p.location.resflags,R_AL);
@@ -828,10 +806,10 @@ implementation
                   end
                 else
                   exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
-                if not(R_EAX in unused) then
+                if not(R_EAX in rg.unusedregsint) then
                   begin
                     emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
-                    ungetregister32(R_EDI);
+                    rg.ungetregisterint(exprasmlist,R_EDI);
                   end;
              end;
 {$ifdef SUPPORT_MMX}
@@ -992,7 +970,7 @@ implementation
                            inc(href.offset,1);
                            emit_reg_ref(A_MOV,S_B,makereg8(source.location.register),
                                         newreference(href));
-                           ungetregister(source.location.register);
+                           rg.ungetregister(exprasmlist,source.location.register);
                         end
                       else
                       { not so elegant (goes better with extra register    }
@@ -1000,13 +978,13 @@ implementation
                            { not "movl", because then we may read past the }
                            { end of the heap! "movw" would be ok too, but  }
                            { I don't think that would be faster (JM)       }
-                           getexplicitregister32(R_EDI);
+                           rg.getexplicitregisterint(exprasmlist,R_EDI);
                            emit_ref_reg(A_MOVZX,S_BL,newreference(source.location.reference),R_EDI);
-                           del_reference(source.location.reference);
+                           rg.del_reference(exprasmlist,source.location.reference);
                            emit_const_reg(A_SHL,S_L,8,R_EDI);
                            emit_const_reg(A_OR,S_L,1,R_EDI);
                            emit_reg_ref(A_MOV,S_W,R_DI,newreference(dest.location.reference));
-                           ungetregister32(R_EDI);
+                           rg.ungetregisterint(exprasmlist,R_EDI);
                         end;
                    end;
               end;
@@ -1053,18 +1031,18 @@ implementation
                          LOC_REGISTER,LOC_CREGISTER:
                            begin
                               emit_reg_ref(A_MOV,S_B,p.right.location.register,r);
-                              ungetregister(p.right.location.register);
+                              rg.ungetregister(exprasmlist,p.right.location.register);
                            end;
                          LOC_MEM,LOC_REFERENCE:
                            begin
-                              if not(R_EAX in unused) then
+                              if not(R_EAX in rg.unusedregsint) then
                                 emit_reg(A_PUSH,S_L,R_EAX);
                               emit_ref_reg(A_MOV,S_B,newreference(p.right.location.reference),R_AL);
                               emit_reg_ref(A_MOV,S_B,R_AL,r);
 
-                              if not(R_EAX in unused) then
+                              if not(R_EAX in rg.unusedregsint) then
                                 emit_reg(A_POP,S_L,R_EAX);
-                              del_reference(p.right.location.reference);
+                              rg.del_reference(exprasmlist,p.right.location.reference);
                            end
                          else
                            internalerror(20799);
@@ -1079,70 +1057,70 @@ implementation
 
     procedure loadansi2short(source,dest : tnode);
       var
-         pushed : tpushed;
-         regs_to_push: byte;
+         pushed : tpushedsaved;
+         regs_to_push: tregisterset;
       begin
          { Find out which registers have to be pushed (JM) }
-         regs_to_push := $ff;
+         regs_to_push := all_registers;
          remove_non_regvars_from_loc(source.location,regs_to_push);
          { Push them (JM) }
-         pushusedregisters(pushed,regs_to_push);
+         rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
          case source.location.loc of
            LOC_REFERENCE,LOC_MEM:
              begin
                 { Now release the location and registers (see cgai386.pas: }
                 { loadansistring for more info on the order) (JM)          }
-                ungetiftemp(source.location.reference);
-                del_reference(source.location.reference);
+                tg.ungetiftemp(exprasmlist,source.location.reference);
+                rg.del_reference(exprasmlist,source.location.reference);
                 emit_push_mem(source.location.reference);
              end;
            LOC_REGISTER,LOC_CREGISTER:
              begin
                 emit_reg(A_PUSH,S_L,source.location.register);
                 { Now release the register (JM) }
-                ungetregister32(source.location.register);
+                rg.ungetregisterint(exprasmlist,source.location.register);
              end;
          end;
          push_shortstring_length(dest);
          emitpushreferenceaddr(dest.location.reference);
-         saveregvars($ff);
+         rg.saveregvars(exprasmlist,all_registers);
          emitcall('FPC_ANSISTR_TO_SHORTSTR');
-         popusedregisters(pushed);
+         rg.restoreusedregisters(exprasmlist,pushed);
          maybe_loadself;
       end;
 
 
     procedure loadwide2short(source,dest : tnode);
       var
-         pushed : tpushed;
-         regs_to_push: byte;
+         pushed : tpushedsaved;
+         regs_to_push: tregisterset;
       begin
          { Find out which registers have to be pushed (JM) }
-         regs_to_push := $ff;
+         regs_to_push := all_registers;
          remove_non_regvars_from_loc(source.location,regs_to_push);
          { Push them (JM) }
-         pushusedregisters(pushed,regs_to_push);
+         rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
          case source.location.loc of
            LOC_REFERENCE,LOC_MEM:
              begin
                 { Now release the location and registers (see cgai386.pas: }
                 { loadansistring for more info on the order) (JM)          }
-                ungetiftemp(source.location.reference);
-                del_reference(source.location.reference);
+                tg.ungetiftemp(exprasmlist,source.location.reference);
+                rg.del_reference(exprasmlist,source.location.reference);
                 emit_push_mem(source.location.reference);
              end;
            LOC_REGISTER,LOC_CREGISTER:
              begin
                 emit_reg(A_PUSH,S_L,source.location.register);
                 { Now release the register (JM) }
-                ungetregister32(source.location.register);
+                rg.ungetregisterint(exprasmlist,source.location.register);
              end;
          end;
          push_shortstring_length(dest);
          emitpushreferenceaddr(dest.location.reference);
-         saveregvars($ff);
+         rg.saveregvars(exprasmlist,all_registers);
          emitcall('FPC_WIDESTR_TO_SHORTSTR');
-         popusedregisters(pushed);
+         rg.restoreusedregisters(exprasmlist,pushed);
          maybe_loadself;
       end;
 
@@ -1154,7 +1132,7 @@ implementation
       to take care of that, an com interface can't be a register variable
     }
       var
-         pushed : tpushed;
+         pushed : tpushedsaved;
          ungettemp : boolean;
       begin
          { before pushing any parameter, we have to save all used      }
@@ -1165,33 +1143,33 @@ implementation
          { nevertheless, this has to be changed, because otherwise the }
          { register is released before it's contents are pushed ->     }
          { problems with the optimizer (JM)                         }
-         del_reference(p.left.location.reference);
+         rg.del_reference(exprasmlist,p.left.location.reference);
          ungettemp:=false;
          case p.right.location.loc of
             LOC_REGISTER,LOC_CREGISTER:
               begin
-                 pushusedregisters(pushed, $ff xor ($80 shr byte(p.right.location.register)));
+                 rg.saveusedregisters(exprasmlist,pushed, all_registers - [p.right.location.register]);
                  exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.right.location.register));
-                 ungetregister32(p.right.location.register);
+                 rg.ungetregisterint(exprasmlist,p.right.location.register);
               end;
             LOC_REFERENCE,LOC_MEM:
               begin
-                 pushusedregisters(pushed,$ff
-                   xor ($80 shr byte(p.right.location.reference.base))
-                   xor ($80 shr byte(p.right.location.reference.index)));
+                 rg.saveusedregisters(exprasmlist,pushed, all_registers
+                   - [p.right.location.reference.base]
+                   - [p.right.location.reference.index]);
                  emit_push_mem(p.right.location.reference);
-                 del_reference(p.right.location.reference);
+                 rg.del_reference(exprasmlist,p.right.location.reference);
                  ungettemp:=true;
               end;
          end;
          emitpushreferenceaddr(p.left.location.reference);
-         del_reference(p.left.location.reference);
-         saveregvars($ff);
+         rg.del_reference(exprasmlist,p.left.location.reference);
+         rg.saveregvars(exprasmlist,all_registers);
          emitcall('FPC_INTF_ASSIGN');
          maybe_loadself;
-         popusedregisters(pushed);
+         rg.restoreusedregisters(exprasmlist,pushed);
          if ungettemp then
-           ungetiftemp(p.right.location.reference);
+           tg.ungetiftemp(exprasmlist,p.right.location.reference);
       end;
 
 
@@ -1199,7 +1177,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.26  2002-03-04 19:10:14  peter
+  Revision 1.27  2002-03-31 20:26:40  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.26  2002/03/04 19:10:14  peter
     * removed compiler warnings
 
   Revision 1.25  2001/12/30 17:24:47  jonas

+ 21 - 4
compiler/i386/popt386.pas

@@ -41,7 +41,7 @@ Uses
 {$ifdef finaldestdebug}
   cobjects,
 {$endif finaldestdebug}
-  tainst,cpubase,cpuasm,DAOpt386,tgcpu;
+  tainst,cpubase,cpuasm,DAOpt386,rgobj;
 
 Function RegUsedAfterInstruction(Reg: TRegister; p: Tai; Var UsedRegs: TRegSet): Boolean;
 Begin
@@ -1123,9 +1123,9 @@ Begin
                                           Taicpu(hp2).LoadRef(1,newreference(Taicpu(hp2).oper[0].ref^));
                                           Taicpu(hp2).LoadReg(0,Taicpu(p).oper[1].reg);
                                           allocRegBetween(asmL,Taicpu(p).oper[1].reg,p,hp2);
-                                          if (Taicpu(p).oper[0].ref^.base in (usableregs+[R_EDI])) then
+                                          if (Taicpu(p).oper[0].ref^.base in (rg.usableregsint+[R_EDI])) then
                                             allocRegBetween(asmL,Taicpu(p).oper[0].ref^.base,p,hp2);
-                                          if (Taicpu(p).oper[0].ref^.index in (usableregs+[R_EDI])) then
+                                          if (Taicpu(p).oper[0].ref^.index in (rg.usableregsint+[R_EDI])) then
                                             allocRegBetween(asmL,Taicpu(p).oper[0].ref^.index,p,hp2);
                                         End
                                       Else
@@ -2025,7 +2025,24 @@ End.
 
 {
   $Log$
-  Revision 1.17  2001-12-29 15:29:59  jonas
+  Revision 1.18  2002-03-31 20:26:40  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.17  2001/12/29 15:29:59  jonas
     * powerpc/cgcpu.pas compiles :)
     * several powerpc-related fixes
     * cpuasm unit is now based on common tainst unit

+ 354 - 0
compiler/i386/rgcpu.pas

@@ -0,0 +1,354 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the i386 specific class for the register
+    allocator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit rgcpu;
+
+{$i defines.inc}
+
+  interface
+
+    uses
+      cpubase,
+      cpuinfo,
+      cpuasm,
+      tainst,
+      cclasses,globtype,cgbase,aasm,rgobj;
+
+    type
+       trgcpu = class(trgobj)
+
+          { to keep the same allocation order as with the old routines }
+          function getregisterint(list: taasmoutput): tregister; override;
+          procedure ungetregisterint(list: taasmoutput; r : tregister); override;
+          function getexplicitregisterint(list: taasmoutput; r : tregister) : tregister; override;
+
+          function getregisterfpu(list: taasmoutput) : tregister; override;
+          procedure ungetregisterfpu(list: taasmoutput; r : tregister); override;
+
+          procedure del_reference(list: taasmoutput; const ref : treference); override;
+
+          { pushes and restores registers }
+          procedure pushusedregisters(list: taasmoutput;
+            var pushed : tpushedsaved;const s: tregisterset);
+          procedure popusedregisters(list: taasmoutput;
+            const pushed : tpushedsaved);
+
+          procedure saveusedregisters(list: taasmoutput;
+            var saved : tpushedsaved;const s: tregisterset);override;
+          procedure restoreusedregisters(list: taasmoutput;
+            const saved : tpushedsaved);override;
+
+          procedure resetusableregisters;override;
+
+         { corrects the fpu stack register by ofs }
+         function correct_fpuregister(r : tregister;ofs : byte) : tregister;
+
+         fpuvaroffset : byte;
+       end;
+
+
+  implementation
+
+    uses
+       systems,
+       globals,verbose,node,
+       cgobj,tgobj,cga;
+
+
+    function trgcpu.getregisterint(list: taasmoutput): tregister;
+      begin
+         if countunusedregsint=0 then
+           internalerror(10);
+{$ifdef TEMPREGDEBUG}
+         if curptree^.usableregsint-countunusedregsint>curptree^.registers32 then
+           internalerror(10);
+{$endif TEMPREGDEBUG}
+{$ifdef EXTTEMPREGDEBUG}
+         if curptree^.usableregs-countunusedregistersint>curptree^^.reallyusedregs then
+           curptree^.reallyusedregs:=curptree^^.usableregs-countunusedregistersint;
+{$endif EXTTEMPREGDEBUG}
+         dec(countunusedregsint);
+         if R_EAX in unusedregsint then
+           begin
+              exclude(unusedregsint,R_EAX);
+              include(usedinproc,R_EAX);
+              getregisterint:=R_EAX;
+{$ifdef TEMPREGDEBUG}
+              reg_user[R_EAX]:=curptree^;
+{$endif TEMPREGDEBUG}
+              exprasmlist.concat(tairegalloc.alloc(R_EAX));
+           end
+         else if R_EDX in unusedregsint then
+           begin
+              exclude(unusedregsint,R_EDX);
+              include(usedinproc,R_EDX);
+              getregisterint:=R_EDX;
+{$ifdef TEMPREGDEBUG}
+              reg_user[R_EDX]:=curptree^;
+{$endif TEMPREGDEBUG}
+              exprasmlist.concat(tairegalloc.alloc(R_EDX));
+           end
+         else if R_EBX in unusedregsint then
+           begin
+              exclude(unusedregsint,R_EBX);
+              include(usedinproc,R_EBX);
+              getregisterint:=R_EBX;
+{$ifdef TEMPREGDEBUG}
+              reg_user[R_EBX]:=curptree^;
+{$endif TEMPREGDEBUG}
+              exprasmlist.concat(tairegalloc.alloc(R_EBX));
+           end
+         else if R_ECX in unusedregsint then
+           begin
+              exclude(unusedregsint,R_ECX);
+              include(usedinproc,R_ECX);
+              getregisterint:=R_ECX;
+{$ifdef TEMPREGDEBUG}
+              reg_user[R_ECX]:=curptree^;
+{$endif TEMPREGDEBUG}
+              exprasmlist.concat(tairegalloc.alloc(R_ECX));
+           end
+         else internalerror(10);
+{$ifdef TEMPREGDEBUG}
+         testregisters;
+{$endif TEMPREGDEBUG}
+      end;
+
+    procedure trgcpu.ungetregisterint(list: taasmoutput; r : tregister);
+      begin
+         r := makereg32(r);
+         if (r = R_EDI) or
+            ((not assigned(procinfo^._class)) and (r = R_ESI)) then
+           begin
+             list.concat(Tairegalloc.DeAlloc(r));
+             exit;
+           end;
+         if not(r in [R_EAX,R_EBX,R_ECX,R_EDX]) then
+           exit;
+         inherited ungetregisterint(list,r);
+      end;
+
+
+   function trgcpu.getexplicitregisterint(list: taasmoutput; r : tregister) : tregister;
+     begin
+       if r in [R_ESI,R_EDI] then
+         begin
+           list.concat(Tairegalloc.Alloc(r));
+           getexplicitregisterint := r;
+           exit;
+         end;
+       result := inherited getexplicitregisterint(list,r);
+    end;
+
+
+    function trgcpu.getregisterfpu(list: taasmoutput) : tregister;
+
+      begin
+        { note: don't return R_ST0, see comments above implementation of }
+        { a_loadfpu_* methods in cgcpu (JM)                              }
+        result := R_ST;
+      end;
+
+
+    procedure trgcpu.ungetregisterfpu(list : taasmoutput; r : tregister);
+
+      begin
+        { nothing to do, fpu stack management is handled by the load/ }
+        { store operations in cgcpu (JM)                              }
+      end;
+
+
+    procedure trgcpu.del_reference(list: taasmoutput; const ref : treference);
+
+      begin
+         if ref.is_immediate then
+           exit;
+         ungetregisterint(list,ref.base);
+         ungetregisterint(list,ref.index);
+      end;
+
+
+    procedure trgcpu.pushusedregisters(list: taasmoutput;
+        var pushed : tpushedsaved; const s: tregisterset);
+
+      var
+        r: tregister;
+        hr: preference;
+      begin
+        usedinproc:=usedinproc + s;
+        for r:=R_EAX to R_EBX do
+          begin
+            pushed[r].pushed:=false;
+            { if the register is used by the calling subroutine    }
+            if not is_reg_var[r] and
+               (r in s) and
+               { and is present in use }
+               not(r in unusedregsint) then
+              begin
+                { then save it }
+                list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
+                include(unusedregsint,r);
+                inc(countunusedregsint);
+                pushed[r].pushed:=true;
+              end;
+          end;
+{$ifdef SUPPORT_MMX}
+        for r:=R_MM0 to R_MM6 do
+          begin
+            pushed[r].pushed:=false;
+            { if the register is used by the calling subroutine    }
+            if not is_reg_var[r] and
+               (r in s) and
+               { and is present in use }
+               not(r in unusedregsmm) then
+              begin
+                list.concat(Taicpu.Op_const_reg(A_SUB,S_L,8,R_ESP));
+                new(hr);
+                reset_reference(hr^);
+                hr^.base:=R_ESP;
+                list.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,r,hr));
+                include(unusedregsmm,r);
+                inc(countunusedregsmm);
+                pushed[r].pushed:=true;
+              end;
+          end;
+{$endif SUPPORT_MMX}
+{$ifdef TEMPREGDEBUG}
+        testregisters;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    procedure trgcpu.popusedregisters(list: taasmoutput;
+        const pushed : tpushedsaved);
+
+      var
+        r : tregister;
+{$ifdef SUPPORT_MMX}
+        hr : preference;
+{$endif SUPPORT_MMX}
+      begin
+        { restore in reverse order: }
+{$ifdef SUPPORT_MMX}
+        for r:=R_MM6 downto R_MM0 do
+          if pushed[r].pushed then
+            begin
+              new(hr);
+              reset_reference(hr^);
+              hr^.base:=R_ESP;
+              list.concat(Taicpu.Op_ref_reg(
+                A_MOVQ,S_NO,hr,r));
+              list.concat(Taicpu.Op_const_reg(
+                A_ADD,S_L,8,R_ESP));
+              if not (r in unusedregsmm) then
+                { internalerror(10)
+                  in cg386cal we always restore regs
+                  that appear as used
+                  due to a unused tmep storage PM }
+              else
+                dec(countunusedregsmm);
+              exclude(unusedregsmm,r);
+            end;
+{$endif SUPPORT_MMX}
+        for r:=R_EBX downto R_EAX do
+          if pushed[r].pushed then
+            begin
+              list.concat(Taicpu.Op_reg(A_POP,S_L,r));
+              if not (r in unusedregsint) then
+                { internalerror(10)
+                  in cg386cal we always restore regs
+                  that appear as used
+                  due to a unused tmep storage PM }
+              else
+                dec(countunusedregsint);
+              exclude(unusedregsint,r);
+            end;
+{$ifdef TEMPREGDEBUG}
+        testregisters;
+{$endif TEMPREGDEBUG}
+      end;
+
+    procedure trgcpu.saveusedregisters(list: taasmoutput;var saved : tpushedsaved;
+      const s: tregisterset);
+
+      begin
+        if (aktoptprocessor in [class386,classP5]) or
+           (CS_LittleSize in aktglobalswitches) then
+          pushusedregisters(list,saved,s)
+        else
+          inherited saveusedregisters(list,saved,s);
+      end;
+
+
+    procedure trgcpu.restoreusedregisters(list: taasmoutput;
+      const saved : tpushedsaved);
+
+      begin
+        if (aktoptprocessor in [class386,classP5]) or
+           (CS_LittleSize in aktglobalswitches) then
+          popusedregisters(list,saved)
+        else
+          inherited restoreusedregisters(list,saved);
+      end;
+
+
+   procedure trgcpu.resetusableregisters;
+
+     begin
+       inherited resetusableregisters;
+       fpuvaroffset := 0;
+     end;
+
+
+   function trgcpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
+
+     begin
+        correct_fpuregister:=tregister(longint(r)+ofs);
+     end;
+
+
+initialization
+  rg := trgcpu.create;
+end.
+
+{
+  $Log$
+  Revision 1.1  2002-03-31 20:26:40  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+}

+ 21 - 4
compiler/i386/rropt386.pas

@@ -35,7 +35,7 @@ Implementation
 
 Uses
   {$ifdef replaceregdebug}cutils,{$endif}
-  verbose,globals,cpubase,cpuasm,daopt386,csopt386,tgcpu;
+  verbose,globals,cpubase,cpuasm,daopt386,csopt386,rgobj;
 
 function canBeFirstSwitch(p: Taicpu; reg: tregister): boolean;
 { checks whether an operation on reg can be switched to another reg without an }
@@ -319,8 +319,8 @@ begin
                      (Taicpu(p).oper[0].typ = top_reg) and
                      (Taicpu(p).oper[1].typ = top_reg) and
                      (Taicpu(p).opsize = S_L) and
-                     (Taicpu(p).oper[0].reg in (usableregs+[R_EDI])) and
-                     (Taicpu(p).oper[1].reg in (usableregs+[R_EDI])) then
+                     (Taicpu(p).oper[0].reg in (rg.usableregsint+[R_EDI])) and
+                     (Taicpu(p).oper[1].reg in (rg.usableregsint+[R_EDI])) then
                     if switchRegs(asml,Taicpu(p).oper[0].reg,
                          Taicpu(p).oper[1].reg,p) then
                       begin
@@ -344,7 +344,24 @@ End.
 
 {
   $Log$
-  Revision 1.8  2001-10-12 13:55:03  jonas
+  Revision 1.9  2002-03-31 20:26:41  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.8  2001/10/12 13:55:03  jonas
     * finer granularity for allocation of reused/replaced registers
 
   Revision 1.7  2001/08/29 14:07:43  jonas

+ 0 - 746
compiler/i386/tgcpu.pas

@@ -1,746 +0,0 @@
-{
-    $Id$
-    Copyright (C) 1998-2000 by Florian Klaempfl
-
-    This unit handles the temporary variables stuff for i386
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- ****************************************************************************
-}
-unit tgcpu;
-
-{$i defines.inc}
-
-interface
-
-    uses
-       globals,
-       cgbase,verbose,aasm,
-       node,
-       cpubase,cpuasm
-       ;
-
-    type
-       tregisterset = set of tregister;
-
-       tpushed = array[R_EAX..R_MM6] of boolean;
-       tsaved = array[R_EAX..R_MM6] of longint;
-
-    const
-       usablereg32 : byte = 4;
-
-       { this value is used in tsaved, if the register isn't saved }
-       reg_not_saved = $7fffffff;
-{$ifdef SUPPORT_MMX}
-       usableregmmx : byte = 8;
-{$endif SUPPORT_MMX}
-
-    var
-       { tries to hold the amount of times which the current tree is processed  }
-       t_times : longint;
-
-{$ifdef TEMPREGDEBUG}
-    procedure testregisters32;
-{$endif TEMPREGDEBUG}
-    function getregisterint : tregister;
-    function getaddressregister: tregister;
-    procedure ungetregister32(r : tregister);
-    { tries to allocate the passed register, if possible }
-    function getexplicitregister32(r : tregister) : tregister;
-{$ifdef SUPPORT_MMX}
-    function getregistermmx : tregister;
-    procedure ungetregistermmx(r : tregister);
-{$endif SUPPORT_MMX}
-
-    function isaddressregister(reg: tregister): boolean;
-
-    procedure ungetregister(r : tregister);
-
-    procedure cleartempgen;
-    procedure del_reference(const ref : treference);
-    procedure del_locref(const location : tlocation);
-    procedure del_location(const l : tlocation);
-
-    { pushs and restores registers }
-    procedure pushusedregisters(var pushed : tpushed;b : byte);
-    procedure popusedregisters(const pushed : tpushed);
-
-    { saves register variables (restoring happens automatically (JM) }
-    procedure saveregvars(b: byte);
-
-    { saves and restores used registers to temp. values }
-    procedure saveusedregisters(var saved : tsaved;b : byte);
-    procedure restoreusedregisters(const saved : tsaved);
-
-    { increments the push count of all registers in b}
-    procedure incrementregisterpushed(b : byte);
-
-    procedure clearregistercount;
-    procedure resetusableregisters;
-
-    { corrects the fpu stack register by ofs }
-    function correct_fpuregister(r : tregister;ofs : byte) : tregister;
-
-    type
-{$ifdef SUPPORT_MMX}
-       regvar_longintarray = array[R_EAX..R_MM6] of longint;
-       regvar_booleanarray = array[R_EAX..R_MM6] of boolean;
-       regvar_ptreearray = array[R_EAX..R_MM6] of tnode;
-{$else SUPPORT_MMX}
-       regvar_longintarray = array[R_EAX..R_EDI] of longint;
-       regvar_booleanarray = array[R_EAX..R_EDI] of boolean;
-       regvar_ptreearray = array[R_EAX..R_EDI] of tnode;
-{$endif SUPPORT_MMX}
-
-    var
-       unused,usableregs : tregisterset;
-       c_usableregs : longint;
-
-       { uses only 1 byte while a set uses in FPC 32 bytes }
-       usedinproc : byte;
-
-       fpuvaroffset : byte;
-
-       { count, how much a register must be pushed if it is used as register }
-       { variable                                                           }
-       reg_pushes : regvar_longintarray;
-       is_reg_var : regvar_booleanarray;
-       regvar_loaded: regvar_booleanarray;
-
-{$ifdef TEMPREGDEBUG}
-       reg_user   : regvar_ptreearray;
-       reg_releaser : regvar_ptreearray;
-{$endif TEMPREGDEBUG}
-
-
-implementation
-
-    uses
-      globtype,temp_gen,tainst,regvars;
-
-    procedure incrementregisterpushed(b : byte);
-
-      var
-         regi : tregister;
-
-      begin
-         for regi:=R_EAX to R_EDI do
-           begin
-              if (b and ($80 shr word(regi)))<>0 then
-                inc(reg_pushes[regi],t_times*2);
-           end;
-      end;
-
-    procedure pushusedregisters(var pushed : tpushed;b : byte);
-
-      var
-         r : tregister;
-{$ifdef SUPPORT_MMX}
-         hr : preference;
-{$endif}
-      begin
-         usedinproc:=usedinproc or b;
-         for r:=R_EAX to R_EBX do
-           begin
-              pushed[r]:=false;
-              { if the register is used by the calling subroutine    }
-              if ((b and ($80 shr byte(r)))<>0) then
-                begin
-                  { and is present in use }
-                  if not is_reg_var[r] then
-                    if not(r in unused) then
-                     begin
-                        { then save it }
-                        exprasmlist.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
-
-                        { here was a big problem  !!!!!}
-                        { you cannot do that for a register that is
-                        globally assigned to a var
-                        this also means that you must push it much more
-                        often, but there must be a better way
-                        maybe by putting the value back to the stack !! }
-                        if not(is_reg_var[r]) then
-                          begin
-                            unused:=unused+[r];
-{$ifdef TEMPREGDEBUG}
-                            inc(usablereg32);
-{$endif TEMPREGDEBUG}
-                          end;
-                        pushed[r]:=true;
-                     end;
-                end;
-           end;
-{$ifdef SUPPORT_MMX}
-         for r:=R_MM0 to R_MM6 do
-           begin
-              pushed[r]:=false;
-              { if the mmx register is in use, save it }
-              if not(r in unused) then
-                begin
-                   exprasmList.concat(Taicpu.Op_const_reg(A_SUB,S_L,8,R_ESP));
-                   new(hr);
-                   reset_reference(hr^);
-                   hr^.base:=R_ESP;
-                   exprasmList.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,r,hr));
-                   if not(is_reg_var[r]) then
-                     begin
-                       unused:=unused+[r];
-{$ifdef TEMPREGDEBUG}
-                       inc(usableregmmx);
-{$endif TEMPREGDEBUG}
-                     end;
-                   pushed[r]:=true;
-                end;
-           end;
-{$endif SUPPORT_MMX}
-{$ifdef TEMPREGDEBUG}
-        testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-
-    procedure saveregvars(b: byte);
-
-      var
-         r : tregister;
-
-      begin
-         if not(cs_regalloc in aktglobalswitches) then
-           exit;
-         for r:=R_EAX to R_EBX do
-           { if the register is used by the calling subroutine    }
-           if ((b and ($80 shr byte(r)))<>0) and is_reg_var[r] then
-             store_regvar(exprasmlist,r)
-      end;
-
-
-    procedure saveusedregisters(var saved : tsaved;b : byte);
-
-      var
-         r : tregister;
-         hr : treference;
-
-      begin
-         usedinproc:=usedinproc or b;
-         for r:=R_EAX to R_EBX do
-           begin
-              saved[r]:=reg_not_saved;
-              { if the register is used by the calling subroutine    }
-              if ((b and ($80 shr byte(r)))<>0) then
-                begin
-                   { and is present in use }
-                   if not(r in unused) then
-                     begin
-                        { then save it }
-                        gettempofsizereference(4,hr);
-                        saved[r]:=hr.offset;
-                        exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,r,newreference(hr)));
-                        { here was a big problem  !!!!!}
-                        { you cannot do that for a register that is
-                        globally assigned to a var
-                        this also means that you must push it much more
-                        often, but there must be a better way
-                        maybe by putting the value back to the stack !! }
-                        if not(is_reg_var[r]) then
-                          begin
-                            unused:=unused+[r];
-{$ifdef TEMPREGDEBUG}
-                            inc(usablereg32);
-{$endif TEMPREGDEBUG}
-                          end;
-                     end;
-                end;
-           end;
-{$ifdef SUPPORT_MMX}
-         for r:=R_MM0 to R_MM6 do
-           begin
-              saved[r]:=reg_not_saved;
-              { if the mmx register is in use, save it }
-              if not(r in unused) then
-                begin
-                   gettempofsizereference(8,hr);
-                   exprasmList.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,r,newreference(hr)));
-                   if not(is_reg_var[r]) then
-                     begin
-                       unused:=unused+[r];
-{$ifdef TEMPREGDEBUG}
-                       inc(usableregmmx);
-{$endif TEMPREGDEBUG}
-                     end;
-                   saved[r]:=hr.offset;
-                end;
-           end;
-{$endif SUPPORT_MMX}
-{$ifdef TEMPREGDEBUG}
-        testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-    procedure popusedregisters(const pushed : tpushed);
-
-      var
-         r : tregister;
-{$ifdef SUPPORT_MMX}
-         hr : preference;
-{$endif SUPPORT_MMX}
-      begin
-         { restore in reverse order: }
-{$ifdef SUPPORT_MMX}
-         for r:=R_MM6 downto R_MM0 do
-           begin
-              if pushed[r] then
-                begin
-                   new(hr);
-                   reset_reference(hr^);
-                   hr^.base:=R_ESP;
-                   exprasmList.concat(Taicpu.Op_ref_reg(
-                     A_MOVQ,S_NO,hr,r));
-                   exprasmList.concat(Taicpu.Op_const_reg(
-                     A_ADD,S_L,8,R_ESP));
-                   unused:=unused-[r];
-{$ifdef TEMPREGDEBUG}
-                   dec(usableregmmx);
-{$endif TEMPREGDEBUG}
-                end;
-           end;
-{$endif SUPPORT_MMX}
-         for r:=R_EBX downto R_EAX do
-           if pushed[r] then
-             begin
-                exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,r));
-{$ifdef TEMPREGDEBUG}
-                if not (r in unused) then
-                  { internalerror(10)
-                    in cg386cal we always restore regs
-                    that appear as used
-                    due to a unused tmep storage PM }
-                else
-                  dec(usablereg32);
-{$endif TEMPREGDEBUG}
-                unused:=unused-[r];
-             end;
-{$ifdef TEMPREGDEBUG}
-        testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-    procedure restoreusedregisters(const saved : tsaved);
-      var
-         r : tregister;
-         hr : treference;
-
-      begin
-         { restore in reverse order: }
-{$ifdef SUPPORT_MMX}
-         for r:=R_MM6 downto R_MM0 do
-           begin
-              if saved[r]<>reg_not_saved then
-                begin
-                   reset_reference(hr);
-                   hr.base:=frame_pointer;
-                   hr.offset:=saved[r];
-                   exprasmList.concat(Taicpu.Op_ref_reg(
-                     A_MOVQ,S_NO,newreference(hr),r));
-                   unused:=unused-[r];
-{$ifdef TEMPREGDEBUG}
-                   dec(usableregmmx);
-{$endif TEMPREGDEBUG}
-                   ungetiftemp(hr);
-                end;
-           end;
-{$endif SUPPORT_MMX}
-         for r:=R_EBX downto R_EAX do
-           if saved[r]<>reg_not_saved then
-             begin
-                reset_reference(hr);
-                hr.base:=frame_pointer;
-                hr.offset:=saved[r];
-                exprasmList.concat(Taicpu.Op_ref_reg(A_MOV,S_L,newreference(hr),r));
-{$ifdef TEMPREGDEBUG}
-                if not (r in unused) then
-                  internalerror(10)
-                else
-                  dec(usablereg32);
-{$endif TEMPREGDEBUG}
-                unused:=unused-[r];
-                ungetiftemp(hr);
-             end;
-{$ifdef TEMPREGDEBUG}
-        testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-    procedure ungetregister(r : tregister);
-
-      begin
-         if r in [R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI] then
-           ungetregister32(r)
-          else if r in [R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI] then
-           ungetregister32(reg16toreg32(r))
-         else if r in [R_AL,R_BL,R_CL,R_DL] then
-           ungetregister32(reg8toreg32(r))
-{$ifdef SUPPORT_MMX}
-         else if r in [R_MM0..R_MM6] then
-           ungetregistermmx(r)
-{$endif SUPPORT_MMX}
-         else internalerror(18);
-      end;
-
-    procedure ungetregister32(r : tregister);
-
-      begin
-         if (r = R_EDI) or
-            ((not assigned(procinfo^._class)) and (r = R_ESI)) then
-           begin
-             exprasmList.concat(Tairegalloc.DeAlloc(r));
-             exit;
-           end;
-         if cs_regalloc in aktglobalswitches then
-           begin
-              { takes much time }
-              if not(r in usableregs) then
-                exit;
-              unused:=unused+[r];
-              inc(usablereg32);
-           end
-         else
-           begin
-              if not(r in [R_EAX,R_EBX,R_ECX,R_EDX]) then
-                exit;
-{$ifdef TEMPREGDEBUG}
-                if (r in unused) then
-{$ifdef EXTTEMPREGDEBUG}
-                  begin
-                    Comment(V_Debug,'register freed twice '+reg2str(r));
-                    testregisters32;
-                    exit;
-                  end
-{$else EXTTEMPREGDEBUG}
-                  exit
-{$endif EXTTEMPREGDEBUG}
-                else
-{$endif TEMPREGDEBUG}
-                  inc(usablereg32);
-              unused:=unused+[r];
-{$ifdef TEMPREGDEBUG}
-              reg_releaser[r]:=curptree^;
-{$endif TEMPREGDEBUG}
-           end;
-         exprasmList.concat(Tairegalloc.DeAlloc(r));
-{$ifdef TEMPREGDEBUG}
-        testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-{$ifdef SUPPORT_MMX}
-    function getregistermmx : tregister;
-
-      var
-         r : tregister;
-
-      begin
-         dec(usableregmmx);
-         for r:=R_MM0 to R_MM6 do
-           if r in unused then
-             begin
-                unused:=unused-[r];
-                usedinproc:=usedinproc or ($80 shr byte(R_EAX));
-                getregistermmx:=r;
-                exit;
-             end;
-         internalerror(10);
-      end;
-
-    procedure ungetregistermmx(r : tregister);
-
-      begin
-         if cs_regalloc in aktglobalswitches then
-           begin
-              { takes much time }
-              if not(r in usableregs) then
-                exit;
-              unused:=unused+[r];
-              inc(usableregmmx);
-           end
-         else
-           begin
-              unused:=unused+[r];
-              inc(usableregmmx);
-           end;
-      end;
-{$endif SUPPORT_MMX}
-
-    function isaddressregister(reg: tregister): boolean;
-
-      begin
-        isaddressregister := true;
-      end;
-
-    procedure del_reference(const ref : treference);
-
-      begin
-         if ref.is_immediate then
-           exit;
-         ungetregister32(ref.base);
-         ungetregister32(ref.index);
-      end;
-
-
-    procedure del_locref(const location : tlocation);
-      begin
-         if (location.loc<>loc_mem) and (location.loc<>loc_reference) then
-           exit;
-         if location.reference.is_immediate then
-           exit;
-         ungetregister32(location.reference.base);
-         ungetregister32(location.reference.index);
-      end;
-
-
-    procedure del_location(const l : tlocation);
-      begin
-        case l.loc of
-          LOC_REGISTER :
-            ungetregister(l.register);
-          LOC_MEM,LOC_REFERENCE :
-            del_reference(l.reference);
-        end;
-      end;
-
-
-{$ifdef TEMPREGDEBUG}
-    procedure testregisters32;
-     var test : byte;
-       begin
-         test:=0;
-         if R_EAX in unused then
-           inc(test);
-         if R_EBX in unused then
-           inc(test);
-         if R_ECX in unused then
-           inc(test);
-         if R_EDX in unused then
-           inc(test);
-         if test<>usablereg32 then
-           internalerror(10);
-       end;
-{$endif TEMPREGDEBUG}
-
-    function getregisterint : tregister;
-      begin
-         if usablereg32=0 then
-           internalerror(10);
-{$ifdef TEMPREGDEBUG}
-         if curptree^^.usableregs-usablereg32>curptree^^.registers32 then
-           internalerror(10);
-{$endif TEMPREGDEBUG}
-{$ifdef EXTTEMPREGDEBUG}
-         if curptree^^.usableregs-usablereg32>curptree^^.reallyusedregs then
-           curptree^^.reallyusedregs:=curptree^^.usableregs-usablereg32;
-{$endif EXTTEMPREGDEBUG}
-         dec(usablereg32);
-         if R_EAX in unused then
-           begin
-              unused:=unused-[R_EAX];
-              usedinproc:=usedinproc or ($80 shr byte(R_EAX));
-              getregisterint:=R_EAX;
-{$ifdef TEMPREGDEBUG}
-              reg_user[R_EAX]:=curptree^;
-{$endif TEMPREGDEBUG}
-              exprasmList.concat(Tairegalloc.Alloc(R_EAX));
-           end
-         else if R_EDX in unused then
-           begin
-              unused:=unused-[R_EDX];
-              usedinproc:=usedinproc or ($80 shr byte(R_EDX));
-              getregisterint:=R_EDX;
-{$ifdef TEMPREGDEBUG}
-              reg_user[R_EDX]:=curptree^;
-{$endif TEMPREGDEBUG}
-              exprasmList.concat(Tairegalloc.Alloc(R_EDX));
-           end
-         else if R_EBX in unused then
-           begin
-              unused:=unused-[R_EBX];
-              usedinproc:=usedinproc or ($80 shr byte(R_EBX));
-              getregisterint:=R_EBX;
-{$ifdef TEMPREGDEBUG}
-              reg_user[R_EBX]:=curptree^;
-{$endif TEMPREGDEBUG}
-              exprasmList.concat(Tairegalloc.Alloc(R_EBX));
-           end
-         else if R_ECX in unused then
-           begin
-              unused:=unused-[R_ECX];
-              usedinproc:=usedinproc or ($80 shr byte(R_ECX));
-              getregisterint:=R_ECX;
-{$ifdef TEMPREGDEBUG}
-              reg_user[R_ECX]:=curptree^;
-{$endif TEMPREGDEBUG}
-              exprasmList.concat(Tairegalloc.Alloc(R_ECX));
-           end
-         else internalerror(10);
-{$ifdef TEMPREGDEBUG}
-         testregisters32;
-{$endif TEMPREGDEBUG}
-      end;
-
-
-    function getaddressregister: tregister;
-
-      begin
-        getaddressregister := getregisterint;
-      end;
-
-    function getexplicitregister32(r : tregister) : tregister;
-
-      begin
-         if r in [R_ESI,R_EDI] then
-           begin
-             exprasmList.concat(Tairegalloc.Alloc(r));
-             getexplicitregister32 := r;
-             exit;
-           end;
-         if r in unused then
-           begin
-              dec(usablereg32);
-{$ifdef TEMPREGDEBUG}
-              if curptree^^.usableregs-usablereg32>curptree^^.registers32 then
-                internalerror(10);
-              reg_user[r]:=curptree^;
-{$endif TEMPREGDEBUG}
-              unused:=unused-[r];
-              usedinproc:=usedinproc or ($80 shr byte(r));
-              exprasmList.concat(Tairegalloc.Alloc(r));
-              getexplicitregister32:=r;
-{$ifdef TEMPREGDEBUG}
-         testregisters32;
-{$endif TEMPREGDEBUG}
-           end
-         else
-           getexplicitregister32:=getregisterint;
-      end;
-
-    procedure cleartempgen;
-
-      begin
-         unused:=usableregs;
-         usablereg32:=c_usableregs;
-         {fpuvaroffset:=0;
-          this must only be resetted at each procedure
-          compilation start PM }
-      end;
-
-
-   procedure clearregistercount;
-      var
-        regi : tregister;
-      begin
-{$ifdef SUPPORT_MMX}
-         for regi:=R_EAX to R_MM6 do
-           begin
-              reg_pushes[regi]:=0;
-              is_reg_var[regi]:=false;
-           end;
-{$else SUPPORT_MMX}
-         for regi:=R_EAX to R_EDI do
-           begin
-              reg_pushes[regi]:=0;
-              is_reg_var[regi]:=false;
-           end;
-{$endif SUPPORT_MMX}
-      end;
-
-   function correct_fpuregister(r : tregister;ofs : byte) : tregister;
-
-     begin
-        correct_fpuregister:=tregister(longint(r)+ofs);
-     end;
-
-   procedure resetusableregisters;
-      begin
-{$ifdef SUPPORT_MMX}
-        usableregs:=[R_EAX,R_EBX,R_ECX,R_EDX,R_MM0..R_MM6];
-        c_usableregs:=4;
-        usableregmmx:=8;
-{$else}
-        usableregs:=[R_EAX,R_EBX,R_ECX,R_EDX];
-        c_usableregs:=4;
-{$endif SUPPORT_MMX}
-        fillchar(regvar_loaded,sizeof(regvar_loaded),false);
-        fillchar(is_reg_var,sizeof(is_reg_var),false);
-        fpuvaroffset:=0;
-      end;
-
-begin
-  resetusableregisters;
-end.
-{
-  $Log$
-  Revision 1.8  2001-12-31 09:53:16  jonas
-    * changed remaining "getregister32" calls to "getregisterint"
-
-  Revision 1.7  2001/12/29 15:29:59  jonas
-    * powerpc/cgcpu.pas compiles :)
-    * several powerpc-related fixes
-    * cpuasm unit is now based on common tainst unit
-    + nppcmat unit for powerpc (almost complete)
-
-  Revision 1.5  2001/08/26 13:37:03  florian
-    * some cg reorganisation
-    * some PPC updates
-
-  Revision 1.4  2001/04/13 01:22:21  peter
-    * symtable change to classes
-    * range check generation and errors fixed, make cycle DEBUG=1 works
-    * memory leaks fixed
-
-  Revision 1.3  2000/12/25 00:07:34  peter
-    + new tlinkedlist class (merge of old tstringqueue,tcontainer and
-      tlinkedlist objects)
-
-  Revision 1.2  2000/12/05 11:44:34  jonas
-    + new integer regvar handling, should be much more efficient
-
-  Revision 1.1  2000/11/29 00:30:51  florian
-    * unused units removed from uses clause
-    * some changes for widestrings
-
-  Revision 1.9  2000/10/31 22:30:13  peter
-    * merged asm result patch part 2
-
-  Revision 1.8  2000/10/14 10:14:56  peter
-    * moehrendorf oct 2000 rewrite
-
-  Revision 1.7  2000/09/30 16:08:46  peter
-    * more cg11 updates
-
-  Revision 1.6  2000/09/24 15:06:32  peter
-    * use defines.inc
-
-  Revision 1.5  2000/08/27 16:11:55  peter
-    * moved some util functions from globals,cobjects to cutils
-    * splitted files into finput,fmodule
-
-  Revision 1.4  2000/08/05 13:32:39  peter
-    * fixed build prob without support_mmx
-
-  Revision 1.3  2000/08/04 05:09:49  jonas
-    * forgot to commit :( (part of regvar changes)
-
-  Revision 1.2  2000/07/13 11:32:52  michael
-  + removed logs
-}

+ 21 - 12
compiler/nbas.pas

@@ -149,7 +149,7 @@ implementation
       verbose,globals,globtype,systems,
       symconst,symdef,symsym,types,
       pass_1,
-      ncal,nflw,tgcpu,cgbase
+      ncal,nflw,rgobj,cgbase
       ;
 
 {*****************************************************************************
@@ -233,11 +233,7 @@ implementation
       begin
          result:=nil;
          { no temps over several statements }
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          { right is the statement itself calln assignn or a complex one }
          firstpass(right);
          if codegenerror then
@@ -371,11 +367,7 @@ implementation
                 end;
               if assigned(hp.right) then
                 begin
-{$ifdef newcg}
-                   tg.cleartempgen;
-{$else newcg}
-                   cleartempgen;
-{$endif newcg}
+                   rg.cleartempgen;
                    codegenerror:=false;
                    firstpass(hp.right);
 
@@ -625,7 +617,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.18  2001-11-02 22:58:01  peter
+  Revision 1.19  2002-03-31 20:26:33  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.18  2001/11/02 22:58:01  peter
     * procsym definition rewrite
 
   Revision 1.17  2001/09/02 21:12:06  peter

+ 22 - 15
compiler/ncal.pas

@@ -121,7 +121,7 @@ implementation
       symconst,types,
       htypechk,pass_1,cpubase,
       ncnv,nld,ninl,nadd,ncon,
-      tgcpu,cgbase
+      rgobj,cgbase
       ;
 
 
@@ -1555,14 +1555,7 @@ implementation
               { procedure does a call }
               if not (block_type in [bt_const,bt_type]) then
                 procinfo^.flags:=procinfo^.flags or pi_do_call;
-{$ifndef newcg}
-              { calc the correct value for the register }
-{$ifdef i386}
-              incrementregisterpushed($ff);
-{$else}
-              incrementregisterpushed(ALL_REGISTERS);
-{$endif}
-{$endif newcg}
+              rg.incrementregisterpushed(all_registers);
            end
          else
          { not a procedure variable }
@@ -1600,12 +1593,9 @@ implementation
                     procinfo^.flags:=procinfo^.flags or pi_do_call;
                 end;
 
-{$ifndef newcg}
-{$ifndef POWERPC}
              { for the PowerPC standard calling conventions this information isn't necassary (FK) }
-             incrementregisterpushed(tprocdef(procdefinition).usedregisters);
-{$endif POWERPC}
-{$endif newcg}
+             { It doesn't hurt to calculate it already though :) (JM) }
+             rg.incrementregisterpushed(tprocdef(procdefinition).usedregisters);
            end;
 
          { get a register for the return value }
@@ -1837,7 +1827,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.65  2002-03-30 23:02:42  carl
+  Revision 1.66  2002-03-31 20:26:33  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.65  2002/03/30 23:02:42  carl
   * avoid crash with inline routines
 
   Revision 1.64  2002/01/24 18:25:48  peter

+ 23 - 6
compiler/ncgbas.pas

@@ -69,7 +69,7 @@ interface
       nflw,pass_2,
       cgbase,
       cga,
-      tgcpu,temp_gen
+      tgobj,rgobj
       ;
 {*****************************************************************************
                                  TNOTHING
@@ -94,7 +94,7 @@ interface
           begin
             if assigned(tstatementnode(hp).right) then
              begin
-               cleartempgen;
+               rg.cleartempgen;
                secondpass(tstatementnode(hp).right);
              end;
             hp:=tstatementnode(hp).left;
@@ -240,9 +240,9 @@ interface
 
         { get a (persistent) temp }
         if persistent then
-          gettempofsizereferencepersistant(size,tempinfo^.ref)
+          tg.gettempofsizereferencepersistant(exprasmlist,size,tempinfo^.ref)
         else
-          gettempofsizereference(size,tempinfo^.ref);
+          tg.gettempofsizereference(exprasmlist,size,tempinfo^.ref);
         tempinfo^.valid := true;
       end;
 
@@ -267,7 +267,7 @@ interface
 
     procedure tcgtempdeletenode.pass_2;
       begin
-        ungetpersistanttempreference(tempinfo^.ref);
+        tg.ungetpersistanttempreference(exprasmlist,tempinfo^.ref);
       end;
 
 
@@ -282,7 +282,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.10  2001-12-31 16:54:14  peter
+  Revision 1.11  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.10  2001/12/31 16:54:14  peter
     * fixed inline crash with assembler routines
 
   Revision 1.9  2001/11/02 22:58:01  peter

+ 49 - 30
compiler/ncgcnv.pas

@@ -59,7 +59,7 @@ interface
 {$ifdef i386}
       n386util,
 {$endif i386}
-      tgcpu,temp_gen
+      tgobj,rgobj
       ;
 
 
@@ -75,8 +75,8 @@ interface
            st_shortstring :
              begin
                inc(left.location.reference.offset);
-               del_reference(left.location.reference);
-               location.register:=getregisterint;
+               rg.del_reference(exprasmlist,left.location.reference);
+               location.register:=rg.getregisterint(exprasmlist);
                cg.a_loadaddress_ref_reg(exprasmlist,left.location.reference,
                  location.register);
              end;
@@ -87,13 +87,13 @@ interface
                 begin
                   reset_reference(hr);
                   hr.symbol:=newasmsymbol('FPC_EMPTYCHAR');
-                  location.register:=getregisterint;
+                  location.register:=rg.getregisterint(exprasmlist);
                   cg.a_loadaddress_ref_reg(exprasmlist,hr,location.register);
                 end
                else
                 begin
-                  del_reference(left.location.reference);
-                  location.register:=getregisterint;
+                  rg.del_reference(exprasmlist,left.location.reference);
+                  location.register:=rg.getregisterint(exprasmlist);
                   cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,
                     location.register);
                 end;
@@ -110,13 +110,13 @@ interface
                 begin
                   reset_reference(hr);
                   hr.symbol:=newasmsymbol('FPC_EMPTYCHAR');
-                  location.register:=getregisterint;
+                  location.register:=rg.getregisterint(exprasmlist);
                   cg.a_loadaddress_ref_reg(exprasmlist,hr,location.register);
                 end
                else
                 begin
-                  del_reference(left.location.reference);
-                  location.register:=getregisterint;
+                  rg.del_reference(exprasmlist,left.location.reference);
+                  location.register:=rg.getregisterint(exprasmlist);
 {$warning Todo: convert widestrings to ascii when typecasting them to pchars}
                   cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,
                     location.register);
@@ -151,10 +151,10 @@ interface
     procedure tcgtypeconvnode.second_array_to_pointer;
 
       begin
-         del_reference(left.location.reference);
+         rg.del_reference(exprasmlist,left.location.reference);
          clear_location(location);
          location.loc:=LOC_REGISTER;
-         location.register:=getregisterint;
+         location.register:=rg.getregisterint(exprasmlist);
          cg.a_loadaddress_ref_reg(exprasmlist,left.location.reference,
            location.register);
       end;
@@ -171,14 +171,14 @@ interface
             location.reference.base:=left.location.register;
           LOC_CREGISTER :
             begin
-              location.reference.base:=getregisterint;
+              location.reference.base:=rg.getregisterint(exprasmlist);
               cg.a_load_reg_reg(exprasmlist,OS_32,left.location.register,
                 location.reference.base);
             end
          else
             begin
-              del_reference(left.location.reference);
-              location.reference.base:=getregisterint;
+              rg.del_reference(exprasmlist,left.location.reference);
+              location.reference.base:=rg.getregisterint(exprasmlist);
               cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,
                 location.reference.base);
             end;
@@ -194,7 +194,7 @@ interface
          case tstringdef(resulttype.def).string_typ of
            st_shortstring :
              begin
-               gettempofsizereference(256,location.reference);
+               tg.gettempofsizereference(exprasmlist,256,location.reference);
                loadshortstring(left,self);
              end;
            { the rest is removed in the resulttype pass and converted to compilerprocs }
@@ -206,6 +206,8 @@ interface
 
     procedure tcgtypeconvnode.second_real_to_real;
       begin
+         clear_location(location);
+         location.loc:=LOC_FPU;
          case left.location.loc of
             LOC_FPU : ;
             LOC_CFPUREGISTER:
@@ -216,14 +218,14 @@ interface
             LOC_MEM,
             LOC_REFERENCE:
               begin
-                 floatload(tfloatdef(left.resulttype.def).typ,
-                   left.location.reference);
+                 location.register := rg.getregisterfpu(exprasmlist);
+                 cg.a_loadfpu_ref_reg(exprasmlist,
+                   def_cgsize(left.resulttype.def),
+                   left.location.reference,location.register);
                  { we have to free the reference }
-                 del_reference(left.location.reference);
+                 rg.del_reference(exprasmlist,left.location.reference);
               end;
          end;
-         clear_location(location);
-         location.loc:=LOC_FPU;
       end;
 
 
@@ -247,8 +249,8 @@ interface
           begin
              clear_location(location);
              location.loc:=LOC_REGISTER;
-             del_reference(left.location.reference);
-             location.register:=getregisterint;
+             rg.del_reference(exprasmlist,left.location.reference);
+             location.register:=rg.getregisterint(exprasmlist);
              cg.a_loadaddress_ref_reg(exprasmlist,left.location.reference,
                location.register);
           end;
@@ -281,8 +283,8 @@ interface
            end;
          clear_location(location);
          location.loc:=LOC_REGISTER;
-         del_location(left.location);
-         location.register:=getregisterint;
+         rg.del_location(exprasmlist,left.location);
+         location.register:=rg.getregisterint(exprasmlist);
          { size of the boolean we're converting }
          opsize := def_cgsize(left.resulttype.def);
          { size of the destination }
@@ -358,8 +360,8 @@ interface
               location.register:=left.location.register;
             LOC_MEM,LOC_REFERENCE:
               begin
-                del_reference(left.location.reference);
-                location.register:=getregisterint;
+                rg.del_reference(exprasmlist,left.location.reference);
+                location.register:=rg.getregisterint(exprasmlist);
                 cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,
                   location.register);
               end;
@@ -382,14 +384,14 @@ interface
             LOC_MEM,
             LOC_REFERENCE:
               begin
-                 del_reference(left.location.reference);
-                 hreg:=getregisterint;
+                 rg.del_reference(exprasmlist,left.location.reference);
+                 hreg:=rg.getregisterint(exprasmlist);
                  cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,
                    hreg);
               end;
             LOC_CREGISTER:
               begin
-                 hreg:=getregisterint;
+                 hreg:=rg.getregisterint(exprasmlist);
                  cg.a_load_reg_reg(exprasmlist,OS_32,left.location.register,
                    hreg);
               end;
@@ -422,7 +424,24 @@ end.
 
 {
   $Log$
-  Revision 1.4  2001-12-31 09:53:15  jonas
+  Revision 1.5  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.4  2001/12/31 09:53:15  jonas
     * changed remaining "getregister32" calls to "getregisterint"
 
   Revision 1.3  2001/10/04 14:33:28  jonas

+ 19 - 3
compiler/ncgcon.pas

@@ -66,9 +66,8 @@ implementation
       globtype,widestr,systems,
       verbose,globals,
       symconst,symdef,aasm,types,
-      temp_gen,
       cpubase,
-      tgcpu;
+      tgobj;
 
 
 {*****************************************************************************
@@ -517,7 +516,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.4  2002-02-26 09:12:39  jonas
+  Revision 1.5  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.4  2002/02/26 09:12:39  jonas
     * fixed problem when compiling the compiler with Delphi (reported by
       "Luc Langlois" <[email protected]>) (lo/hi don't work as in FPC
       when used with int64's under Delphi)

+ 73 - 35
compiler/ncgflw.pas

@@ -68,10 +68,10 @@ implementation
     uses
       verbose,globals,systems,globtype,
       symconst,symdef,symsym,aasm,types,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       cpubase,cpuasm,cpuinfo,
       nld,ncon,
-      cga,tgcpu,
+      cga,tgobj,rgobj,
       ncgutil,
       tainst,regvars,cgobj,cgcpu;
 
@@ -105,7 +105,7 @@ implementation
 
          aktcontinuelabel:=lcont;
          aktbreaklabel:=lbreak;
-         cleartempgen;
+         rg.cleartempgen;
          if assigned(right) then
            secondpass(right);
 
@@ -125,7 +125,7 @@ implementation
             truelabel:=lbreak;
             falselabel:=lloop;
           end;
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(left);
 
          maketojumpbool(left,lr_load_regvars);
@@ -160,7 +160,7 @@ implementation
          oflabel:=falselabel;
          getlabel(truelabel);
          getlabel(falselabel);
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(left);
 
 
@@ -174,12 +174,12 @@ implementation
          maketojumpbool(left,lr_dont_load_regvars);
 
          if cs_regalloc in aktglobalswitches then
-           org_regvar_loaded := regvar_loaded;
+           org_regvar_loaded := rg.regvar_loaded;
 
          if assigned(right) then
            begin
               cg.a_label(exprasmlist,truelabel);
-              cleartempgen;
+              rg.cleartempgen;
               secondpass(right);
            end;
 
@@ -187,8 +187,8 @@ implementation
          { loaded regvar state and create new clean ones                 }
          if cs_regalloc in aktglobalswitches then
            begin
-             then_regvar_loaded := regvar_loaded;
-             regvar_loaded := org_regvar_loaded;
+             then_regvar_loaded := rg.regvar_loaded;
+             rg.regvar_loaded := org_regvar_loaded;
              then_list := exprasmlist;
              exprasmlist := taasmoutput.create;
            end;
@@ -206,13 +206,13 @@ implementation
                    cg.a_jmp_cond(exprasmlist,OC_None,hl);
                 end;
               cg.a_label(exprasmlist,falselabel);
-              cleartempgen;
+              rg.cleartempgen;
               secondpass(t1);
               { save current asmlist (previous instructions + else-block) }
               { and loaded regvar state and create a new clean list       }
               if cs_regalloc in aktglobalswitches then
                 begin
-                  else_regvar_loaded := regvar_loaded;
+                  else_regvar_loaded := rg.regvar_loaded;
                   else_list := exprasmlist;
                   exprasmlist := taasmoutput.create;
                 end;
@@ -223,7 +223,7 @@ implementation
            begin
               if cs_regalloc in aktglobalswitches then
                 begin
-                  else_regvar_loaded := regvar_loaded;
+                  else_regvar_loaded := rg.regvar_loaded;
                   else_list := exprasmlist;
                   exprasmlist := taasmoutput.create;
                 end;
@@ -297,28 +297,28 @@ implementation
                   (tordconstnode(tassignmentnode(left).right).value<=tordconstnode(right).value));
 
          { only calculate reference }
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(t2);
          hs := t2.resulttype.def.size;
          opsize := def_cgsize(t2.resulttype.def);
 
          { first set the to value
            because the count var can be in the expression !! }
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(right);
          { calculate pointer value and check if changeable and if so }
          { load into temporary variable                       }
          if right.nodetype<>ordconstn then
            begin
               temp1.symbol:=nil;
-              gettempofsizereference(hs,temp1);
+              tg.gettempofsizereference(exprasmlist,hs,temp1);
               temptovalue:=true;
               if (right.location.loc=LOC_REGISTER) or
                  (right.location.loc=LOC_CREGISTER) then
                 begin
                    cg.a_load_reg_ref(exprasmlist,opsize,
                      right.location.register,temp1);
-                   ungetregister(right.location.register);
+                   rg.ungetregister(exprasmlist,right.location.register);
                  end
               else
                 cg.g_concatcopy(exprasmlist,right.location.reference,temp1,
@@ -328,7 +328,7 @@ implementation
            temptovalue:=false;
 
          { produce start assignment }
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(left);
          count_var_is_signed:=is_signed(torddef(t2.resulttype.def));
 
@@ -365,7 +365,7 @@ implementation
          cg.a_label(exprasmlist,l3);
 
          { help register must not be in instruction block }
-         cleartempgen;
+         rg.cleartempgen;
          if assigned(t1) then
            begin
              secondpass(t1);
@@ -375,7 +375,7 @@ implementation
          cg.a_label(exprasmlist,aktcontinuelabel);
 
          { makes no problems there }
-         cleartempgen;
+         rg.cleartempgen;
 
          if nf_backward in flags then
            if count_var_is_signed then
@@ -411,7 +411,7 @@ implementation
          cg.a_jmp_cond(exprasmlist,OC_None,l3);
 
          if temptovalue then
-           ungetiftemp(temp1);
+           tg.ungetiftemp(exprasmlist,temp1);
 
          { this is the break label: }
          cg.a_label(exprasmlist,aktbreaklabel);
@@ -442,14 +442,14 @@ implementation
         begin
           if is_mem then
             begin
-              del_reference(left.location.reference);
-              ungetiftemp(left.location.reference);
+              rg.del_reference(exprasmlist,left.location.reference);
+              tg.ungetiftemp(exprasmlist,left.location.reference);
             end
           else
             begin
-              ungetregister(left.location.register);
+              rg.ungetregister(exprasmlist,left.location.register);
               if left.location.registerhigh <> R_NO then
-                ungetregister(left.location.registerhigh);
+                rg.ungetregister(exprasmlist,left.location.registerhigh);
             end;
         end;
 
@@ -487,15 +487,25 @@ implementation
                              goto do_jmp;
                            end;
                 LOC_JUMP : begin
-                             exprasmlist.concat(tairegalloc.alloc(accumulator));
+                             cg.a_reg_alloc(exprasmlist,accumulator);
                              allocated_acc := true;
                              cg.a_label(exprasmlist,truelabel);
+{$ifdef i386}
                              cg.a_load_const_reg(exprasmlist,OS_8,1,
                                makereg8(accumulator));
+{$else i386}
+                             cg.a_load_const_reg(exprasmlist,OS_8,1,
+                               accumulator);
+{$endif i386}
                              cg.a_jmp_cond(exprasmlist,OC_NONE,aktexit2label);
                              cg.a_label(exprasmlist,falselabel);
+{$ifdef i386}
                              cg.a_load_const_reg(exprasmlist,OS_8,0,
                                makereg8(accumulator));
+{$else i386}
+                             cg.a_load_const_reg(exprasmlist,OS_8,0,
+                               accumulator);
+{$endif i386}
                              goto do_jmp;
                            end;
               else
@@ -507,17 +517,17 @@ implementation
                           cleanleft;
                           cg.a_reg_alloc(exprasmlist,accumulator);
                           allocated_acc := true;
-                          if is_mem then
-                            cg.a_load_ref_reg(exprasmlist,OS_ADDR,
-                              left.location.reference,accumulator)
-                          else
-                            cg.a_load_reg_reg(exprasmlist,OS_ADDR,
-                              left.location.register,accumulator);
+                          cg.a_load_loc_reg(exprasmlist,OS_ADDR,
+                            left.location,accumulator);
                         end;
              floatdef : begin
+{$ifndef i386}
+                          cg.a_reg_alloc(exprasmlist,fpuresultreg);
+{$endif not i386}
+                          cg.a_loadfpu_loc_reg(exprasmlist,
+                            def_cgsize(aktprocdef.rettype.def),
+                            left.location,fpuresultreg);
                           cleanleft;
-                          if is_mem then
-                           floatload(tfloatdef(aktprocdef.rettype.def).typ,left.location.reference);
                         end;
               { orddef,
               enumdef : }
@@ -550,6 +560,7 @@ implementation
                         end;
                    { if its 3 bytes only we can still
                      copy one of garbage ! PM }
+{$ifdef i386}
                     4,3 :
                       cg.a_load_loc_reg(exprasmlist,OS_32,left.location,
                         accumulator);
@@ -559,6 +570,12 @@ implementation
                     1 :
                       cg.a_load_loc_reg(exprasmlist,OS_8,left.location,
                         makereg8(accumulator));
+{$else i386}
+                    4,3,2,1:
+                      cg.a_load_loc_reg(exprasmlist,
+                        def_cgsize(aktprocdef.rettype.def.size),left.location,
+                        accumulator));
+{$endif i386}
                     else internalerror(605001);
                    end;
                  end;
@@ -571,6 +588,10 @@ do_jmp:
                 cg.a_reg_dealloc(exprasmlist,accumulator);
               if allocated_acchigh then
                 cg.a_reg_dealloc(exprasmlist,accumulator);
+{$ifndef i386}
+             if (aktprocdef.rettype.def.deftype = floatdef) then
+               cg.a_reg_dealloc(exprasmlist,fpuresultreg);
+{$endif not i386}
            end
          else
             cg.a_jmp_cond(exprasmlist,OC_None,aktexitlabel);
@@ -631,7 +652,7 @@ do_jmp:
       begin
          load_all_regvars(exprasmlist);
          cg.a_label(exprasmlist,labelnr);
-         cleartempgen;
+         rg.cleartempgen;
          secondpass(left);
       end;
 
@@ -648,7 +669,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.8  2002-03-04 19:10:11  peter
+  Revision 1.9  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.8  2002/03/04 19:10:11  peter
     * removed compiler warnings
 
   Revision 1.7  2001/12/30 17:24:48  jonas

+ 49 - 32
compiler/ncgmem.pas

@@ -81,10 +81,10 @@ implementation
       globtype,systems,
       cutils,verbose,globals,
       symconst,symbase,symdef,symsym,aasm,
-      cgbase,temp_gen,pass_2,
+      cgbase,pass_2,
       nld,ncon,nadd,
       cpubase,cgobj,cgcpu,
-      cga,tgcpu;
+      cga,tgobj,rgobj;
 
 {*****************************************************************************
                             TCGLOADNODE
@@ -93,7 +93,7 @@ implementation
     procedure tcgloadvmtnode.pass_2;
 
       begin
-         location.register:=getregisterint;
+         location.register:=rg.getregisterint(exprasmlist);
          cg.a_load_sym_ofs_reg(exprasmlist,
            newasmsymbol(tobjectdef(tclassrefdef(resulttype.def).pointertype.def).vmt_mangledname),
            0,location.register);
@@ -125,10 +125,10 @@ implementation
          case left.location.loc of
             LOC_REGISTER:
               begin
-                if not isaddressregister(left.location.register) then
+                if not rg.isaddressregister(left.location.register) then
                   begin
-                    ungetregister(left.location.register);
-                    location.reference.index := getaddressregister;
+                    rg.ungetregister(exprasmlist,left.location.register);
+                    location.reference.index := rg.getaddressregister(exprasmlist);
                     cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
                       location.reference.index);
                   end
@@ -137,8 +137,8 @@ implementation
               end;
             LOC_CREGISTER,LOC_MEM,LOC_REFERENCE:
               begin
-                 del_location(left.location);
-                 location.reference.index:=getaddressregister;
+                 rg.del_location(exprasmlist,left.location);
+                 location.reference.index:=rg.getaddressregister(exprasmlist);
                  cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,
                    location.reference.index);
               end;
@@ -163,8 +163,8 @@ implementation
           end;
 
          location.loc:=LOC_REGISTER;
-         del_reference(left.location.reference);
-         location.register:=getaddressregister;
+         rg.del_reference(exprasmlist,left.location.reference);
+         location.register:=rg.getaddressregister(exprasmlist);
          {@ on a procvar means returning an address to the procedure that
            is stored in it.}
          { yes but left.symtableentry can be nil
@@ -191,8 +191,8 @@ implementation
       begin
          secondpass(left);
          location.loc:=LOC_REGISTER;
-         del_reference(left.location.reference);
-         location.register:=getaddressregister;
+         rg.del_reference(exprasmlist,left.location.reference);
+         location.register:=rg.getaddressregister(exprasmlist);
          cg.a_loadaddress_ref_reg(exprasmlist,left.location.reference,
            location.register);
       end;
@@ -210,10 +210,10 @@ implementation
          case left.location.loc of
             LOC_REGISTER:
               begin
-                if not isaddressregister(left.location.register) then
+                if not rg.isaddressregister(left.location.register) then
                   begin
-                    ungetregister(left.location.register);
-                    location.reference.base := getaddressregister;
+                    rg.ungetregister(exprasmlist,left.location.register);
+                    location.reference.base := rg.getaddressregister(exprasmlist);
                     cg.a_load_reg_reg(exprasmlist,OS_ADDR,left.location.register,
                       location.reference.base);
                   end
@@ -222,8 +222,8 @@ implementation
               end;
             LOC_CREGISTER,LOC_MEM,LOC_REFERENCE:
               begin
-                 del_location(left.location);
-                 location.reference.base:=getaddressregister;
+                 rg.del_location(exprasmlist,left.location);
+                 location.reference.base:=rg.getaddressregister(exprasmlist);
                  cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,
                    location.reference.base);
               end;
@@ -249,10 +249,10 @@ implementation
              case left.location.loc of
                 LOC_REGISTER:
                   begin
-                    if not isaddressregister(left.location.register) then
+                    if not rg.isaddressregister(left.location.register) then
                       begin
-                        ungetregister(left.location.register);
-                        location.reference.base := getaddressregister;
+                        rg.ungetregister(exprasmlist,left.location.register);
+                        location.reference.base := rg.getaddressregister(exprasmlist);
                         cg.a_load_reg_reg(exprasmlist,OS_ADDR,
                           left.location.register,location.reference.base);
                       end
@@ -261,8 +261,8 @@ implementation
                   end;
                 LOC_CREGISTER,LOC_MEM,LOC_REFERENCE:
                   begin
-                     del_location(left.location);
-                     location.reference.base:=getaddressregister;
+                     rg.del_location(exprasmlist,left.location);
+                     location.reference.base:=rg.getaddressregister(exprasmlist);
                      cg.a_load_loc_reg(exprasmlist,OS_ADDR,left.location,
                        location.reference.base);
                   end;
@@ -270,7 +270,7 @@ implementation
            end
          else if is_interfacecom(left.resulttype.def) then
            begin
-              gettempintfcomreference(location.reference);
+              tg.gettempintfcomreference(exprasmlist,location.reference);
               cg.a_load_loc_ref(exprasmlist,OS_ADDR,left.location,
                 location.reference);
            end
@@ -290,7 +290,7 @@ implementation
     procedure tcgselfnode.pass_2;
       begin
          reset_reference(location.reference);
-         getexplicitregister32(SELF_POINTER);
+         rg.getexplicitregisterint(exprasmlist,SELF_POINTER);
          if (resulttype.def.deftype=classrefdef) or
            is_class(resulttype.def) then
           begin
@@ -352,15 +352,15 @@ implementation
                       left.location.reference,tmpreg);
                 end;
 
-               del_location(left.location);
+               rg.del_location(exprasmlist,left.location);
 
                { if the with expression is stored in a temp    }
                { area we must make it persistent and shouldn't }
                { release it (FK)                               }
                if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) and
-                 istemp(left.location.reference) then
+                 tg.istemp(left.location.reference) then
                  begin
-                    normaltemptopersistant(left.location.reference.offset);
+                    tg.normaltemptopersistant(left.location.reference.offset);
                     with_expr_in_temp:=true;
                  end
                else
@@ -369,9 +369,9 @@ implementation
                { if usetemp is set the value must be in tmpreg }
                if usetemp then
                 begin
-                  gettempofsizereference(target_info.size_of_pointer,
+                  tg.gettempofsizereference(exprasmlist,target_info.size_of_pointer,
                     withreference^);
-                  normaltemptopersistant(withreference^.offset);
+                  tg.normaltemptopersistant(withreference^.offset);
                   { move to temp reference }
                   cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,withreference^);
                   cg.free_scratch_reg(exprasmlist,tmpreg);
@@ -405,7 +405,7 @@ implementation
 
                if usetemp then
                  begin
-                   ungetpersistanttemp(withreference^.offset);
+                   tg.ungetpersistanttemp(exprasmlist,withreference^.offset);
 {$ifdef GDB}
                    if (cs_debuginfo in aktmoduleswitches) then
                      begin
@@ -424,7 +424,7 @@ implementation
                  end;
 
                if with_expr_in_temp then
-                 ungetpersistanttemp(left.location.reference.offset);
+                 tg.ungetpersistanttemp(exprasmlist,left.location.reference.offset);
 
                dispose(withreference);
                withreference:=nil;
@@ -444,7 +444,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.3  2001-12-31 09:53:15  jonas
+  Revision 1.4  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.3  2001/12/31 09:53:15  jonas
     * changed remaining "getregister32" calls to "getregisterint"
 
   Revision 1.2  2001/11/02 22:58:02  peter

+ 31 - 14
compiler/ncgutil.pas

@@ -45,8 +45,8 @@ implementation
     globals,globtype,systems,verbose,
     types,
     aasm,cgbase,regvars,
-    temp_gen,ncon,
-    cpubase,cpuinfo,tgcpu,cgobj,cgcpu,cg64f32;
+    ncon,
+    cpubase,cpuinfo,tgobj,cgobj,cgcpu,cg64f32,rgobj;
 
 
 {$ifdef TEMPS_NOT_PUSH}
@@ -62,7 +62,7 @@ implementation
                 begin
                    if isint64 then
                      begin
-                       gettempofsizereference(8,href);
+                       tg.gettempofsizereference(8,href);
                        p.temp_offset:=href.offset;
                        { do we have a 64bit processor? }
                        if sizeof(aword) < 8 then
@@ -70,23 +70,23 @@ implementation
                            tcg64f32(cg).a_load64_reg_ref(exprasmlist,
                              p.location.registerlow,p.location.registerhigh,
                              href);
-                           ungetregister(p.location.registerhigh);
-                           ungetregister(p.location.registerlow);
+                           rg.ungetregister(exprasmlist,p.location.registerhigh);
+                           rg.ungetregister(exprasmlist,p.location.registerlow);
                          end
                        else
                          begin
                            cg.a_load_reg_ref(exprasmlist,OS_64,
                              p.location.register,href);
-                           ungetregister(p.location.register);
+                           rg.ungetregister(exprasmlist,p.location.register);
                          end;
                      end
                    else
                      begin
-                        gettempofsizereference(4,href);
+                        tg.gettempofsizereference(4,href);
                         p.temp_offset:=href.offset;
                         cg.a_load_reg_ref(exprasmlist,OS_32,
                           p.location.register,href);
-                        ungetregister(p.location.register);
+                        rg.ungetregister(exprasmlist,p.location.register);
                      end;
                    saved:=true;
                 end
@@ -99,7 +99,7 @@ implementation
                      cg.a_loadaddress_ref_reg(exprasmlist,
                        p.location.reference,scratchreg);
                      del_reference(p.location.reference);
-                     gettempofsizereference(target_info.size_of_pointer,href);
+                     tg.gettempofsizereference(target_info.size_of_pointer,href);
                      cg.a_load_reg_ref(exprasmlist,OS_ADDR,scratchreg,href);
                      cg.free_scratch_reg(exprasmlist,scratchreg);
                      p.temp_offset:=href.offset;
@@ -118,7 +118,7 @@ implementation
          href : treference;
 
       begin
-         hregister:=getregisterint;
+         hregister:=rg.getregisterint(exprasmlist);
          reset_reference(href);
          href.base:=procinfo^.framepointer;
          href.offset:=p.temp_offset;
@@ -129,7 +129,7 @@ implementation
                 begin
                   if sizeof(aword) < 8 then
                     begin
-                      p.location.registerhigh:=getregisterint;
+                      p.location.registerhigh:=rg.getregisterint(exprasmlist);
                       tcg64f32(cg).a_load64_ref_reg(exprasmlist,
                         href,p.location.registerlow,p.location.registerhigh);
                     end
@@ -148,7 +148,7 @@ implementation
                 because otherwise secondload fails PM
               set_location(p^.left^.location,p^.location);}
            end;
-         ungetiftemp(href);
+         tg.ungetiftemp(href);
       end;
 {$endif TEMPS_NOT_PUSH}
 
@@ -192,7 +192,7 @@ implementation
                          cg.a_cmp_const_loc_label(exprasmlist,opsize,OC_NE,
                            0,p.location,truelabel);
                          { !!! should happen right after cmp (JM) }
-                         del_location(p.location);
+                         rg.del_location(exprasmlist,p.location);
                          cg.a_jmp_cond(exprasmlist,OC_NONE,falselabel);
                        end;
                      LOC_FLAGS :
@@ -213,7 +213,24 @@ end.
 
 {
   $Log$
-  Revision 1.2  2002-03-04 19:10:11  peter
+  Revision 1.3  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.2  2002/03/04 19:10:11  peter
     * removed compiler warnings
 
   Revision 1.1  2001/12/30 17:24:48  jonas

+ 47 - 94
compiler/nflw.pas

@@ -179,8 +179,8 @@ implementation
       globtype,systems,
       cutils,verbose,globals,
       symconst,symtable,types,htypechk,pass_1,
-      ncon,nmem,nld,ncnv,nbas,tgcpu,
-      cgbase,temp_gen
+      ncon,nmem,nld,ncnv,nbas,rgobj,
+      cgbase
       ;
 
     function genloopnode(t : tnodetype;l,r,n1 : tnode;back : boolean) : tnode;
@@ -293,16 +293,12 @@ implementation
          old_t_times : longint;
       begin
          result:=nil;
-         old_t_times:=t_times;
+         old_t_times:=rg.t_times;
 
          { calc register weight }
          if not(cs_littlesize in aktglobalswitches ) then
-           t_times:=t_times*8;
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+           rg.t_times:=rg.t_times*8;
+         rg.cleartempgen;
 
          firstpass(left);
          if codegenerror then
@@ -316,11 +312,7 @@ implementation
          { loop instruction }
          if assigned(right) then
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(right);
               if codegenerror then
                 exit;
@@ -335,7 +327,7 @@ implementation
 {$endif SUPPORT_MMX}
            end;
 
-         t_times:=old_t_times;
+         rg.t_times:=old_t_times;
       end;
 
 
@@ -376,12 +368,8 @@ implementation
          hp : tnode;
       begin
          result:=nil;
-         old_t_times:=t_times;
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         old_t_times:=rg.t_times;
+         rg.cleartempgen;
          firstpass(left);
          registers32:=left.registers32;
          registersfpu:=left.registersfpu;
@@ -391,18 +379,14 @@ implementation
 
          { determines registers weigths }
          if not(cs_littlesize in aktglobalswitches) then
-           t_times:=t_times div 2;
-         if t_times=0 then
-           t_times:=1;
+           rg.t_times:=rg.t_times div 2;
+         if rg.t_times=0 then
+           rg.t_times:=1;
 
          { if path }
          if assigned(right) then
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(right);
 
               if registers32<right.registers32 then
@@ -418,11 +402,7 @@ implementation
          { else path }
          if assigned(t1) then
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(t1);
 
               if registers32<t1.registers32 then
@@ -465,7 +445,7 @@ implementation
                 end;
            end;
 
-         t_times:=old_t_times;
+         rg.t_times:=old_t_times;
       end;
 
 
@@ -547,22 +527,14 @@ implementation
      begin
          result:=nil;
          { Calc register weight }
-         old_t_times:=t_times;
+         old_t_times:=rg.t_times;
          if not(cs_littlesize in aktglobalswitches) then
-           t_times:=t_times*8;
+           rg.t_times:=rg.t_times*8;
 
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(left);
 
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          if assigned(t1) then
           begin
             firstpass(t1);
@@ -584,11 +556,7 @@ implementation
 {$endif SUPPORT_MMX}
 
          { process count var }
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(t2);
          if codegenerror then
           exit;
@@ -601,11 +569,7 @@ implementation
            registersmmx:=t2.registersmmx;
 {$endif SUPPORT_MMX}
 
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(right);
          if right.registers32>registers32 then
            registers32:=right.registers32;
@@ -618,7 +582,7 @@ implementation
          { we need at least one register for comparisons PM }
          if registers32=0 then
            inc(registers32);
-         t_times:=old_t_times;
+         rg.t_times:=old_t_times;
       end;
 
 
@@ -818,11 +782,7 @@ implementation
          result:=nil;
          if assigned(left) then
           begin
-{$ifdef newcg}
-            tg.cleartempgen;
-{$else newcg}
-            cleartempgen;
-{$endif newcg}
+            rg.cleartempgen;
             firstpass(left);
             registers32:=left.registers32;
             registersfpu:=left.registersfpu;
@@ -964,20 +924,12 @@ implementation
     function ttryexceptnode.pass_1 : tnode;
       begin
          result:=nil;
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(left);
          { on statements }
          if assigned(right) then
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(right);
               registers32:=max(registers32,right.registers32);
               registersfpu:=max(registersfpu,right.registersfpu);
@@ -1024,18 +976,10 @@ implementation
     function ttryfinallynode.pass_1 : tnode;
       begin
          result:=nil;
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(left);
 
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(right);
          left_right_max;
       end;
@@ -1088,11 +1032,7 @@ implementation
     function tonnode.pass_1 : tnode;
       begin
          result:=nil;
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          registers32:=0;
          registersfpu:=0;
 {$ifdef SUPPORT_MMX}
@@ -1108,11 +1048,7 @@ implementation
 {$endif SUPPORT_MMX}
            end;
 
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          if assigned(right) then
            begin
               firstpass(right);
@@ -1177,7 +1113,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.27  2001-11-19 14:21:30  jonas
+  Revision 1.28  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.27  2001/11/19 14:21:30  jonas
     * upper constant limits for "for" loops are now also converted to the
       type of the counter var ('merged')
 

+ 19 - 2
compiler/ninl.pas

@@ -60,7 +60,7 @@ implementation
       symbase,symconst,symtype,symdef,symsym,symtable,types,
       pass_1,
       ncal,ncon,ncnv,nadd,nld,nbas,nflw,nmem,nmat,
-      cpubase,tgcpu,cgbase
+      cpubase,tgobj,cgbase
       ;
 
    function geninlinenode(number : byte;is_const:boolean;l : tnode) : tinlinenode;
@@ -2341,7 +2341,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.69  2002-01-24 18:25:48  peter
+  Revision 1.70  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.69  2002/01/24 18:25:48  peter
    * implicit result variable generation for assembler routines
    * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
 

+ 21 - 4
compiler/nld.pas

@@ -124,7 +124,7 @@ implementation
       cutils,verbose,globtype,globals,systems,
       symtable,types,
       htypechk,pass_1,
-      ncnv,nmem,ncal,cpubase,tgcpu,cgbase
+      ncnv,nmem,ncal,cpubase,rgobj,cgbase
       ;
 
 
@@ -351,10 +351,10 @@ implementation
                      if (assigned(tvarsym(symtableentry).owner) and assigned(aktprocsym)
                        and ((tvarsym(symtableentry).owner = aktprocdef.localst)
                        or (tvarsym(symtableentry).owner = aktprocdef.localst))) then }
-                   if t_times<1 then
+                   if rg.t_times<1 then
                      inc(tvarsym(symtableentry).refs)
                    else
-                     inc(tvarsym(symtableentry).refs,t_times);
+                     inc(tvarsym(symtableentry).refs,rg.t_times);
                 end;
             typedconstsym :
                 ;
@@ -911,7 +911,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.32  2002-01-19 11:52:32  peter
+  Revision 1.33  2002-03-31 20:26:34  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.32  2002/01/19 11:52:32  peter
     * dynarr:=nil support added
 
   Revision 1.31  2001/12/28 15:02:00  jonas

+ 26 - 3
compiler/node.pas

@@ -315,7 +315,7 @@ interface
           maxfirstpasscount,
           firstpasscount : longint;
 {$endif extdebug}
-          list : taasmoutput;
+{          list : taasmoutput; }
           constructor create(tt : tnodetype);
           { this constructor is only for creating copies of class }
           { the fields are copied by getcopy                      }
@@ -416,6 +416,12 @@ interface
      procedure writenode(t:tnode);
 {$endif EXTDEBUG}
 
+{$ifdef tempregdebug}
+    type
+      pptree = ^tnode;
+    var
+      curptree: pptree;
+{$endif tempregdebug}
 
 implementation
 
@@ -547,7 +553,7 @@ implementation
 {$ifdef extdebug}
          p.firstpasscount:=firstpasscount;
 {$endif extdebug}
-         p.list:=list;
+{         p.list:=list; }
          getcopy:=p;
       end;
 
@@ -805,7 +811,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.21  2002-01-19 11:52:32  peter
+  Revision 1.22  2002-03-31 20:26:35  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.21  2002/01/19 11:52:32  peter
     * dynarr:=nil support added
 
   Revision 1.20  2001/10/20 19:28:38  peter

+ 27 - 22
compiler/nset.pas

@@ -113,7 +113,7 @@ implementation
       verbose,globals,
       symconst,symdef,symsym,types,
       htypechk,pass_1,
-      ncnv,ncon,cpubase,nld,tgcpu,cgbase;
+      ncnv,ncon,cpubase,nld,rgobj,cgbase;
 
     function gencasenode(l,r : tnode;nodes : pcaserecord) : tnode;
 
@@ -461,11 +461,7 @@ implementation
       begin
          result:=nil;
          { evalutes the case expression }
-{$ifdef newcg}
-         tg.cleartempgen;
-{$else newcg}
-         cleartempgen;
-{$endif newcg}
+         rg.cleartempgen;
          firstpass(left);
          set_varstate(left,true);
          if codegenerror then
@@ -479,22 +475,18 @@ implementation
          { walk through all instructions }
 
          {   estimates the repeat of each instruction }
-         old_t_times:=t_times;
+         old_t_times:=rg.t_times;
          if not(cs_littlesize in aktglobalswitches) then
            begin
-              t_times:=t_times div case_count_labels(nodes);
-              if t_times<1 then
-                t_times:=1;
+              rg.t_times:=rg.t_times div case_count_labels(nodes);
+              if rg.t_times<1 then
+                rg.t_times:=1;
            end;
          { first case }
          hp:=tbinarynode(right);
          while assigned(hp) do
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(hp.right);
 
               { searchs max registers }
@@ -513,11 +505,7 @@ implementation
          { may be handle else tree }
          if assigned(elseblock) then
            begin
-{$ifdef newcg}
-              tg.cleartempgen;
-{$else newcg}
-              cleartempgen;
-{$endif newcg}
+              rg.cleartempgen;
               firstpass(elseblock);
               if codegenerror then
                 exit;
@@ -530,7 +518,7 @@ implementation
                 registersmmx:=elseblock.registersmmx;
 {$endif SUPPORT_MMX}
            end;
-         t_times:=old_t_times;
+         rg.t_times:=old_t_times;
 
          { there is one register required for the case expression    }
          { for 64 bit ints we cheat: the high dword is stored in EDI }
@@ -588,7 +576,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.17  2001-12-06 17:57:35  florian
+  Revision 1.18  2002-03-31 20:26:35  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.17  2001/12/06 17:57:35  florian
     + parasym to tparaitem added
 
   Revision 1.16  2001/10/12 13:51:51  jonas

+ 19 - 2
compiler/pass_1.pas

@@ -50,7 +50,7 @@ implementation
       verbose,
       htypechk,
 {$endif extdebug}
-      tgcpu
+      tgobj
       ;
 
 {*****************************************************************************
@@ -198,7 +198,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.18  2001-10-20 17:23:43  peter
+  Revision 1.19  2002-03-31 20:26:35  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.18  2001/10/20 17:23:43  peter
     * fixed firstpass when det_resulttype returns an error
 
   Revision 1.17  2001/09/02 21:18:28  peter

+ 23 - 6
compiler/pass_2.pas

@@ -53,7 +53,7 @@ implementation
      globtype,systems,verbose,
      cclasses,globals,
      symconst,symbase,symtype,symsym,aasm,
-     pass_1,cgbase,temp_gen,regvars,nflw,tgcpu;
+     pass_1,cgbase,regvars,nflw,rgobj;
 
 {*****************************************************************************
                               SecondPass
@@ -225,16 +225,16 @@ implementation
 
     procedure generatecode(var p : tnode);
       begin
-         cleartempgen;
+         rg.cleartempgen;
          flowcontrol:=[];
          { when size optimization only count occurrence }
          if cs_littlesize in aktglobalswitches then
-           t_times:=1
+           rg.t_times:=1
          else
            { reference for repetition is 100 }
-           t_times:=100;
+           rg.t_times:=100;
          { clear register count }
-         clearregistercount;
+         rg.clearregistercount;
          use_esp_stackframe:=false;
          symtablestack.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs);
          symtablestack.next.foreach_static({$ifdef FPCPROCVAR}@{$endif}clearrefs);
@@ -311,7 +311,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.21  2001-11-06 16:39:02  jonas
+  Revision 1.22  2002-03-31 20:26:35  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.21  2001/11/06 16:39:02  jonas
     * moved call to "cleanup_regvars" to cga.pas for i386 because it has
       to insert "fstp %st0" instructions after the exit label
 

+ 20 - 3
compiler/pexpr.pas

@@ -230,7 +230,7 @@ implementation
         consume(_LKLAMMER);
         p:=comp_expr(true);
         { calc return type }
-        { cleartempgen; }
+        { rg.cleartempgen; }
         set_varstate(p,(not is_new));
         { constructor,destructor specified }
         if try_to_consume(_COMMA) then
@@ -320,7 +320,7 @@ implementation
                   end;
 
                 { we need the real called method }
-                { cleartempgen;}
+                { rg.cleartempgen;}
                 do_resulttypepass(p2);
                 if not codegenerror then
                  begin
@@ -2452,7 +2452,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.58  2002-03-01 14:08:26  peter
+  Revision 1.59  2002-03-31 20:26:35  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.58  2002/03/01 14:08:26  peter
     * fixed sizeof(TClass) to return only 4
 
   Revision 1.57  2002/02/03 09:30:04  peter

+ 19 - 2
compiler/ppu.pas

@@ -41,7 +41,7 @@ type
 {$endif Test_Double_checksum}
 
 const
-  CurrentPPUVersion=25;
+  CurrentPPUVersion=27;
 
 { buffer sizes }
   maxentrysize = 1024;
@@ -987,7 +987,24 @@ end;
 end.
 {
   $Log$
-  Revision 1.15  2002-03-28 16:07:52  armin
+  Revision 1.16  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.15  2002/03/28 16:07:52  armin
   + initialize threadvars defined local in units
 
   Revision 1.14  2001/12/06 17:57:37  florian

+ 42 - 45
compiler/pstatmnt.pas

@@ -54,7 +54,7 @@ implementation
        scanner,
        pbase,pexpr,
        { codegen }
-       tgcpu,cgbase
+       rgobj,cgbase
 {$ifdef i386}
   {$ifndef NoRa386Int}
        ,ra386int
@@ -194,7 +194,7 @@ implementation
          consume(_CASE);
          caseexpr:=comp_expr(true);
        { determines result type }
-         cleartempgen;
+         rg.cleartempgen;
          do_resulttypepass(caseexpr);
          casedeferror:=false;
          casedef:=caseexpr.resulttype.def;
@@ -784,7 +784,6 @@ implementation
          { Read first the _ASM statement }
          consume(_ASM);
 
-{$ifndef newcg}
          { END is read }
          if try_to_consume(_LECKKLAMMER) then
            begin
@@ -796,50 +795,50 @@ implementation
                   uppervar(pattern);
 {$ifdef i386}
                   if pattern='EAX' then
-                    usedinproc:=usedinproc or ($80 shr byte(R_EAX))
+                    include(rg.usedinproc,R_EAX)
                   else if pattern='EBX' then
-                    usedinproc:=usedinproc or ($80 shr byte(R_EBX))
+                    include(rg.usedinproc,R_EBX)
                   else if pattern='ECX' then
-                    usedinproc:=usedinproc or ($80 shr byte(R_ECX))
+                    include(rg.usedinproc,R_ECX)
                   else if pattern='EDX' then
-                    usedinproc:=usedinproc or ($80 shr byte(R_EDX))
+                    include(rg.usedinproc,R_EDX)
                   else if pattern='ESI' then
                     begin
-                       usedinproc:=usedinproc or ($80 shr byte(R_ESI));
+                       include(rg.usedinproc,R_ESI);
                        exclude(asmstat.flags,nf_object_preserved);
                     end
                   else if pattern='EDI' then
-                    usedinproc:=usedinproc or ($80 shr byte(R_EDI))
+                    include(rg.usedinproc,R_EDI)
 {$endif i386}
 {$ifdef m68k}
                   if pattern='D0' then
-                    usedinproc:=usedinproc +[R_D0]
+                    include(rg.usedinproc,R_D0)
                   else if pattern='D1' then
-                    usedinproc:=usedinproc + [R_D1]
+                    include(rg.usedinproc,R_D1)
                   else if pattern='D2' then
-                    usedinproc:=usedinproc + [R_D2]
+                    include(rg.usedinproc,R_D2)
                   else if pattern='D3' then
-                    usedinproc:=usedinproc + [R_D3]
+                    include(rg.usedinproc,R_D3)
                   else if pattern='D4' then
-                    usedinproc:=usedinproc + [R_D4]
+                    include(rg.usedinproc,R_D4)
                   else if pattern='D5' then
-                    usedinproc:=usedinproc + [R_D5]
+                    include(rg.usedinproc,R_D5)
                   else if pattern='D6' then
-                    usedinproc:=usedinproc + [R_D6]
+                    include(rg.usedinproc,R_D6)
                   else if pattern='D7' then
-                    usedinproc:=usedinproc + [R_D7]
+                    include(rg.usedinproc,R_D7)
                   else if pattern='A0' then
-                    usedinproc:=usedinproc + [R_A0]
+                    include(rg.usedinproc,R_A0)
                   else if pattern='A1' then
-                    usedinproc:=usedinproc + [R_A1]
+                    include(rg.usedinproc,R_A1)
                   else if pattern='A2' then
-                    usedinproc:=usedinproc + [R_A2]
+                    include(rg.usedinproc,R_A2)
                   else if pattern='A3' then
-                    usedinproc:=usedinproc + [R_A3]
+                    include(rg.usedinproc,R_A3)
                   else if pattern='A4' then
-                    usedinproc:=usedinproc + [R_A4]
+                    include(rg.usedinproc,R_A4)
                   else if pattern='A5' then
-                    usedinproc:=usedinproc + [R_A5]
+                    include(rg.usedinproc,R_A5)
 {$endif m68k}
 {$ifdef powerpc}
                   if pattern<>'' then
@@ -852,16 +851,7 @@ implementation
                 until false;
               consume(_RECKKLAMMER);
            end
-{$ifdef i386}
-         else usedinproc:=$ff;
-{$else}
-{$ifdef powerpc}
-         else usedinproc := 0;
-{$else powerpc}
-         else usedinproc := ALL_REGISTERS;
-{$endif powerpc}
-{$endif i386}
-{$endif newcg}
+         else rg.usedinproc := [firstreg..lastreg];
 
          { mark the start and the end of the assembler block
            this is needed for the optimizer }
@@ -1168,17 +1158,7 @@ implementation
                symtablestack.datasize:=0;
               { set the used flag for the return }
               if ret_in_acc(aktprocdef.rettype.def) then
-                begin
-{$ifdef i386}
-                   usedinproc:=usedinproc or ($80 shr byte(R_EAX))
-{$else}
-  {$ifdef POWERPC}
-                   usedinproc:=0;
-  {$else POWERPC}
-                   usedinproc:=usedinproc + [accumulator];
-  {$endif POWERPC}
-{$endif i386}
-                end;
+                 include(rg.usedinproc,accumulator);
             end;
          { force the asm statement }
          if token<>_ASM then
@@ -1222,7 +1202,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.48  2002-03-11 19:10:28  peter
+  Revision 1.49  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.48  2002/03/11 19:10:28  peter
     * Regenerated with updated fpcmake
 
   Revision 1.47  2002/03/04 17:54:59  peter

+ 32 - 64
compiler/psub.pas

@@ -47,7 +47,7 @@ implementation
        globtype,globals,tokens,verbose,comphook,
        systems,
        { aasm }
-       cpubase,aasm,
+       cpubase,cpuinfo,aasm,
        { symtable }
        symconst,symbase,symdef,symsym,symtype,symtable,types,
        ppu,fmodule,
@@ -62,8 +62,8 @@ implementation
        scanner,
        pbase,pstatmnt,pdecl,pdecsub,pexports,
        { codegen }
-       tgcpu,cgbase,
-       temp_gen,
+       tgobj,cgbase,rgobj,
+       rgcpu,
        cga
        {$ifndef NOOPT}
          {$ifdef i386}
@@ -72,9 +72,6 @@ implementation
            ,aoptcpu
          {$endif i386}
        {$endif}
-{$ifdef newcg}
-       ,cgobj
-{$endif newcg}
        ;
 
 
@@ -141,20 +138,10 @@ implementation
                       assigned(otsym) then
                      otsym.address:=-procinfo^.return_offset;
                    { eax is modified by a function }
-{$ifndef newcg}
-{$ifdef i386}
-                   usedinproc:=usedinproc or ($80 shr byte(R_EAX));
-
-                   if is_64bitint(aktprocdef.rettype.def) then
-                     usedinproc:=usedinproc or ($80 shr byte(R_EDX))
-{$endif}
-{$ifdef m68k}
-                   usedinproc:=usedinproc + [accumulator];
-
-                   if is_64bitint(aktprocdef.rettype.def) then
-                     usedinproc:=usedinproc  + [scratch_reg];
-{$endif}
-{$endif newcg}
+                   include(rg.usedinproc,accumulator);
+                   if (sizeof(aword) < 8) and
+                      (is_64bitint(aktprocdef.rettype.def)) then
+                     include(rg.usedinproc,accumulatorhigh);
                 end;
            end;
 
@@ -293,22 +280,9 @@ implementation
          constsymtable:=symtablestack;
 
          { reset the temporary memory }
-         cleartempgen;
+         rg.cleartempgen;
 
-{$ifdef newcg}
-{$ifdef POWERPC}
-         tgcpu.usedinproc:=0;
-{$else POWERPC}
-         tg.usedinproc:=[];
-{$endif POWERPC}
-{$else newcg}
-{$ifdef i386}
-        { no registers are used }
-        usedinproc:=0;
-{$else}
-        usedinproc := [];
-{$endif}
-{$endif newcg}
+         rg.usedinproc:=[];
          { save entry info }
          entrypos:=aktfilepos;
          entryswitches:=aktlocalswitches;
@@ -332,11 +306,7 @@ implementation
          { set the framepointer to esp for assembler functions }
          { but only if the are no local variables           }
          { already done in assembler_block }
-{$ifdef newcg}
-         setfirsttemp(procinfo^.firsttemp_offset);
-{$else newcg}
-         setfirsttemp(procinfo^.firsttemp_offset);
-{$endif newcg}
+         tg.setfirsttemp(procinfo^.firsttemp_offset);
 
          { ... and generate assembler }
          { but set the right switches for entry !! }
@@ -355,11 +325,7 @@ implementation
               begin
                 generatecode(code);
                 aktprocdef.code:=code;
-{$ifdef newcg}
-                stackframe:=gettempsize;
-{$else newcg}
-                stackframe:=gettempsize;
-{$endif newcg}
+                stackframe:=tg.gettempsize;
 
                 { first generate entry code with the correct position and switches }
                 aktfilepos:=entrypos;
@@ -373,11 +339,7 @@ implementation
                 { FPC_POPADDRSTACK destroys all registers (JM) }
                 if (procinfo^.flags and (pi_needs_implicit_finally or pi_uses_exceptions)) <> 0 then
                  begin
-{$ifdef i386}
-                   usedinproc := $ff;
-{$else}
-                   usedinproc := ALL_REGISTERS;
-{$endif}
+                   rg.usedinproc := ALL_REGISTERS;
                  end;
 
                 { now generate exit code with the correct position and switches }
@@ -390,11 +352,7 @@ implementation
 {$endif newcg}
 
                 { now all the registers used are known }
-{$ifdef newcg}
-                aktprocdef.usedregisters:=tg.usedinproc;
-{$else newcg}
-                aktprocdef.usedregisters:=usedinproc;
-{$endif newcg}
+                aktprocdef.usedregisters:=rg.usedinproc;
                 procinfo^.aktproccode.insertlist(procinfo^.aktentrycode);
                 procinfo^.aktproccode.concatlist(procinfo^.aktexitcode);
 {$ifdef i386}
@@ -471,17 +429,10 @@ implementation
              aktprocdef.localst:=nil;
            end;
 
-{$ifdef newcg}
          { all registers can be used again }
-         tg.resetusableregisters;
+         rg.resetusableregisters;
          { only now we can remove the temps }
          tg.resettempgen;
-{$else newcg}
-         { all registers can be used again }
-         resetusableregisters;
-         { only now we can remove the temps }
-         resettempgen;
-{$endif newcg}
 
          { remove code tree, if not inline procedure }
          if assigned(code) and (aktprocdef.proccalloption<>pocall_inline) then
@@ -868,7 +819,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.44  2002-01-19 15:37:24  peter
+  Revision 1.45  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.44  2002/01/19 15:37:24  peter
     * commited the wrong file :(
 
   Revision 1.43  2002/01/19 15:20:09  peter

+ 44 - 31
compiler/regvars.pas

@@ -30,7 +30,7 @@ interface
        aasm,
        node,
        symsym,
-       cpubase, tgcpu;
+       cpubase, tgobj, rgobj;
 
     procedure assign_regvars(p: tnode);
     procedure load_regvars(asml: TAAsmoutput; p: tnode);
@@ -49,11 +49,18 @@ implementation
       globtype,systems,comphook,
       cutils,cclasses,verbose,globals,
       symconst,symbase,symtype,symdef,types,
-      tainst,cgbase,cpuasm,cgobj,cgcpu,cga;
+      tainst,cgbase,cpuasm,cgobj,cgcpu,cga,rgcpu;
 
     var
       parasym : boolean;
 
+{$ifndef i386}
+    function makereg32(const reg: tregister): tregister;
+      begin
+        makereg32 := reg;
+      end;
+{$endif i386}
+
     procedure searchregvars(p : tnamedindexitem);
       var
          i,j,k : longint;
@@ -163,15 +170,13 @@ implementation
               for i:=1 to maxvarregs-p.registers32 do
                 begin
                   if assigned(regvarinfo^.regvars[i]) and
-                    (reg_pushes[varregs[i]] < regvarinfo^.regvars[i].refs) then
+                    (rg.reg_pushes[varregs[i]] < regvarinfo^.regvars[i].refs) then
                     begin
                       { register is no longer available for }
                       { expressions                          }
                       { search the register which is the most }
-                      { unused                                        }
-                      usableregs:=usableregs-[varregs[i]];
-                      is_reg_var[varregs[i]]:=true;
-                      dec(c_usableregs);
+                      { unused                                }
+                      rg.makeregvar(varregs[i]);
 
                       { possibly no 32 bit register are needed }
                       { call by reference/const ? }
@@ -199,14 +204,8 @@ implementation
                         begin
                           regvarinfo^.regvars[i].reg:=varregs[i];
                         end;
-                      if regvarinfo^.regvars_para[i] then
-                        unused:=unused - [regvarinfo^.regvars[i].reg];
                       { procedure uses this register }
-{$ifdef i386}
-                      usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
-{$else i386}
-                      usedinproc:=usedinproc + [varregs[i]];
-{$endif i386}
+                      include(rg.usedinproc,varregs[i]);
                     end
                   else
                     begin
@@ -253,9 +252,9 @@ implementation
                      begin
 {$ifdef i386}
                        { reserve place on the FPU stack }
-                       regvarinfo^.fpuregvars[i].reg:=correct_fpuregister(R_ST0,i-1);
+                       regvarinfo^.fpuregvars[i].reg:=trgcpu(rg).correct_fpuregister(R_ST0,i);
 {$else i386}
-                       regvarinfo^.fpuregvars[i].reg:=fpuvarregs[i];
+                       rg.makeregvar(fpuregvars[i]);
 {$endif i386}
                      end;
                   end;
@@ -278,7 +277,7 @@ implementation
         if assigned(regvarinfo^.regvars[i]) and
            (makereg32(regvarinfo^.regvars[i].reg) = reg) then
           begin
-            if regvar_loaded[makereg32(reg)] then
+            if rg.regvar_loaded[makereg32(reg)] then
               begin
                 vsym := tvarsym(regvarinfo^.regvars[i]);
                 { we only have to store the regvar back to memory if it's }
@@ -291,10 +290,9 @@ implementation
                     else hr.offset:=vsym.address+vsym.owner.address_fixup;
                     hr.base:=procinfo^.framepointer;
                     cg.a_load_reg_ref(asml,def_cgsize(vsym.vartype.def),vsym.reg,hr);
-{                    asml.concat(Taicpu.op_reg_ref(A_MOV,regsize(vsym.reg),vsym.reg,hr)); }
                   end;
                 asml.concat(Tairegalloc.dealloc(makereg32(reg)));
-                regvar_loaded[makereg32(reg)] := false;
+                rg.regvar_loaded[makereg32(reg)] := false;
               end;
             break;
           end;
@@ -305,7 +303,7 @@ implementation
       hr: treference;
       opsize: tcgsize;
     begin
-      if not regvar_loaded[makereg32(vsym.reg)] then
+      if not rg.regvar_loaded[makereg32(vsym.reg)] then
         begin
           asml.concat(Tairegalloc.alloc(makereg32(vsym.reg)));
           reset_reference(hr);
@@ -316,13 +314,11 @@ implementation
           if (vsym.varspez in [vs_var,vs_out]) or
              ((vsym.varspez=vs_const) and
                push_addr_param(vsym.vartype.def)) then
-            {FIXME!!! Needs to be OS_SIZE_OF_POINTER (JM) }
-            opsize := OS_32
+            opsize := OS_ADDR
           else
             opsize := def_cgsize(vsym.vartype.def);
           cg.a_load_ref_reg(asml,opsize,hr,makereg32(vsym.reg));
-{          asml.concat(Taicpu.op_ref_reg(opcode,opsize,hr,makereg32(vsym.reg))); }
-          regvar_loaded[makereg32(vsym.reg)] := true;
+          rg.regvar_loaded[makereg32(vsym.reg)] := true;
         end;
     end;
 
@@ -350,8 +346,8 @@ implementation
       if not assigned(regvarinfo) then
         exit;
       for i := 1 to maxvarregs do
-        if assigned(regvarinfo^.regvars[i]) and
-           (makereg32(regvarinfo^.regvars[i].reg) in [R_EAX,R_EBX,R_ECX,R_EDX]) then
+        if assigned(regvarinfo^.regvars[i]) {and
+           (makereg32(regvarinfo^.regvars[i].reg) in [R_EAX,R_EBX,R_ECX,R_EDX])} then
           load_regvar(asml,tvarsym(regvarinfo^.regvars[i]))
     end;
 
@@ -387,7 +383,7 @@ implementation
                 begin
 {$ifdef i386}
                   { reserve place on the FPU stack }
-                  regvarinfo^.fpuregvars[i].reg:=correct_fpuregister(R_ST0,i-1);
+                  regvarinfo^.fpuregvars[i].reg:=trgcpu(rg).correct_fpuregister(R_ST0,i-1);
                   asml.concat(Taicpu.op_none(A_FLDZ,S_NO));
 {$endif i386}
                 end;
@@ -422,9 +418,9 @@ implementation
     var
       counter: tregister;
     begin
-      for counter := low(regvar_loaded) to high(regvar_loaded) do
+      for counter := low(rg.regvar_loaded) to high(rg.regvar_loaded) do
         begin
-           regvar_loaded[counter] := regvarsloaded1[counter] and
+           rg.regvar_loaded[counter] := regvarsloaded1[counter] and
              regvarsloaded2[counter];
            if regvarsloaded1[counter] xor regvarsloaded2[counter] then
              if regvarsloaded1[counter] then
@@ -454,7 +450,7 @@ implementation
 {$endif i386}
             for i := 1 to maxvarregs do
               if assigned(regvars[i]) and
-                 (regvar_loaded[makereg32(regvars[i].reg)]) then
+                 (rg.regvar_loaded[makereg32(regvars[i].reg)]) then
                 asml.concat(Tairegalloc.dealloc(makereg32(regvars[i].reg)));
           end;
     end;
@@ -463,7 +459,24 @@ end.
 
 {
   $Log$
-  Revision 1.22  2001-12-29 15:32:13  jonas
+  Revision 1.23  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.22  2001/12/29 15:32:13  jonas
     * powerpc/cgcpu.pas compiles :)
     * several powerpc-related fixes
     * cpuasm unit is now based on common tainst unit

+ 799 - 0
compiler/rgobj.pas

@@ -0,0 +1,799 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the base class for the register allocator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+{$i defines.inc}
+
+unit rgobj;
+
+  interface
+
+    uses
+      cpubase,
+      cpuinfo,
+      cpuasm,
+      tainst,
+      cclasses,globtype,cgbase,aasm,node;
+
+    type
+       regvar_longintarray = array[firstreg..lastreg] of longint;
+       regvar_booleanarray = array[firstreg..lastreg] of boolean;
+       regvar_ptreearray = array[firstreg..lastreg] of tnode;
+
+       tpushedsavedloc = record
+         case byte of
+           0: (pushed: boolean);
+           1: (ofs: longint);
+       end;
+
+       tpushedsaved = array[lowsavereg..highsavereg] of tpushedsavedloc;
+
+       trgobj = class
+          { The "usableregsxxx" contain all registers of type "xxx" that }
+          { aren't currently allocated to a regvar. The "unusedregsxxx"  }
+          { contain all registers of type "xxx" that aren't currenly     }
+          { allocated                                                    }
+          unusedregsint,usableregsint : tregisterset;
+          unusedregsfpu,usableregsfpu : tregisterset;
+          unusedregsmm,usableregsmm : tregisterset;
+          { these counters contain the number of elements in the }
+          { unusedregsxxx/usableregsxxx sets                     }
+          countunusedregsint,
+          countunusedregsfpu,
+          countunusedregsmm : byte;
+          countusableregsint,
+          countusableregsfpu,
+          countusableregsmm : byte;
+
+          usedinproc : tregisterset;
+
+          reg_pushes : regvar_longintarray;
+          is_reg_var : regvar_booleanarray;
+          regvar_loaded: regvar_booleanarray;
+
+
+          { tries to hold the amount of times which the current tree is processed  }
+          t_times: longint;
+
+          constructor create;
+
+          function getregisterint(list: taasmoutput) : tregister; virtual;
+          procedure ungetregisterint(list: taasmoutput; r : tregister); virtual;
+
+          function getregisterfpu(list: taasmoutput) : tregister; virtual;
+          procedure ungetregisterfpu(list: taasmoutput; r : tregister); virtual;
+
+          function getregistermm(list: taasmoutput) : tregister; virtual;
+          procedure ungetregistermm(list: taasmoutput; r : tregister); virtual;
+
+          function getaddressregister(list: taasmoutput): tregister; virtual;
+          procedure ungetaddressregister(list: taasmoutput; r: tregister); virtual;
+          { the following must only be called for address and integer }
+          { registers, otherwise the result is undefined              }
+          function isaddressregister(reg: tregister): boolean; virtual;
+
+          { tries to allocate the passed register, if possible }
+          function getexplicitregisterint(list: taasmoutput; r : tregister) : tregister;virtual;
+
+          { deallocate any kind of register }
+          procedure ungetregister(list: taasmoutput; r : tregister); virtual;
+
+          { reset the register allocator information (usable registers etc) }
+          procedure cleartempgen;virtual;
+
+          { deallocate the registers of a reference }
+          procedure del_reference(list: taasmoutput; const ref : treference);virtual;
+
+          { deallocate the registers of a location if it's a reference }
+          procedure del_locref(list: taasmoutput; const location : tlocation);
+
+          { deallocate the registers of a location }
+          procedure del_location(list: taasmoutput; const l : tlocation);
+
+          { saves register variables (restoring happens automatically) }
+          procedure saveregvars(list: taasmoutput; const s: tregisterset);
+
+          { saves and restores used registers }
+          procedure saveusedregisters(list: taasmoutput;
+            var saved : tpushedsaved;const s: tregisterset);virtual;
+          procedure restoreusedregisters(list: taasmoutput;
+            const saved : tpushedsaved);virtual;
+
+          { used when deciding which registers to use for regvars }
+          procedure incrementregisterpushed(const s: tregisterset);
+          procedure clearregistercount;
+          procedure resetusableregisters;virtual;
+
+          procedure makeregvar(reg: tregister);
+
+          procedure saveStateForInline(var state: pointer);
+          procedure restoreStateAfterInline(var state: pointer);
+
+          procedure saveUnusedState(var state: pointer);
+          procedure restoreUnusedState(var state: pointer);
+       protected
+          { the following two contain the common (generic) code for all }
+          { get- and ungetregisterxxx functions/procedures              }
+          function getregistergen(list: taasmoutput; const lowreg, highreg: tregister;
+              var unusedregs: tregisterset; var countunusedregs: byte): tregister;
+          procedure ungetregistergen(list: taasmoutput; const r: tregister;
+              const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
+{$ifdef TEMPREGDEBUG}
+         reg_user   : regvar_ptreearray;
+         reg_releaser : regvar_ptreearray;
+{$endif TEMPREGDEBUG}
+
+{$ifdef TEMPREGDEBUG}
+          procedure testregisters;
+{$endif TEMPREGDEBUGx}
+       end;
+
+     const
+       { this value is used in tsaved, if the register isn't saved }
+       reg_not_saved = $7fffffff;
+
+     var
+       rg: trgobj;
+
+
+  implementation
+
+    uses
+       systems,
+       globals,verbose,
+       cgobj,tgobj,regvars;
+
+    type
+      psavedstate = ^tsavedstate;
+      tsavedstate = record
+        unusedregsint,usableregsint : tregisterset;
+        unusedregsfpu,usableregsfpu : tregisterset;
+        unusedregsmm,usableregsmm : tregisterset;
+        countunusedregsint,
+        countunusedregsfpu,
+        countunusedregsmm : byte;
+        countusableregsint,
+        countusableregsfpu,
+        countusableregsmm : byte;
+        usedinproc : tregisterset;
+        reg_pushes : regvar_longintarray;
+        is_reg_var : regvar_booleanarray;
+        regvar_loaded: regvar_booleanarray;
+{$ifdef TEMPREGDEBUG}
+         reg_user   : regvar_ptreearray;
+         reg_releaser : regvar_ptreearray;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+      punusedstate = ^tsavedstate;
+      tunusedstate = record
+        unusedregsint : tregisterset;
+        unusedregsfpu : tregisterset;
+        unusedregsmm : tregisterset;
+        countunusedregsint,
+        countunusedregsfpu,
+        countunusedregsmm : byte;
+      end;
+
+
+    constructor trgobj.create;
+
+     begin
+       usedinproc := [];
+       t_times := 0;
+       resetusableregisters;
+{$ifdef TEMPREGDEBUG}
+       fillchar(reg_user,sizeof(reg_user),0);
+       fillchar(reg_releaser,sizeof(reg_releaser),0);
+{$endif TEMPREGDEBUG}
+     end;
+
+
+    function trgobj.getregistergen(list: taasmoutput; const lowreg, highreg: tregister;
+        var unusedregs: tregisterset; var countunusedregs: byte): tregister;
+      var
+        i: tregister;
+      begin
+         for i:=lowreg to highreg do
+           begin
+              if i in unusedregs then
+                begin
+                   exclude(unusedregs,i);
+                   include(usedinproc,i);
+                   dec(countunusedregs);
+                   list.concat(tairegalloc.alloc(i));
+                   result := i;
+                   exit;
+                end;
+           end;
+         internalerror(10);
+      end;
+
+
+    procedure trgobj.ungetregistergen(list: taasmoutput; const r: tregister;
+        const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
+      begin
+         { takes much time }
+         if not(r in usableregs) then
+           exit;
+{$ifdef TEMPREGDEBUG}
+         if (r in unusedregs) then
+{$ifdef EXTTEMPREGDEBUG}
+           begin
+             Comment(V_Debug,'register freed twice '+reg2str(r));
+             testregisters32;
+             exit;
+           end
+{$else EXTTEMPREGDEBUG}
+           exit
+{$endif EXTTEMPREGDEBUG}
+         else
+{$endif TEMPREGDEBUG}
+          inc(countunusedregs);
+        include(unusedregs,r);
+        list.concat(tairegalloc.dealloc(r));
+      end;
+
+
+    function trgobj.getregisterint(list : taasmoutput) : tregister;
+
+      begin
+         if countunusedregsint=0 then
+           internalerror(10);
+{$ifdef TEMPREGDEBUG}
+         if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
+           internalerror(10);
+{$endif TEMPREGDEBUG}
+{$ifdef EXTTEMPREGDEBUG}
+         if curptree^^.usableregs-countunusedregsint>curptree^^.reallyusedregs then
+           curptree^^.reallyusedregs:=curptree^^.usableregs-countunusedregsint;
+{$endif EXTTEMPREGDEBUG}
+         result := getregistergen(list,firstsaveintreg,lastsaveintreg,
+                     unusedregsint,countunusedregsint);
+{$ifdef TEMPREGDEBUG}
+         reg_user[result]:=curptree^;
+         testregisters32;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
+
+      begin
+         ungetregistergen(list,r,usableregsint,unusedregsint,
+           countunusedregsint);
+{$ifdef TEMPREGDEBUG}
+        reg_releaser[r]:=curptree^;
+        testregisters32;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    { tries to allocate the passed register, if possible }
+    function trgobj.getexplicitregisterint(list : taasmoutput; r : tregister) : tregister;
+
+      begin
+         if r in unusedregsint then
+           begin
+              dec(countunusedregsint);
+{$ifdef TEMPREGDEBUG}
+              if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
+                internalerror(10);
+              reg_user[r]:=curptree^;
+{$endif TEMPREGDEBUG}
+              exclude(unusedregsint,r);
+              include(usedinproc,r);
+              list.concat(tairegalloc.alloc(r));
+              getexplicitregisterint:=r;
+{$ifdef TEMPREGDEBUG}
+              testregisters32;
+{$endif TEMPREGDEBUG}
+           end
+         else
+           getexplicitregisterint:=getregisterint(list);
+      end;
+
+
+    function trgobj.getregisterfpu(list: taasmoutput) : tregister;
+      begin
+        if countunusedregsfpu=0 then
+           internalerror(10);
+       result := getregistergen(list,firstsavefpureg,lastsavefpureg,
+                   unusedregsfpu,countunusedregsfpu);
+      end;
+
+
+    procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister);
+
+      begin
+         ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
+           countunusedregsfpu);
+      end;
+
+
+    function trgobj.getregistermm(list: taasmoutput) : tregister;
+      begin
+        if countunusedregsmm=0 then
+           internalerror(10);
+       result := getregistergen(list,firstsavemmreg,lastsavemmreg,
+                   unusedregsmm,countunusedregsmm);
+      end;
+
+
+    procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
+      begin
+       ungetregistergen(list,r,usableregsmm,unusedregsmm,
+         countunusedregsmm);
+      end;
+
+
+    function trgobj.getaddressregister(list: taasmoutput): tregister;
+      begin
+        result := getregisterint(list);
+      end;
+
+
+    procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
+      begin
+        ungetregisterint(list,r);
+      end;
+
+
+    function trgobj.isaddressregister(reg: tregister): boolean;
+      begin
+        result := true;
+      end;
+
+
+    procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
+
+      begin
+         if r in intregs then
+           ungetregisterint(list,r)
+         else if r in fpuregs then
+           ungetregisterfpu(list,r)
+         else if r in mmregs then
+           ungetregistermm(list,r)
+         else internalerror(18);
+      end;
+
+
+    procedure trgobj.cleartempgen;
+
+      begin
+         countunusedregsint:=countusableregsint;
+         countunusedregsfpu:=countusableregsfpu;
+         countunusedregsmm:=countusableregsmm;
+         unusedregsint:=usableregsint;
+         unusedregsfpu:=usableregsfpu;
+         unusedregsmm:=usableregsmm;
+      end;
+
+
+    procedure trgobj.del_reference(list : taasmoutput; const ref : treference);
+
+      begin
+         ungetregister(list,ref.base);
+         ungetregister(list,ref.index);
+      end;
+
+
+    procedure trgobj.del_locref(list : taasmoutput; const location : tlocation);
+
+      begin
+         if (location.loc<>LOC_MEM) and (location.loc<>LOC_REFERENCE) then
+           exit;
+         del_reference(list,location.reference);
+      end;
+
+
+    procedure trgobj.del_location(list : taasmoutput; const l : tlocation);
+
+      begin
+         case l.loc of
+           LOC_REGISTER :
+             ungetregister(list,l.register);
+           LOC_MEM,LOC_REFERENCE :
+             del_reference(list,l.reference);
+         end;
+      end;
+
+
+    procedure trgobj.saveregvars(list: taasmoutput; const s: tregisterset);
+      var
+        r: tregister;
+      begin
+        if not(cs_regalloc in aktglobalswitches) then
+          exit;
+        for r := firstsaveintreg to lastsaveintreg do
+          if is_reg_var[r] and
+             (r in s) then
+            store_regvar(list,r);
+        if firstsavefpureg <> R_NO then
+          for r := firstsavefpureg to lastsavefpureg do
+            if is_reg_var[r] and
+               (r in s) then
+              store_regvar(list,r);
+        if firstsavemmreg <> R_NO then
+          for r := firstsavemmreg to lastsavemmreg do
+            if is_reg_var[r] and
+               (r in s) then
+              store_regvar(list,r);
+      end;
+
+
+    procedure trgobj.saveusedregisters(list: taasmoutput;
+        var saved : tpushedsaved; const s: tregisterset);
+
+      var
+         r : tregister;
+         hr : treference;
+
+      begin
+        usedinproc:=usedinproc + s;
+        for r:=firstsaveintreg to lastsaveintreg do
+          begin
+            saved[r].ofs:=reg_not_saved;
+            { if the register is used by the calling subroutine and if }
+            { it's not a regvar (those are handled separately)         }
+            if not is_reg_var[r] and
+               (r in s) and
+               { and is present in use }
+               not(r in unusedregsint) then
+              begin
+                { then save it }
+                tg.gettempofsizereferencepersistant(list,sizeof(aword),hr);
+                saved[r].ofs:=hr.offset;
+                cg.a_load_reg_ref(list,OS_INT,r,hr);
+                cg.a_reg_dealloc(list,r);
+                include(unusedregsint,r);
+                inc(countunusedregsint);
+              end;
+          end;
+
+        { don't try to save the fpu registers if not desired (e.g. for }
+        { the 80x86)                                                   }
+        if firstsavefpureg <> R_NO then
+          for r:=firstsavefpureg to lastsavefpureg do
+            begin
+              saved[r].ofs:=reg_not_saved;
+              { if the register is used by the calling subroutine and if }
+              { it's not a regvar (those are handled separately)         }
+              if not is_reg_var[r] and
+                 (r in s) and
+                 { and is present in use }
+                 not(r in unusedregsfpu) then
+                begin
+                  { then save it }
+                  tg.gettempofsizereferencepersistant(list,extended_size,hr);
+                  saved[r].ofs:=hr.offset;
+                  cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
+                  cg.a_reg_dealloc(list,r);
+                  include(unusedregsfpu,r);
+                  inc(countunusedregsfpu);
+                end;
+            end;
+
+        { don't save the vector registers if there's no support for them }
+        if firstsavemmreg <> R_NO then
+          for r:=firstsavemmreg to lastsavemmreg do
+            begin
+              saved[r].ofs:=reg_not_saved;
+              { if the register is in use and if it's not a regvar (those }
+              { are handled separately), save it                          }
+              if not is_reg_var[r] and
+                 (r in s) and
+                 { and is present in use }
+                 not(r in unusedregsmm) then
+                begin
+                  { then save it }
+                  tg.gettempofsizereferencepersistant(list,mmreg_size,hr);
+                  saved[r].ofs:=hr.offset;
+                  cg.a_loadmm_reg_ref(list,r,hr);
+                  cg.a_reg_dealloc(list,r);
+                  include(unusedregsmm,r);
+                  inc(countunusedregsmm);
+               end;
+            end;
+{$ifdef TEMPREGDEBUG}
+        testregisters32;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    procedure trgobj.restoreusedregisters(list : taasmoutput;
+        const saved : tpushedsaved);
+
+      var
+         r : tregister;
+         hr : treference;
+
+      begin
+        if firstsavemmreg <> R_NO then
+          for r:=lastsavemmreg downto firstsavemmreg do
+            begin
+              if saved[r].ofs <> reg_not_saved then
+                begin
+                  reset_reference(hr);
+                  hr.base:=frame_pointer;
+                  hr.offset:=saved[r].ofs;
+                  cg.a_reg_alloc(list,r);
+                  cg.a_loadmm_ref_reg(list,hr,r);
+                  if not (r in unusedregsmm) then
+                    { internalerror(10)
+                      in n386cal we always save/restore the reg *state*
+                      using save/restoreunusedstate -> the current state
+                      may not be real (JM) }
+                  else
+                    begin
+                      dec(countunusedregsmm);
+                      exclude(unusedregsmm,r);
+                    end;
+                  tg.ungetpersistanttemp(list,hr.offset);
+                end;
+            end;
+
+        if firstsavefpureg <> R_NO then
+          for r:=lastsavefpureg downto firstsavefpureg do
+            begin
+              if saved[r].ofs <> reg_not_saved then
+                begin
+                  reset_reference(hr);
+                  hr.base:=frame_pointer;
+                  hr.offset:=saved[r].ofs;
+                  cg.a_reg_alloc(list,r);
+                  cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
+                  if not (r in unusedregsfpu) then
+                    { internalerror(10)
+                      in n386cal we always save/restore the reg *state*
+                      using save/restoreunusedstate -> the current state
+                      may not be real (JM) }
+                  else
+                    begin
+                      dec(countunusedregsfpu);
+                      exclude(unusedregsfpu,r);
+                    end;
+                  tg.ungetpersistanttemp(list,hr.offset);
+                end;
+            end;
+
+        for r:=lastsaveintreg downto firstsaveintreg do
+          begin
+            if saved[r].ofs <> reg_not_saved then
+              begin
+                reset_reference(hr);
+                hr.base:=frame_pointer;
+                hr.offset:=saved[r].ofs;
+                cg.a_reg_alloc(list,r);
+                cg.a_load_ref_reg(list,OS_INT,hr,r);
+                if not (r in unusedregsint) then
+                  { internalerror(10)
+                    in n386cal we always save/restore the reg *state*
+                    using save/restoreunusedstate -> the current state
+                    may not be real (JM) }
+                else
+                  begin
+                    dec(countunusedregsint);
+                    exclude(unusedregsint,r);
+                  end;
+                tg.ungetpersistanttemp(list,hr.offset);
+              end;
+          end;
+{$ifdef TEMPREGDEBUG}
+        testregisters32;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    procedure trgobj.incrementregisterpushed(const s: tregisterset);
+
+      var
+         regi : tregister;
+
+      begin
+         for regi:=firstsaveintreg to lastsaveintreg do
+           begin
+              if (regi in s) then
+                inc(reg_pushes[regi],t_times*2);
+           end;
+         if firstsavefpureg <> R_NO then
+           for regi:=firstsavefpureg to lastsavefpureg do
+             begin
+                if (regi in s) then
+                  inc(reg_pushes[regi],t_times*2);
+             end;
+         if firstsavemmreg <> R_NO then
+           for regi:=firstsavemmreg to lastsavemmreg do
+             begin
+                if (regi in s) then
+                  inc(reg_pushes[regi],t_times*2);
+             end;
+      end;
+
+
+    procedure trgobj.clearregistercount;
+
+      begin
+        fillchar(reg_pushes,sizeof(reg_pushes),0);
+        fillchar(is_reg_var,sizeof(is_reg_var),false);
+        fillchar(regvar_loaded,sizeof(regvar_loaded),false);
+      end;
+
+
+    procedure trgobj.resetusableregisters;
+
+      begin
+        { initialize fields with constant values from cpubase }
+        countusableregsint := cpubase.c_countusableregsint;
+        countusableregsfpu := cpubase.c_countusableregsfpu;
+        countusableregsmm := cpubase.c_countusableregsmm;
+        usableregsint := cpubase.usableregsint;
+        usableregsfpu := cpubase.usableregsfpu;
+        usableregsmm := cpubase.usableregsmm;
+        clearregistercount;
+      end;
+
+
+    procedure trgobj.makeregvar(reg: tregister);
+      begin
+        if reg in intregs then
+          begin
+            dec(countusableregsint);
+            dec(countunusedregsint);
+            exclude(usableregsint,reg);
+            exclude(unusedregsint,reg);
+          end
+        else if reg in fpuregs then
+          begin
+             dec(countusableregsfpu);
+             dec(countunusedregsfpu);
+             exclude(usableregsfpu,reg);
+             exclude(unusedregsfpu,reg);
+          end
+        else if reg in mmregs then
+          begin
+             dec(countusableregsmm);
+             dec(countunusedregsmm);
+             exclude(usableregsmm,reg);
+             exclude(unusedregsmm,reg);
+          end;
+        is_reg_var[reg]:=true;
+      end;
+
+
+{$ifdef TEMPREGDEBUG}
+    procedure trgobj.testregisters;
+      var
+        r: tregister;
+        test : byte;
+      begin
+        test:=0;
+        for r := firstsaveintreg to lastsaveintreg do
+          inc(test,ord(r in unusedregsint));
+        if test<>countunusedregsint then
+          internalerror(10);
+      end;
+{$endif TEMPREGDEBUG}
+
+
+    procedure trgobj.saveStateForInline(var p: pointer);
+      begin
+        new(psavedstate(state));
+        psavedstate(state)^.unusedregsint := unusedregsint;
+        psavedstate(state)^.usableregsint := usableregsint;
+        psavedstate(state)^.unusedregsfpu := unusedregsfpu;
+        psavedstate(state)^.usableregsfpu := usableregsfpu;
+        psavedstate(state)^.unusedregsmm := unusedregsmm;
+        psavedstate(state)^.usableregsmm := usableregsmm;
+        psavedstate(state)^.countunusedregsint := countunusedregsint;
+        psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
+        psavedstate(state)^.countunusedregsmm := countunusedregsmm;
+        psavedstate(state)^.countusableregsint := countusableregsint;
+        psavedstate(state)^.countusableregsfpu := countusableregsfpu;
+        psavedstate(state)^.countusableregsmm := countusableregsmm;
+        psavedstate(state)^.usedinproc := usedinproc;
+        psavedstate(state)^.reg_pushes := reg_pushes;
+        psavedstate(state)^.is_reg_var := is_reg_var;
+        psavedstate(state)^.regvar_loaded := regvar_loaded;
+{$ifdef TEMPREGDEBUG}
+        psavedstate(state)^.reg_user := reg_user;
+        psavedstate(state)^.reg_releaser := reg_releaser;
+{$endif TEMPREGDEBUG}
+      end;
+
+
+    procedure trgobj.restoreStateAfterInline(var state: pointer);
+      begin
+        unusedregsint := psavedstate(state)^.unusedregsint;
+        usableregsint := psavedstate(state)^.usableregsint;
+        unusedregsfpu := psavedstate(state)^.unusedregsfpu;
+        usableregsfpu := psavedstate(state)^.usableregsfpu;
+        unusedregsmm := psavedstate(state)^.unusedregsmm;
+        usableregsmm := psavedstate(state)^.usableregsmm;
+        countunusedregsint := psavedstate(state)^.countunusedregsint;
+        countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
+        countunusedregsmm := psavedstate(state)^.countunusedregsmm;
+        countusableregsint := psavedstate(state)^.countusableregsint;
+        countusableregsfpu := psavedstate(state)^.countusableregsfpu;
+        countusableregsmm := psavedstate(state)^.countusableregsmm;
+        usedinproc := psavedstate(state)^.usedinproc;
+        reg_pushes := psavedstate(state)^.reg_pushes;
+        is_reg_var := psavedstate(state)^.is_reg_var;
+        regvar_loaded := psavedstate(state)^.regvar_loaded;
+{$ifdef TEMPREGDEBUG}
+        reg_user := psavedstate(state)^.reg_user;
+        reg_releaser := psavedstate(state)^.reg_releaser;
+{$endif TEMPREGDEBUG}
+        dispose(psavedstate(state));
+        state := nil;
+      end;
+
+
+    procedure trgobj.saveUnusedState(var state: pointer);
+      begin
+        new(punusedstate(state));
+        punusedstate(state)^.unusedregsint := unusedregsint;
+        punusedstate(state)^.unusedregsfpu := unusedregsfpu;
+        punusedstate(state)^.unusedregsmm := unusedregsmm;
+        punusedstate(state)^.countunusedregsint := countunusedregsint;
+        punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
+        punusedstate(state)^.countunusedregsmm := countunusedregsmm;
+      end;
+
+
+    procedure trgobj.restoreUnusedState(var state: pointer);
+      begin
+        unusedregsint := punusedstate(state)^.unusedregsint;
+        unusedregsfpu := punusedstate(state)^.unusedregsfpu;
+        unusedregsmm := punusedstate(state)^.unusedregsmm;
+        countunusedregsint := punusedstate(state)^.countunusedregsint;
+        countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
+        countunusedregsmm := punusedstate(state)^.countunusedregsmm;
+        dispose(punusedstate(state));
+        state := nil;
+      end;
+
+finalization
+  rg.free;
+end.
+
+{
+  $Log$
+  Revision 1.1  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+}

+ 21 - 62
compiler/symdef.pas

@@ -505,13 +505,7 @@ interface
           is_used    : boolean;
           has_mangledname : boolean;
           { small set which contains the modified registers }
-{$ifdef i386}
-          usedregisters : longint;
-{$endif}
-{$ifdef POWERPC}
-          { not used, only a fake }
-          usedregisters : longint;
-{$endif}
+          usedregisters : tregisterset;
           constructor create;
           constructor load(ppufile:tcompilerppufile);
           destructor  destroy;override;
@@ -3272,18 +3266,7 @@ implementation
           end;
          lastref:=defref;
        { first, we assume that all registers are used }
-{$ifdef newcg}
          usedregisters:=[firstreg..lastreg];
-{$else newcg}
-{$ifdef i386}
-         usedregisters:=$ff;
-{$endif i386}
-{$ifdef POWERPC}
-         { on the PPC, we use the OS specific standard calling conventions }
-         { so the information about the used register isn't necessary yet  }
-         usedregisters:=0;
-{$endif POWERPC}
-{$endif newcg}
          forwarddef:=true;
          interfacedef:=false;
          hasforward:=false;
@@ -3303,21 +3286,7 @@ implementation
          inherited load(ppufile);
          deftype:=procdef;
 
-{$ifdef newcg}
-         readnormalset(usedregisters);
-{$else newcg}
-{$ifdef i386}
-         usedregisters:=ppufile.getbyte;
-{$else}
-{$ifdef POWERPC}
-         { on the PPC, we use the OS specific standard calling conventions }
-         { so the information about the used register isn't necessary yet  }
-         usedregisters:=0;
-{$else POWERPC}
-         readnormalset(usedregisters);
-{$endif POWERPC}
-{$endif}
-{$endif newcg}
+         ppufile.getnormalset(usedregisters);
          has_mangledname:=true;
          _mangledname:=stringdup(ppufile.getstring);
 
@@ -3400,37 +3369,10 @@ implementation
          { set all registers to used for simplified compilation PM }
          if simplify_ppu then
            begin
-{$ifdef newcg}
              usedregisters:=[firstreg..lastreg];
-{$else newcg}
-{$ifdef i386}
-             usedregisters:=$ff;
-{$else}
-{$ifdef POWERPC}
-         { on the PPC, we use the OS specific standard calling conventions }
-         { so the information about the used register isn't necessary yet  }
-            usedregisters:=0;
-{$else POWERPC}
-            usedregisters:=[firstreg..lastreg];
-{$endif POWERPC}
-{$endif i386}
-{$endif newcg}
            end;
 
-{$ifdef newcg}
-         writenormalset(usedregisters);
-{$else newcg}
-{$ifdef i386}
-         ppufile.putbyte(usedregisters);
-{$else}
-{$ifdef POWERPC}
-         { on the PPC, we use the OS specific standard calling conventions }
-         { so the information about the used register isn't necessary yet  }
-{$else POWERPC}
-           writenormalset(usedregisters);
-{$endif POWERPC}
-{$endif i386}
-{$endif newcg}
+         ppufile.putnormalset(usedregisters);
          ppufile.do_interface_crc:=oldintfcrc;
          ppufile.putstring(mangledname);
          ppufile.putlongint(extnumber);
@@ -5478,7 +5420,24 @@ implementation
 end.
 {
   $Log$
-  Revision 1.66  2002-03-24 19:10:14  carl
+  Revision 1.67  2002-03-31 20:26:36  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.66  2002/03/24 19:10:14  carl
   + patch for SPARC from Mazen NEIFER
 
   Revision 1.65  2002/02/04 08:16:07  jonas

+ 696 - 0
compiler/tgobj.pas

@@ -0,0 +1,696 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by Florian Klaempfl
+
+    This unit implements the base object for temp. generator
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit tgobj;
+
+{$i defines.inc}
+
+  interface
+
+    uses
+      globals,
+      cpubase,
+      cpuinfo,
+      cpuasm,
+      tainst,
+      cclasses,globtype,cgbase,aasm;
+
+    type
+      ttemptype = (tt_none,tt_free,tt_normal,tt_persistant,
+                   tt_ansistring,tt_freeansistring,tt_widestring,tt_freewidestring,
+                   tt_interfacecom,tt_freeinterfacecom);
+
+      ttemptypeset = set of ttemptype;
+
+      ptemprecord = ^ttemprecord;
+      ttemprecord = record
+         temptype   : ttemptype;
+         pos        : longint;
+         size       : longint;
+         next       : ptemprecord;
+         nextfree   : ptemprecord; { for faster freeblock checking }
+{$ifdef EXTDEBUG}
+         posinfo,
+         releaseposinfo : tfileposinfo;
+{$endif}
+      end;
+
+
+       ttgobj = class
+          { contains all temps }
+          templist      : ptemprecord;
+          { contains all free temps using nextfree links }
+          tempfreelist  : ptemprecord;
+          { Offsets of the first/last temp }
+          firsttemp,
+          lasttemp      : longint;
+          lasttempofsize : ptemprecord;
+
+          { tries to hold the amount of times which the current tree is processed  }
+          t_times: longint;
+
+          constructor create;
+
+          { generates temporary variables }
+          procedure resettempgen;
+          procedure setfirsttemp(l : longint);
+          function gettempsize : longint;
+          function gettempofsize(list: taasmoutput; size : longint) : longint;
+          { special call for inlined procedures }
+          function gettempofsizepersistant(list: taasmoutput; size : longint) : longint;
+          procedure gettempofsizereferencepersistant(list: taasmoutput; l : longint;var ref : treference);
+
+          procedure gettemppointerreferencefortype(list: taasmoutput; var ref : treference; const usedtype, freetype: ttemptype);
+          function ungettemppointeriftype(list: taasmoutput; const ref : treference; const usedtype, freetype: ttemptype) : boolean;
+
+          { for parameter func returns }
+          procedure normaltemptopersistant(pos : longint);
+          procedure persistanttemptonormal(pos : longint);
+
+          {procedure ungettemp(pos : longint;size : longint);}
+          procedure ungetpersistanttemp(list: taasmoutput; pos : longint);
+          procedure ungetpersistanttempreference(list: taasmoutput; const ref : treference);
+
+          procedure gettempofsizereference(list: taasmoutput; l : longint;var ref : treference);
+          function istemp(const ref : treference) : boolean;
+          procedure ungetiftemp(list: taasmoutput; const ref : treference);
+          function getsizeoftemp(const ref: treference): longint;
+
+          function ungetiftempansi(list: taasmoutput; const ref : treference) : boolean;
+          procedure gettempansistringreference(list: taasmoutput; var ref : treference);
+
+          function ungetiftempwidestr(list: taasmoutput; const ref : treference) : boolean;
+          procedure gettempwidestringreference(list: taasmoutput; var ref : treference);
+
+          function ungetiftempintfcom(list: taasmoutput; const ref : treference) : boolean;
+          procedure gettempintfcomreference(list: taasmoutput; var ref : treference);
+
+       private
+          function ungettemp(list: taasmoutput; pos:longint;allowtype:ttemptype):ttemptype;
+          function newtempofsize(size : longint) : longint;
+       end;
+
+     var
+       tg: ttgobj;
+
+
+  implementation
+
+    uses
+       systems,
+       verbose,cutils,
+       cgobj;
+
+    constructor ttgobj.create;
+
+     begin
+       tempfreelist:=nil;
+       templist:=nil;
+       lasttempofsize := nil;
+     end;
+
+
+    procedure ttgobj.resettempgen;
+      var
+         hp : ptemprecord;
+      begin
+        { Clear the old templist }
+        while assigned(templist) do
+         begin
+{$ifdef EXTDEBUG}
+           case templist^.temptype of
+             tt_normal,
+             tt_persistant :
+               Comment(V_Warning,'temporary assignment of size '+
+                       tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
+                       ':'+tostr(templist^.posinfo.column)+
+                       ' at pos '+tostr(templist^.pos)+
+                       ' not freed at the end of the procedure');
+             tt_ansistring :
+               Comment(V_Warning,'temporary ANSI assignment of size '+
+                       tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
+                       ':'+tostr(templist^.posinfo.column)+
+                       ' at pos '+tostr(templist^.pos)+
+                     ' not freed at the end of the procedure');
+             tt_widestring :
+               Comment(V_Warning,'temporary WIDE assignment of size '+
+                       tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)+
+                       ':'+tostr(templist^.posinfo.column)+
+                       ' at pos '+tostr(templist^.pos)+
+                     ' not freed at the end of the procedure');
+           end;
+{$endif}
+           hp:=templist;
+           templist:=hp^.next;
+           dispose(hp);
+         end;
+        templist:=nil;
+        tempfreelist:=nil;
+        firsttemp:=0;
+        lasttemp:=0;
+      end;
+
+
+    procedure ttgobj.setfirsttemp(l : longint);
+      begin
+         { this is a negative value normally }
+         if l < 0 then
+          Begin
+            if odd(l) then
+             Dec(l);
+          end
+         else
+          Begin
+            if odd(l) then
+             Inc(l);
+          end;
+         firsttemp:=l;
+         lasttemp:=l;
+      end;
+
+
+    function ttgobj.newtempofsize(size : longint) : longint;
+      var
+        tl : ptemprecord;
+      begin
+        { we need to allocate at least a minimum of 4 bytes, else
+          we get two temps at the same position resulting in problems
+          when finding the corresponding temprecord }
+        if size=0 then
+         size:=4;
+        { Just extend the temp, everything below has been use
+          already }
+        dec(lasttemp,size);
+        { now we can create the templist entry }
+        new(tl);
+        tl^.temptype:=tt_normal;
+        tl^.pos:=lasttemp;
+        tl^.size:=size;
+        tl^.next:=templist;
+        tl^.nextfree:=nil;
+        templist:=tl;
+        newtempofsize:=tl^.pos;
+      end;
+
+    function ttgobj.gettempofsize(list: taasmoutput; size : longint) : longint;
+      var
+         tl,
+         bestslot,bestprev,
+         hprev,hp : ptemprecord;
+         bestsize,ofs : longint;
+      begin
+         bestprev:=nil;
+         bestslot:=nil;
+         tl:=nil;
+         bestsize:=0;
+{$ifdef EXTDEBUG}
+         if size=0 then
+          Comment(V_Warning,'Temp of size 0 requested');
+{$endif}
+         { Align needed size on 4 bytes }
+         if (size mod 4)<>0 then
+           size:=size+(4-(size mod 4));
+         { First check the tmpfreelist }
+         if assigned(tempfreelist) then
+          begin
+            { Check for a slot with the same size first }
+            hprev:=nil;
+            hp:=tempfreelist;
+            while assigned(hp) do
+             begin
+{$ifdef EXTDEBUG}
+               if hp^.temptype<>tt_free then
+                 Comment(V_Warning,'Temp in freelist is not set to tt_free');
+{$endif}
+               if hp^.size>=size then
+                begin
+                  { Slot is the same size, then leave immediatly }
+                  if hp^.size=size then
+                   begin
+                     bestprev:=hprev;
+                     bestslot:=hp;
+                     bestsize:=size;
+                     break;
+                   end
+                  else
+                   begin
+                     if (bestsize=0) or (hp^.size<bestsize) then
+                      begin
+                        bestprev:=hprev;
+                        bestslot:=hp;
+                        bestsize:=hp^.size;
+                      end;
+                   end;
+                end;
+               hprev:=hp;
+               hp:=hp^.nextfree;
+             end;
+          end;
+         { Reuse an old temp ? }
+         if assigned(bestslot) then
+          begin
+            if bestsize=size then
+             begin
+               bestslot^.temptype:=tt_normal;
+               ofs:=bestslot^.pos;
+               tl:=bestslot;
+               { Remove from the tempfreelist }
+               if assigned(bestprev) then
+                 bestprev^.nextfree:=bestslot^.nextfree
+               else
+                 tempfreelist:=bestslot^.nextfree;
+             end
+            else
+             begin
+               { Resize the old block }
+               dec(bestslot^.size,size);
+               { Create new block and link after bestslot }
+               new(tl);
+               tl^.temptype:=tt_normal;
+               tl^.pos:=bestslot^.pos+bestslot^.size;
+               ofs:=tl^.pos;
+               tl^.size:=size;
+               tl^.nextfree:=nil;
+               { link the new block }
+               tl^.next:=bestslot^.next;
+               bestslot^.next:=tl;
+             end;
+          end
+         else
+          begin
+             ofs:=newtempofsize(size);
+             tl:=templist;
+          end;
+         lasttempofsize:=tl;
+{$ifdef EXTDEBUG}
+         tl^.posinfo:=aktfilepos;
+{$endif}
+         list.concat(Taitempalloc.alloc(ofs,size));
+         gettempofsize:=ofs;
+      end;
+
+
+    function ttgobj.gettempofsizepersistant(list: taasmoutput; size : longint) : longint;
+      var
+         l : longint;
+      begin
+         l:=gettempofsize(list, size);
+         lasttempofsize^.temptype:=tt_persistant;
+{$ifdef EXTDEBUG}
+         Comment(V_Debug,'temp managment  : call to gettempofsizepersistant()'+
+                     ' with size '+tostr(size)+' returned '+tostr(l));
+{$endif}
+         gettempofsizepersistant:=l;
+      end;
+
+
+    function ttgobj.gettempsize : longint;
+      var
+        _align : longint;
+      begin
+        { align to 4 bytes at least
+          otherwise all those subl $2,%esp are meaningless PM }
+        _align:=target_info.alignment.localalignmin;
+        if _align<4 then
+          _align:=4;
+        gettempsize:=Align(-lasttemp,_align);
+      end;
+
+
+    procedure ttgobj.gettempofsizereference(list: taasmoutput; l : longint;var ref : treference);
+      begin
+         { do a reset, because the reference isn't used }
+         reset_reference(ref);
+         ref.offset:=gettempofsize(list,l);
+         ref.base:=procinfo^.framepointer;
+      end;
+
+    procedure ttgobj.gettempofsizereferencepersistant(list: taasmoutput; l : longint;var ref : treference);
+      begin
+         { do a reset, because the reference isn't used }
+         reset_reference(ref);
+         ref.offset:=gettempofsizepersistant(list,l);
+         ref.base:=procinfo^.framepointer;
+      end;
+
+
+    procedure ttgobj.gettemppointerreferencefortype(list: taasmoutput; var ref : treference; const usedtype, freetype: ttemptype);
+      var
+         foundslot,tl : ptemprecord;
+      begin
+         { do a reset, because the reference isn't used }
+         reset_reference(ref);
+         ref.base:=procinfo^.framepointer;
+         { Reuse old slot ? }
+         foundslot:=nil;
+         tl:=templist;
+         while assigned(tl) do
+          begin
+            if tl^.temptype=freetype then
+             begin
+               foundslot:=tl;
+{$ifdef EXTDEBUG}
+               tl^.posinfo:=aktfilepos;
+{$endif}
+               break;
+             end;
+            tl:=tl^.next;
+          end;
+         if assigned(foundslot) then
+          begin
+            foundslot^.temptype:=usedtype;
+            ref.offset:=foundslot^.pos;
+          end
+         else
+          begin
+            ref.offset:=newtempofsize(target_info.size_of_pointer);
+{$ifdef EXTDEBUG}
+            templist^.posinfo:=aktfilepos;
+{$endif}
+            templist^.temptype:=usedtype;
+          end;
+         list.concat(Taitempalloc.alloc(ref.offset,target_info.size_of_pointer));
+      end;
+
+    function ttgobj.ungettemppointeriftype(list: taasmoutput; const ref : treference; const usedtype, freetype: ttemptype) : boolean;
+      var
+         tl : ptemprecord;
+      begin
+        ungettemppointeriftype:=false;
+        tl:=templist;
+        while assigned(tl) do
+         begin
+           if tl^.pos=ref.offset then
+            begin
+              if tl^.temptype=usedtype then
+               begin
+                 tl^.temptype:=freetype;
+                 ungettemppointeriftype:=true;
+                 list.concat(Taitempalloc.dealloc(tl^.pos,tl^.size));
+                 exit;
+{$ifdef EXTDEBUG}
+               end
+              else if (tl^.temptype=freetype) then
+               begin
+                 Comment(V_Debug,'temp managment problem : ungettemppointeriftype()'+
+                     ' at pos '+tostr(ref.offset)+ ' already free !');
+{$endif}
+               end;
+            end;
+           tl:=tl^.next;
+         end;
+      end;
+
+
+    procedure ttgobj.gettempansistringreference(list: taasmoutput; var ref : treference);
+      begin
+        gettemppointerreferencefortype(list,ref,tt_ansistring,tt_freeansistring);
+      end;
+
+    procedure ttgobj.gettempwidestringreference(list: taasmoutput; var ref : treference);
+      begin
+        gettemppointerreferencefortype(list,ref,tt_widestring,tt_freewidestring);
+      end;
+
+    function ttgobj.ungetiftempansi(list: taasmoutput; const ref : treference) : boolean;
+      begin
+        ungetiftempansi:=ungettemppointeriftype(list,ref,tt_ansistring,tt_freeansistring);
+      end;
+
+    function ttgobj.ungetiftempwidestr(list: taasmoutput; const ref : treference) : boolean;
+      begin
+        ungetiftempwidestr:=ungettemppointeriftype(list,ref,tt_widestring,tt_freewidestring);
+      end;
+
+
+    procedure ttgobj.gettempintfcomreference(list: taasmoutput; var ref : treference);
+      begin
+        gettemppointerreferencefortype(list,ref,tt_interfacecom,tt_freeinterfacecom);
+      end;
+
+
+    function ttgobj.ungetiftempintfcom(list: taasmoutput; const ref : treference) : boolean;
+      begin
+        ungetiftempintfcom:=ungettemppointeriftype(list,ref,tt_ansistring,tt_freeansistring);
+      end;
+
+    function ttgobj.istemp(const ref : treference) : boolean;
+
+      begin
+         { ref.index = R_NO was missing
+           led to problems with local arrays
+           with lower bound > 0 (PM) }
+         istemp:=((ref.base=procinfo^.framepointer) and
+{$ifdef i386}
+                  (ref.index=R_NO) and
+{$endif}
+                  (ref.offset<firsttemp));
+      end;
+
+
+    procedure ttgobj.persistanttemptonormal(pos : longint);
+      var
+        hp : ptemprecord;
+      begin
+         hp:=templist;
+         while assigned(hp) do
+           if (hp^.pos=pos) and (hp^.temptype=tt_persistant) then
+             begin
+{$ifdef EXTDEBUG}
+               Comment(V_Debug,'temp managment : persistanttemptonormal()'+
+                  ' at pos '+tostr(pos)+ ' found !');
+{$endif}
+                hp^.temptype:=tt_normal;
+                exit;
+             end
+           else
+             hp:=hp^.next;
+{$ifdef EXTDEBUG}
+         Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
+            ' at pos '+tostr(pos)+ ' not found !');
+{$endif}
+      end;
+
+
+    procedure ttgobj.normaltemptopersistant(pos : longint);
+      var
+        hp : ptemprecord;
+      begin
+         hp:=templist;
+         while assigned(hp) do
+           if (hp^.pos=pos) and (hp^.temptype=tt_normal) then
+             begin
+{$ifdef EXTDEBUG}
+               Comment(V_Debug,'temp managment : normaltemptopersistant()'+
+                  ' at pos '+tostr(pos)+ ' found !');
+{$endif}
+                hp^.temptype:=tt_persistant;
+                exit;
+             end
+           else
+             hp:=hp^.next;
+{$ifdef EXTDEBUG}
+         Comment(V_Debug,'temp managment problem : normaltemptopersistant()'+
+            ' at pos '+tostr(pos)+ ' not found !');
+{$endif}
+      end;
+
+
+    function ttgobj.ungettemp(list: taasmoutput; pos:longint;allowtype:ttemptype):ttemptype;
+      var
+         hp,hnext,hprev,hprevfree : ptemprecord;
+      begin
+         ungettemp:=tt_none;
+         hp:=templist;
+         hprev:=nil;
+         hprevfree:=nil;
+         while assigned(hp) do
+          begin
+            if (hp^.pos=pos) then
+             begin
+               { check type }
+               ungettemp:=hp^.temptype;
+               if hp^.temptype<>allowtype then
+                begin
+                  exit;
+                end;
+               list.concat(Taitempalloc.dealloc(hp^.pos,hp^.size));
+               { set this block to free }
+               hp^.temptype:=tt_free;
+               { Update tempfreelist }
+               if assigned(hprevfree) then
+                begin
+                  { Connect with previous? }
+                  if assigned(hprev) and (hprev^.temptype=tt_free) then
+                   begin
+                     inc(hprev^.size,hp^.size);
+                     hprev^.next:=hp^.next;
+                     dispose(hp);
+                     hp:=hprev;
+                   end
+                  else
+                   hprevfree^.nextfree:=hp;
+                end
+               else
+                begin
+                  hp^.nextfree:=tempfreelist;
+                  tempfreelist:=hp;
+                end;
+               { Next block free ? Yes, then concat }
+               hnext:=hp^.next;
+               if assigned(hnext) and (hnext^.temptype=tt_free) then
+                begin
+                  inc(hp^.size,hnext^.size);
+                  hp^.nextfree:=hnext^.nextfree;
+                  hp^.next:=hnext^.next;
+                  dispose(hnext);
+                end;
+               exit;
+             end;
+            if (hp^.temptype=tt_free) then
+             hprevfree:=hp;
+            hprev:=hp;
+            hp:=hp^.next;
+          end;
+        ungettemp:=tt_none;
+      end;
+
+    function ttgobj.getsizeoftemp(const ref: treference): longint;
+      var
+         hp : ptemprecord;
+      begin
+        hp:=templist;
+        while assigned(hp) do
+          begin
+            if (hp^.pos=ref.offset) then
+              begin
+                getsizeoftemp := hp^.size;
+                exit;
+              end;
+            hp := hp^.next;
+          end;
+        getsizeoftemp := -1;
+      end;
+
+    procedure ttgobj.ungetpersistanttemp(list: taasmoutput; pos : longint);
+      begin
+{$ifdef EXTDEBUG}
+        if ungettemp(list,pos,tt_persistant)<>tt_persistant then
+          Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
+                  ' at pos '+tostr(pos)+ ' not found !');
+{$else}
+        ungettemp(list,pos,tt_persistant);
+{$endif}
+      end;
+
+    procedure ttgobj.ungetpersistanttempreference(list: taasmoutput; const ref : treference);
+
+      begin
+         ungetpersistanttemp(list, ref.offset);
+      end;
+
+    procedure ttgobj.ungetiftemp(list: taasmoutput; const ref : treference);
+{$ifdef EXTDEBUG}
+      var
+         tt : ttemptype;
+{$endif}
+      begin
+         if istemp(ref) then
+           begin
+              { first check if ansistring }
+              if ungetiftempansi(list,ref) or
+                 ungetiftempwidestr(list,ref) or
+                 ungetiftempintfcom(list,ref) then
+                exit;
+{$ifndef EXTDEBUG}
+              ungettemp(list,ref.offset,tt_normal);
+{$else}
+              tt:=ungettemp(list,ref.offset,tt_normal);
+              if tt=tt_persistant then
+                Comment(V_Debug,'temp at pos '+tostr(ref.offset)+ ' not released because persistant!');
+              if tt=tt_none then
+                Comment(V_Warning,'temp not found for release at offset '+tostr(ref.offset));
+{$endif}
+           end;
+      end;
+
+
+initialization
+  tg := ttgobj.create;
+finalization
+  tg.free;
+end.
+{
+  $Log$
+  Revision 1.1  2002-03-31 20:26:37  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.1  2000/07/13 06:30:09  michael
+  + Initial import
+
+  Revision 1.10  2000/02/17 14:48:36  florian
+     * updated to use old firstpass
+
+  Revision 1.9  2000/01/07 01:14:55  peter
+    * updated copyright to 2000
+
+  Revision 1.8  1999/10/14 14:57:54  florian
+    - removed the hcodegen use in the new cg, use cgbase instead
+
+  Revision 1.7  1999/10/12 21:20:47  florian
+    * new codegenerator compiles again
+
+  Revision 1.6  1999/09/10 18:48:11  florian
+    * some bug fixes (e.g. must_be_valid and procinfo.funcret_is_valid)
+    * most things for stored properties fixed
+
+  Revision 1.5  1999/08/06 16:04:06  michael
+  + introduced tainstruction
+
+  Revision 1.4  1999/08/03 00:33:23  michael
+  + Added cpuasm for alpha
+
+  Revision 1.3  1999/08/03 00:32:13  florian
+    * reg_vars and reg_pushes is now in tgobj
+
+  Revision 1.2  1999/08/02 23:13:22  florian
+    * more changes to compile for the Alpha
+
+  Revision 1.1  1999/08/02 17:14:12  florian
+    + changed the temp. generator to an object
+
+}

+ 61 - 3
compiler/utils/ppudump.pp

@@ -27,7 +27,7 @@ uses
 {$ifdef go32v2}
   dpmiexcp,
 {$endif go32v2}
-  ppu;
+  ppu, cpubase;
 
 const
   Version   = 'Version 1.10';
@@ -932,6 +932,46 @@ end;
                          Read defintions Part
 ****************************************************************************}
 
+procedure getusedregisters;
+var
+  regs: tregisterset;
+  r: tregister;
+  first: boolean;
+begin
+  first := true;
+  ppufile.getnormalset(regs);
+  for r := firstsaveintreg to lastsaveintreg do
+    if r in regs then
+      begin
+        if not first then
+          write(', ')
+        else
+          first := false;
+        write(att_reg2str[r])
+      end;
+  if (firstsavefpureg <> R_NO) then
+    for r := firstsavefpureg to lastsavefpureg do
+      if r in regs then
+        begin
+          if not first then
+            write(', ')
+          else
+            first := false;
+          write(att_reg2str[r])
+        end;
+  if (firstsavemmreg <> R_NO) then
+    for r := firstsavemmreg to lastsavemmreg do
+      if r in regs then
+        begin
+          if not first then
+            write(', ')
+          else
+            first := false;
+          write(att_reg2str[r])
+        end;
+  writeln;
+end;
+
 procedure readdefinitions(start_read : boolean);
 type
   tsettype  = (normset,smallset,varset);
@@ -1033,7 +1073,8 @@ begin
            begin
              readcommondef('Procedure definition');
              calloption:=read_abstract_proc_def;
-             writeln(space,'    Used Register : ',getbyte);
+             write  (space,'   Used Registers : ');
+             getusedregisters;
              writeln(space,'     Mangled name : ',getstring);
              writeln(space,'           Number : ',getlongint);
              write  (space,'            Class : ');
@@ -1647,7 +1688,24 @@ begin
 end.
 {
   $Log$
-  Revision 1.14  2002-03-28 20:48:52  carl
+  Revision 1.15  2002-03-31 20:26:42  jonas
+    + a_loadfpu_* and a_loadmm_* methods in tcg
+    * register allocation is now handled by a class and is mostly processor
+      independent (+rgobj.pas and i386/rgcpu.pas)
+    * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
+    * some small improvements and fixes to the optimizer
+    * some register allocation fixes
+    * some fpuvaroffset fixes in the unary minus node
+    * push/popusedregisters is now called rg.save/restoreusedregisters and
+      (for i386) uses temps instead of push/pop's when using -Op3 (that code is
+      also better optimizable)
+    * fixed and optimized register saving/restoring for new/dispose nodes
+    * LOC_FPU locations now also require their "register" field to be set to
+      R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
+    - list field removed of the tnode class because it's not used currently
+      and can cause hard-to-find bugs
+
+  Revision 1.14  2002/03/28 20:48:52  carl
   - remove go32v1 support
 
   Revision 1.13  2002/03/28 16:44:59  armin

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov