浏览代码

* several arm related stuff fixed

florian 22 年之前
父节点
当前提交
2b83637905
共有 7 个文件被更改,包括 1627 次插入286 次删除
  1. 768 0
      compiler/arm/aasmcpu.pas
  2. 260 0
      compiler/arm/agarmgas.pas
  3. 315 217
      compiler/arm/cpubase.pas
  4. 37 62
      compiler/arm/cpupara.pas
  5. 10 7
      compiler/arm/radirect.pas
  6. 69 0
      compiler/arm/rasm.pas
  7. 168 0
      compiler/arm/rgcpu.pas

+ 768 - 0
compiler/arm/aasmcpu.pas

@@ -0,0 +1,768 @@
+{
+    $Id$
+    Copyright (c) 2003 by Florian Klaempfl
+
+    Contains the assembler object for the ARM
+
+    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 aasmcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  cclasses,aasmtai,
+  aasmbase,globals,verbose,
+  cpubase,cpuinfo;
+
+    const
+      { "mov reg,reg" source operand number }
+      O_MOV_SOURCE = 1;
+      { "mov reg,reg" source operand number }
+      O_MOV_DEST = 0;
+
+
+    type
+      taicpu = class(taicpu_abstract)
+         constructor op_none(op : tasmop);
+
+         constructor op_reg(op : tasmop;_op1 : tregister);
+         constructor op_const(op : tasmop;_op1 : longint);
+
+         constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+         constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+         constructor op_reg_const(op:tasmop; _op1: tregister; _op2: longint);
+         constructor op_const_reg(op:tasmop; _op1: longint; _op2: tregister);
+
+         constructor op_const_const(op : tasmop;_op1,_op2 : longint);
+
+         constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+         constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: Longint);
+         constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
+         constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+         constructor op_const_reg_reg(op : tasmop;_op1 : longint;_op2, _op3 : tregister);
+         constructor op_const_reg_const(op : tasmop;_op1 : longint;_op2 : tregister;_op3 : longint);
+
+         constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+         constructor op_reg_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+         constructor op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: longint);
+
+         constructor op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : Longint);
+         constructor op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : Longint);
+
+
+         { this is for Jmp instructions }
+         constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+         constructor op_const_const_sym(op : tasmop;_op1,_op2 : longint;_op3: tasmsymbol);
+
+
+         constructor op_sym(op : tasmop;_op1 : tasmsymbol);
+         constructor op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
+         constructor op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint);
+         constructor op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
+
+         procedure loadbool(opidx:longint;_b:boolean);
+
+
+         function is_nop: boolean; override;
+         function is_move:boolean; override;
+         function spill_registers(list:Taasmoutput;
+                                  rgget:Trggetproc;
+                                  rgunget:Trgungetproc;
+                                  r:Tsupregset;
+                                  var unusedregsint:Tsupregset;
+                                  const spilltemplist:Tspill_temp_list):boolean; override;
+      end;
+
+      tai_align = class(tai_align_abstract)
+        { nothing to add }
+      end;
+
+    procedure InitAsm;
+    procedure DoneAsm;
+
+
+implementation
+
+uses cutils,rgobj;
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    procedure taicpu.loadbool(opidx:longint;_b:boolean);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+         begin
+           if typ=top_ref then
+            dispose(ref);
+           b:=_b;
+           typ:=top_bool;
+         end;
+      end;
+
+
+    constructor taicpu.op_none(op : tasmop);
+      begin
+         inherited create(op);
+      end;
+
+
+    constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031207);
+         ops:=1;
+         loadreg(0,_op1);
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_op1 : longint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadconst(0,aword(_op1));
+      end;
+
+
+    constructor taicpu.op_reg_reg(op : tasmop;_op1,_op2 : tregister);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031205);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031206);
+         ops:=2;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+      end;
+
+    constructor taicpu.op_reg_const(op:tasmop; _op1: tregister; _op2: longint);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031208);
+         ops:=2;
+         loadreg(0,_op1);
+         loadconst(1,aword(_op2));
+      end;
+
+     constructor taicpu.op_const_reg(op:tasmop; _op1: longint; _op2: tregister);
+      begin
+         inherited create(op);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031209);
+         ops:=2;
+         loadconst(0,aword(_op1));
+         loadreg(1,_op2);
+      end;
+
+
+    constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031210);
+         ops:=2;
+         loadreg(0,_op1);
+         loadref(1,_op2);
+      end;
+
+
+    constructor taicpu.op_const_const(op : tasmop;_op1,_op2 : longint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadconst(0,aword(_op1));
+         loadconst(1,aword(_op2));
+      end;
+
+
+    constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031211);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031212);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031213);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: Longint);
+       begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031214);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031215);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,aword(_op3));
+      end;
+
+     constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint);
+       begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031216);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031217);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadsymbol(0,_op3,_op3ofs);
+      end;
+
+     constructor taicpu.op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference);
+       begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031218);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031219);
+         ops:=3;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadref(2,_op3);
+      end;
+
+    constructor taicpu.op_const_reg_reg(op : tasmop;_op1 : longint;_op2, _op3 : tregister);
+      begin
+         inherited create(op);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031221);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031220);
+         ops:=3;
+         loadconst(0,aword(_op1));
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+      end;
+
+     constructor taicpu.op_const_reg_const(op : tasmop;_op1 : longint;_op2 : tregister;_op3 : longint);
+      begin
+         inherited create(op);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031222);
+         ops:=3;
+         loadconst(0,aword(_op1));
+         loadreg(1,_op2);
+         loadconst(2,aword(_op3));
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031223);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031224);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031225);
+         if (_op4.enum = R_INTREGISTER) and (_op4.number = NR_NO) then
+           internalerror(2003031226);
+         ops:=4;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_reg(op : tasmop;_op1: tregister;_op2:boolean;_op3,_op4:tregister);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031227);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031228);
+         if (_op4.enum = R_INTREGISTER) and (_op4.number = NR_NO) then
+           internalerror(2003031229);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(1,_op2);
+         loadreg(2,_op3);
+         loadreg(3,_op4);
+      end;
+
+     constructor taicpu.op_reg_bool_reg_const(op : tasmop;_op1: tregister;_op2:boolean;_op3:tregister;_op4: longint);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031230);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031231);
+         ops:=4;
+         loadreg(0,_op1);
+         loadbool(0,_op2);
+         loadreg(0,_op3);
+         loadconst(0,cardinal(_op4));
+      end;
+
+
+     constructor taicpu.op_reg_reg_reg_const_const(op : tasmop;_op1,_op2,_op3 : tregister;_op4,_op5 : Longint);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031232);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031233);
+         if (_op3.enum = R_INTREGISTER) and (_op3.number = NR_NO) then
+           internalerror(2003031233);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadreg(2,_op3);
+         loadconst(3,cardinal(_op4));
+         loadconst(4,cardinal(_op5));
+      end;
+
+     constructor taicpu.op_reg_reg_const_const_const(op : tasmop;_op1,_op2 : tregister;_op3,_op4,_op5 : Longint);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031232);
+         if (_op2.enum = R_INTREGISTER) and (_op2.number = NR_NO) then
+           internalerror(2003031233);
+         ops:=5;
+         loadreg(0,_op1);
+         loadreg(1,_op2);
+         loadconst(2,aword(_op3));
+         loadconst(3,cardinal(_op4));
+         loadconst(4,cardinal(_op5));
+      end;
+
+    constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         condition:=cond;
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+     constructor taicpu.op_const_const_sym(op : tasmop;_op1,_op2 : longint; _op3: tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=3;
+         loadconst(0,aword(_op1));
+         loadconst(1,aword(_op2));
+         loadsymbol(2,_op3,0);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_ofs(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint);
+      begin
+         inherited create(op);
+         ops:=1;
+         loadsymbol(0,_op1,_op1ofs);
+      end;
+
+
+     constructor taicpu.op_reg_sym_ofs(op : tasmop;_op1 : tregister;_op2:tasmsymbol;_op2ofs : longint);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadreg(0,_op1);
+         loadsymbol(1,_op2,_op2ofs);
+      end;
+
+
+    constructor taicpu.op_sym_ofs_ref(op : tasmop;_op1 : tasmsymbol;_op1ofs:longint;const _op2 : treference);
+      begin
+         inherited create(op);
+         ops:=2;
+         loadsymbol(0,_op1,_op1ofs);
+         loadref(1,_op2);
+      end;
+
+
+{ ****************************** newra stuff *************************** }
+
+    function taicpu.is_nop: boolean;
+      begin
+        { we don't insert any more nops than necessary }
+        is_nop := false;
+      end;
+
+
+    function taicpu.is_move:boolean;
+      begin
+        is_move := opcode = A_MR;
+      end;
+
+
+    function taicpu.spill_registers(list:Taasmoutput;
+                             rgget:Trggetproc;
+                             rgunget:Trgungetproc;
+                             r:Tsupregset;
+                             var unusedregsint:Tsupregset;
+                              const spilltemplist:Tspill_temp_list): boolean;
+
+      function get_insert_pos(p:Tai;huntfor1,huntfor2,huntfor3:Tsuperregister):Tai;
+
+      var back:Tsupregset;
+
+      begin
+        back:=unusedregsint;
+        get_insert_pos:=p;
+        while (p<>nil) and (p.typ=ait_regalloc) do
+          begin
+            {Rewind the register allocation.}
+            if Tai_regalloc(p).allocation then
+              include(unusedregsint,Tai_regalloc(p).reg.number shr 8)
+            else
+              begin
+                exclude(unusedregsint,Tai_regalloc(p).reg.number shr 8);
+                if Tai_regalloc(p).reg.number shr 8=huntfor1 then
+                  begin
+                    get_insert_pos:=Tai(p.previous);
+                    back:=unusedregsint;
+                  end;
+                if Tai_regalloc(p).reg.number shr 8=huntfor2 then
+                  begin
+                    get_insert_pos:=Tai(p.previous);
+                    back:=unusedregsint;
+                  end;
+                if Tai_regalloc(p).reg.number shr 8=huntfor3 then
+                  begin
+                    get_insert_pos:=Tai(p.previous);
+                    back:=unusedregsint;
+                  end;
+              end;
+            p:=Tai(p.previous);
+          end;
+        unusedregsint:=back;
+      end;
+
+      procedure forward_allocation(p:Tai);
+
+      begin
+        {Forward the register allocation again.}
+        while (p<>self) do
+          begin
+            if p.typ<>ait_regalloc then
+              internalerror(200305311);
+            if Tai_regalloc(p).allocation then
+              exclude(unusedregsint,Tai_regalloc(p).reg.number shr 8)
+            else
+              include(unusedregsint,Tai_regalloc(p).reg.number shr 8);
+            p:=Tai(p.next);
+          end;
+      end;
+
+
+      function decode_loadstore(op: tasmop; var counterpart: tasmop; wasload: boolean): boolean;
+
+        begin
+          result := true;
+          wasload := true;
+          case op of
+            A_LBZ:
+              begin
+                counterpart := A_STB;
+              end;
+            A_LBZX:
+              begin
+                counterpart := A_STBX;
+              end;
+            A_LHZ,A_LHA:
+              begin
+                counterpart := A_STH;
+              end;
+            A_LHZX,A_LHAX:
+              begin
+                counterpart := A_STHX;
+              end;
+            A_LWZ:
+              begin
+                counterpart := A_STW;
+              end;
+            A_LWZX:
+              begin
+                counterpart := A_STWX;
+              end;
+            A_STB:
+              begin
+                counterpart := A_LBZ;
+                wasload := false;
+              end;
+            A_STBX:
+              begin
+                counterpart := A_LBZX;
+                wasload := false;
+              end;
+            A_STH:
+              begin
+                counterpart := A_LHZ;
+                wasload := false;
+              end;
+            A_STHX:
+              begin
+                counterpart := A_LHZX;
+                wasload := false;
+              end;
+            A_STW:
+              begin
+                counterpart := A_LWZ;
+                wasload := false;
+              end;
+            A_STWX:
+              begin
+                counterpart := A_LWZX;
+                wasload := false;
+              end;
+            A_LBZU,A_LBZUX,A_LHZU,A_LHZUX,A_LHAU,A_LHAUX,
+            A_LWZU,A_LWZUX,A_STBU,A_STBUX,A_STHU,A_STHUX,
+            A_STWU,A_STWUX:
+              internalerror(2003070602);
+            else
+              result := false;
+          end;
+       end;
+
+
+    var i:byte;
+        supreg, reg1, reg2, reg3: Tsuperregister;
+        helpreg:Tregister;
+        helpins:Taicpu;
+        op:Tasmop;
+        pos:Tai;
+        wasload: boolean;
+
+      begin
+        spill_registers:=false;
+        if (ops = 2) and
+           (oper[1].typ=top_ref) and
+           { oper[1] can also be ref in case of "lis r3,symbol@ha" or so }
+           decode_loadstore(opcode,op,wasload) then
+          begin
+            { the register that's being stored/loaded }
+            supreg:=oper[0].reg.number shr 8;
+            if supreg in r then
+              begin
+                // Example:
+                //   l?? r20d, 8(r1)   ; r20d must be spilled into -60(r1)
+                //
+                //   Change into:
+                //
+                //   l?? r21d, 8(r1)
+                //   st? r21d, -60(r1)
+                //
+                // And:
+                //
+                //   st? r20d, 8(r1)   ; r20d must be spilled into -60(r1)
+                //
+                //   Change into:
+                //
+                //   l?? r21d, -60(r1)
+                //   st? r21d, 8(r1)
+
+                pos := get_insert_pos(Tai(previous),oper[0].reg.number shr 8,
+                                      oper[1].ref^.base.number shr 8,oper[1].ref^.index.number shr 8);
+                rgget(list,pos,0,helpreg);
+                spill_registers := true;
+                if wasload then
+                  begin
+                    helpins := taicpu.op_reg_ref(opcode,helpreg,oper[1].ref^);
+                    loadref(1,spilltemplist[supreg]);
+                    opcode := op;
+                  end
+                else
+                  helpins := taicpu.op_reg_ref(op,helpreg,spilltemplist[supreg]);
+                if pos=nil then
+                  list.insertafter(helpins,list.first)
+                else
+                  list.insertafter(helpins,pos.next);
+                loadreg(0,helpreg);
+                rgunget(list,helpins,helpreg);
+                forward_allocation(tai(helpins.next));
+{$ifdef debugra}
+                writeln('spilling!');
+                list.insertafter(tai_comment.Create(strpnew('Spilling!')),helpins);
+{$endif debugra}
+              end;
+
+            { now the registers used in the reference }
+            { a) base                                 }
+            supreg := oper[1].ref^.base.number shr 8;
+            if supreg in r then
+              begin
+                if wasload then
+                  pos:=get_insert_pos(Tai(previous),oper[1].ref^.index.number shr 8,oper[0].reg.number shr 8,0)
+                else
+                  pos:=get_insert_pos(Tai(previous),oper[1].ref^.index.number shr 8,0,0);
+                rgget(list,pos,0,helpreg);
+                spill_registers:=true;
+                helpins:=Taicpu.op_reg_ref(A_LWZ,helpreg,spilltemplist[supreg]);
+                if pos=nil then
+                  list.insertafter(helpins,list.first)
+                else
+                  list.insertafter(helpins,pos.next);
+                oper[1].ref^.base:=helpreg;
+                rgunget(list,helpins,helpreg);
+                forward_allocation(Tai(helpins.next));
+{$ifdef debugra}
+                writeln('spilling!');
+                list.insertafter(tai_comment.Create(strpnew('Spilling!')),helpins);
+{$endif debugra}
+              end;
+
+            { b) index }
+            supreg := oper[1].ref^.index.number shr 8;
+            if supreg in r then
+              begin
+                if wasload then
+                  pos:=get_insert_pos(Tai(previous),oper[1].ref^.base.number shr 8,oper[0].reg.number shr 8,0)
+                else
+                  pos:=get_insert_pos(Tai(previous),oper[1].ref^.base.number shr 8,0,0);
+                rgget(list,pos,0,helpreg);
+                spill_registers:=true;
+                helpins:=Taicpu.op_reg_ref(A_LWZ,helpreg,spilltemplist[supreg]);
+                if pos=nil then
+                  list.insertafter(helpins,list.first)
+                else
+                  list.insertafter(helpins,pos.next);
+                oper[1].ref^.index:=helpreg;
+                rgunget(list,helpins,helpreg);
+                forward_allocation(Tai(helpins.next));
+{$ifdef debugra}
+                writeln('spilling!');
+                list.insertafter(tai_comment.Create(strpnew('Spilling!')),helpins);
+{$endif debugra}
+              end;
+            { load/store is done }
+            exit;
+          end;
+
+        { all other instructions the compiler generates are the same (I hope):   }
+        { operand 0 is a register and is the destination, the others are sources }
+        { and can be either registers or constants                               }
+        { exception: branches (is_jmp isn't always set for them)                 }
+        if oper[0].typ <> top_reg then
+          exit;
+        reg1 := oper[0].reg.number shr 8;
+        if oper[1].typ = top_reg then
+          reg2 := oper[1].reg.number shr 8
+        else
+          reg2 := 0;
+        if (ops >= 3) and
+           (oper[2].typ = top_reg) then
+          reg3 := oper[2].reg.number shr 8
+        else
+          reg3 := 0;
+
+        supreg:=reg1;
+        if supreg in r then
+          begin
+            // Example:
+            //   add r20d, r21d, r22d   ; r20d must be spilled into -60(r1)
+            //
+            //   Change into:
+            //
+            //   lwz r23d, -60(r1)
+            //   add r23d, r21d, r22d
+            //   stw r23d, -60(r1)
+
+            pos := get_insert_pos(Tai(previous),reg1,reg2,reg3);
+            rgget(list,pos,0,helpreg);
+            spill_registers := true;
+            helpins := taicpu.op_reg_ref(A_STW,helpreg,spilltemplist[supreg]);
+            list.insertafter(helpins,self);
+            helpins := taicpu.op_reg_ref(A_LWZ,helpreg,spilltemplist[supreg]);
+            if pos=nil then
+              list.insertafter(helpins,list.first)
+            else
+              list.insertafter(helpins,pos.next);
+            loadreg(0,helpreg);
+            rgunget(list,helpins,helpreg);
+            forward_allocation(tai(helpins.next));
+{$ifdef debugra}
+            writeln('spilling!');
+            list.insertafter(tai_comment.Create(strpnew('Spilling!')),helpins);
+{$endif debugra}
+          end;
+
+        for i := 1 to 2 do
+          if (oper[i].typ = top_reg) then
+            begin
+              supreg:=oper[i].reg.number;
+              if supreg in r then
+                begin
+                  // Example:
+                  //   add r20d, r21d, r22d   ; r20d must be spilled into -60(r1)
+                  //
+                  //   Change into:
+                  //
+                  //   lwz r23d, -60(r1)
+                  //   add r23d, r21d, r22d
+                  //   stw r23d, -60(r1)
+
+                  pos := get_insert_pos(Tai(previous),reg1,reg2,reg3);
+                  rgget(list,pos,0,helpreg);
+                  spill_registers := true;
+                  helpins := taicpu.op_reg_ref(A_LWZ,helpreg,spilltemplist[supreg]);
+                  if pos=nil then
+                    list.insertafter(helpins,list.first)
+                  else
+                    list.insertafter(helpins,pos.next);
+                  loadreg(i,helpreg);
+                  rgunget(list,helpins,helpreg);
+                  forward_allocation(tai(helpins.next));
+{$ifdef debugra}
+                  writeln('spilling!');
+                  list.insertafter(tai_comment.Create(strpnew('Spilling!')),helpins);
+{$endif debugra}
+                end;
+            end;
+      end;
+
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+end.
+{
+  $Log$
+  Revision 1.1  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+}

+ 260 - 0
compiler/arm/agarmgas.pas

@@ -0,0 +1,260 @@
+{
+    $Id$
+    Copyright (c) 2003 by Florian Klaempfl
+
+    This unit implements an asm for the ARM
+
+    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.
+
+ ****************************************************************************
+}
+{ This unit implements the GNU Assembler writer for the ARM
+}
+
+unit agarmgas;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       aasmtai,
+       aggas,
+       cpubase;
+
+    type
+      PARMGNUAssembler=^TARMGNUAssembler;
+      TARMGNUAssembler=class(TGNUassembler)
+        procedure WriteInstruction(hp : tai);override;
+      end;
+
+  implementation
+
+    uses
+       cutils,globals,verbose,
+       systems,
+       assemble,
+       aasmcpu;
+
+    const
+       as_arm_gas_info : tasminfo =
+          (
+            id     : as_gas;
+
+            idtxt  : 'AS';
+            asmbin : 'as';
+            asmcmd : '-o $OBJ $ASM';
+            supported_target : system_any;
+            outputbinary: false;
+            allowdirect : true;
+            needar : true;
+            labelprefix_only_inside_procedure : false;
+            labelprefix : '.L';
+            comment : '# ';
+            secnames : ('',
+              '.text','.data','.text',
+              '','','','','','',
+              '.stab','.stabstr','COMMON')
+          );
+
+    function getreferencestring(var ref : treference) : string;
+    var
+      s : string;
+    begin
+       with ref do
+        begin
+          inc(offset,offsetfixup);
+
+          if not assigned(symbol) then
+            s := '['
+          else
+            s:='['+symbol.name;
+
+          if offset<0 then
+           s:=s+tostr(offset)
+          else
+           if (offset>0) then
+            begin
+              if assigned(symbol) then
+               s:=s+'+'+tostr(offset)
+              else
+               s:=s+tostr(offset);
+            end;
+
+           if (index.enum < firstreg) or (index.enum > lastreg) then
+             internalerror(20030312);
+           if (base.enum < firstreg) or (base.enum > lastreg) then
+             internalerror(200303123);
+           if (index.enum=R_NO) and (base.enum<>R_NO) then
+             begin
+                if offset=0 then
+                  begin
+                     if assigned(symbol) then
+                       s:=s+'+0'
+                     else
+                       s:=s+'0';
+                  end;
+                s:=s+'['+std_reg2str[base.enum]+']'
+             end
+           else if (index.enum<>R_NO) and (base.enum<>R_NO) and (offset=0) then
+             s:=s+std_reg2str[base.enum]+','+std_reg2str[index.enum]
+           else if ((index.enum<>R_NO) or (base.enum<>R_NO)) then
+             internalerror(19992);
+        end;
+      getreferencestring:=s;
+    end;
+
+
+    function getopstr_jmp(const o:toper) : string;
+    var
+      hs : string;
+    begin
+      case o.typ of
+        top_reg :
+          begin
+            if (o.reg.enum < R_R0) or (o.reg.enum > lastreg) then
+              internalerror(200303121);
+            getopstr_jmp:=std_reg2str[o.reg.enum];
+          end;
+        top_shifter:
+          begin
+          end;
+        { no top_ref jumping for powerpc }
+        top_const :
+          getopstr_jmp:=tostr(o.val);
+        top_symbol :
+          begin
+            hs:=o.sym.name;
+            if o.symofs>0 then
+             hs:=hs+'+'+tostr(o.symofs)
+            else
+             if o.symofs<0 then
+              hs:=hs+tostr(o.symofs);
+            getopstr_jmp:=hs;
+          end;
+        top_none:
+          getopstr_jmp:='';
+        else
+{$ifndef testing}
+          internalerror(2002070603);
+{$else testing}
+          begin
+            writeln('internalerror 10001');
+            halt(1);
+          end;
+{$endif testing}
+      end;
+    end;
+
+    const
+      shifterop2str: array[tshiftertype] of string[3] = ('','asr','lsl','lsr','ror','rrx');
+
+    function getopstr(const o:toper) : string;
+    var
+      hs : string;
+    begin
+      case o.typ of
+        top_reg:
+          begin
+            if (o.reg.enum < R_R0) or (o.reg.enum > lastreg) then
+              internalerror(200303125);
+            getopstr:=std_reg2str[o.reg.enum];
+          end;
+        top_shifter:
+          begin
+          end;
+        top_const:
+          getopstr:=tostr(longint(o.val));
+        top_ref:
+          getopstr:=getreferencestring(o.ref^);
+        top_symbol:
+          begin
+            hs:=o.sym.name;
+            if o.symofs>0 then
+             hs:=hs+'+'+tostr(o.symofs)
+            else
+             if o.symofs<0 then
+              hs:=hs+tostr(o.symofs);
+            getopstr:=hs;
+          end;
+        else
+{$ifndef testing}
+          internalerror(2002070604);
+{$else testing}
+          begin
+            writeln('internalerror 10001');
+            halt(1);
+          end;
+{$endif testing}
+      end;
+    end;
+
+    Procedure TARMGNUAssembler.WriteInstruction(hp : tai);
+    var op: TAsmOp;
+        s: string;
+        i: byte;
+        sep: string[3];
+    begin
+      op:=taicpu(hp).opcode;
+      if is_calljmp(op) then
+        begin
+{
+          { direct BO/BI in op[0] and op[1] not supported, put them in condition! }
+          case op of
+             A_B,A_BA,A_BL,A_BLA:
+               s:=#9+op2str[op]+#9;
+             A_BCTR,A_BCTRL,A_BLR,A_BLRL:
+               s:=#9+op2str[op]
+             else
+               s:=cond2str(op,taicpu(hp).condition)+',';
+          end;
+
+          if (taicpu(hp).oper[0].typ <> top_none) then
+            s:=s+getopstr_jmp(taicpu(hp).oper[0]);
+}
+        end
+      else
+        { process operands }
+        begin
+          s:=#9+std_op2str[op];
+          if taicpu(hp).ops<>0 then
+            begin
+            {
+              if not is_calljmp(op) then
+                sep:=','
+              else
+            }
+                sep:=#9;
+              for i:=0 to taicpu(hp).ops-1 do
+                begin
+                   // debug code
+                   // writeln(s);
+                   // writeln(taicpu(hp).fileinfo.line);
+                   s:=s+sep+getopstr(taicpu(hp).oper[i]);
+                   sep:=',';
+                end;
+            end;
+        end;
+      AsmWriteLn(s);
+    end;
+
+begin
+  RegisterAssembler(as_arm_gas_info,TARMGNUAssembler);
+end.
+{
+  $Log$
+  Revision 1.1  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+}

+ 315 - 217
compiler/arm/cpubase.pas

@@ -32,10 +32,14 @@ interface
 
 uses
   cutils,cclasses,
-  globals,
+  globtype,globals,
   cpuinfo,
   aasmbase,
-  cginfo;
+  cginfo
+{$ifdef delphi}
+  ,dmisc
+{$endif}
+  ;
 
 
 {*****************************************************************************
@@ -43,18 +47,18 @@ uses
 *****************************************************************************}
 
     type
-      TAsmOp=(A_ADC,A_ADD,A_AND,A_N,A_BIC,A_BKPT,A_BL,A_BLX,A_BX,
+      TAsmOp=(A_None,A_ADC,A_ADD,A_AND,A_N,A_BIC,A_BKPT,A_B,A_BL,A_BLX,A_BX,
               A_CDP,A_CDP2,A_CLZ,A_CMN,A_CMP,A_EOR,A_LDC,_A_LDC2,
               A_LDM,A_LDR,A_LDRB,A_LDRD,A_LDRBT,A_LDRH,A_LDRSB,
               A_LDRSH,A_LDRT,A_MCR,A_MCR2,A_MCRR,A_MLA,A_MOV,
               A_MRC,A_MRC2,A_MRRC,A_RS,A_MSR,A_MUL,A_MVN,
               A_ORR,A_PLD,A_QADD,A_QDADD,A_QDSUB,A_QSUB,A_RSB,A_RSC,
-              A_SBC,A_SMLAL.A_SMLA,A_SMLAL,A_SMLAW,A_SMULL,A_SMUL,
+              A_SBC,A_SMLAL,A_SMULL,A_SMUL,
               A_SMULW,A_STC,A_STC2,A_STM,A_STR,A_STRB,A_STRBT,A_STRD,
-              A_STRH,A_STRT,A_SUB,A_SWI,A_SWP,A_SWPB,A_TEQ,A_TST.
+              A_STRH,A_STRT,A_SUB,A_SWI,A_SWP,A_SWPB,A_TEQ,A_TST,
               A_UMLAL,A_UMULL
-              { FPU coprocessor codes }
-              { Vec unit coprocessor codes }
+              { FPA coprocessor codes }
+              { VPA coprocessor codes }
               );
 
       { This should define the array of instructions as string }
@@ -66,18 +70,6 @@ uses
       { Last value of opcode enumeration  }
       lastop  = high(tasmop);
 
-{*****************************************************************************
-                                Operand Sizes
-*****************************************************************************}
-
-    type
-      topsize = (S_NO,
-        S_B,S_W,S_L,S_BW,S_BL,S_WL,
-        S_IS,S_IL,S_IQ,
-        S_FS,S_FL,S_FX,S_D,S_Q,S_FV,
-        S_NEAR,S_FAR,S_SHORT
-      );
-
 {*****************************************************************************
                                   Registers
 *****************************************************************************}
@@ -91,13 +83,61 @@ uses
       { don't change the order }
       { it's used by the register size conversions        }
       toldregister = (R_NO,
-        R_RAX,R_RCX,R_RDX,R_RBX,R_RSP,R_RBP,R_RSI,R_RDI,
         R_R0,R_R1,R_R2,R_R3,R_R4,R_R5,R_R6,R_R7,
         R_R8,R_R9,R_R10,R_R11,R_R12,R_R13,R_R14,R_PC,
-        R_CPSR
+        R_CPSR,
+        { FPA registers }
+        R_F0,R_F1,R_F2,R_F3,R_F4,R_F5,R_F6,R_F7,
+        R_F8,R_F9,R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,
+        { VPA registers }
+        R_S0,R_S1,R_S2,R_S3,R_S4,R_S5,R_S6,R_S7,
+        R_S8,R_S9,R_S10,R_S11,R_S12,R_S13,R_S14,R_S15,
+        R_S16,R_S17,R_S18,R_S19,R_S20,R_S21,R_S22,R_S23,
+        R_S24,R_S25,R_S26,R_S27,R_S28,R_S29,R_S30,R_S31,
+        R_D0,R_D1,R_D2,R_D3,R_D4,R_D5,R_D6,R_D7,
+        R_D8,R_D9,R_D10,R_D11,R_D12,R_D13,R_D14,R_D15,
+        R_INTREGISTER,R_FLOATREGISTER,R_MMXREGISTER,R_KNIREGISTER
       );
 
-   type
+    const
+      { special registers }
+      { Invalid register }
+      NR_NO    = $0000;
+
+      { Normal registers:}
+
+      { General purpose registers }
+      NR_R0 = $0100; NR_R1 = $0200; NR_R2 = $0300;
+      NR_R3 = $0400; NR_R4 = $0500; NR_R5 = $0600;
+      NR_R6 = $0700; NR_R7 = $0800; NR_R8 = $0900;
+      NR_R9 = $0A00; NR_R10 = $0B00; NR_R11 = $0C00;
+      NR_R12 = $0D00; NR_R13 = $0E00; NR_R14 = $0F00;
+      NR_R15 = $1000;
+
+      { Super registers: }
+      RS_NONE=$00;
+      RS_R0 = $01;  RS_R1 = $02; RS_R2 = $03;
+      RS_R3 = $04;  RS_R4 = $05; RS_R5 = $06;
+      RS_R6 = $07;  RS_R7 = $08; RS_R8 = $09;
+      RS_R9 = $0A;  RS_R10 = $0B; RS_R11 = $0C;
+      RS_R12 = $0D; RS_R13 = $0E; RS_R14 = $0F;
+      RS_R15 = $10;
+
+      first_supreg = RS_R0;
+      last_supreg = RS_R15;
+
+      { registers which may be destroyed by calls }
+      VOLATILE_INTREGISTERS = [RS_R0..RS_R3];
+
+      { Number of first and last imaginary register. }
+      first_imreg     = $21;
+      last_imreg      = $ff;
+
+      { Subregisters, situation unknown!!.}
+      R_SUBWHOLE=$00;
+      R_SUBL=$00;
+
+    type
       tnewregister=word;
 
       Tregister = packed record
@@ -119,61 +159,44 @@ uses
       treg64 = tregister64;
 
       { Set type definition for registers }
-      tregisterset = set of tregister;
+      tregisterset = set of toldregister;
       tsupregset = set of tsuperregister;
 
-      { Type definition for the array of string of register names }
-      reg2strtable = array[tregister] of string[6];
-
     const
-      {# First register in the tregister enumeration }
-      firstreg = low(tregister);
-      {# Last register in the tregister enumeration }
-      lastreg  = high(tregister);
-
-      firstsreg = R_CS;
-      lastsreg  = R_GS;
-
-      regset8bit  : tregisterset = [R_AL..R_DH];
-      regset16bit : tregisterset = [R_AX..R_DI,R_CS..R_SS];
-      regset32bit : tregisterset = [R_EAX..R_EDI];
-
-      { Convert reg to opsize }
-      reg2opsize : array[firstreg..lastreg] of topsize = (S_NO,
-        S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
-        S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
-        S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
-        S_W,S_W,S_W,S_W,S_W,S_W,
-        S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,S_FL,
-        S_L,S_L,S_L,S_L,S_L,S_L,
-        S_L,S_L,S_L,S_L,
-        S_L,S_L,S_L,S_L,S_L,
-        S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D,
-        S_D,S_D,S_D,S_D,S_D,S_D,S_D,S_D
-      );
+      { First register in the tregister enumeration }
+      firstreg = low(toldregister);
+      { Last register in the tregister enumeration }
+      lastreg  = R_D15;
 
-      {# Standard opcode string table (for each tasmop enumeration). The
-         opcode strings should conform to the names as defined by the
-         processor manufacturer.
-      }
-      std_op2str:op2strtable={$i i386int.inc}
+    type
+      { Type definition for the array of string of register names }
+      reg2strtable = array[firstreg..lastreg] of string[6];
+      regname2regnumrec = record
+        name:string[6];
+        number:Tnewregister;
+      end;
 
-      {# Standard register table (for each tregister enumeration). The
-         register strings should conform to the the names as defined
-         by the processor manufacturer
+{*****************************************************************************
+                          Instruction post fixes
+*****************************************************************************}
+    type
+      { ARM instructions load/store and arithmetic instructions
+        can have several instruction post fixes which are collected
+        in this enumeration
       }
-      std_reg2str : reg2strtable = ('',
-        'eax','ecx','edx','ebx','esp','ebp','esi','edi',
-        'ax','cx','dx','bx','sp','bp','si','di',
-        'al','cl','dl','bl','ah','ch','bh','dh',
-        'cs','ds','es','ss','fs','gs',
-        'st','st(0)','st(1)','st(2)','st(3)','st(4)','st(5)','st(6)','st(7)',
-        'dr0','dr1','dr2','dr3','dr6','dr7',
-        'cr0','cr2','cr3','cr4',
-        'tr3','tr4','tr5','tr6','tr7',
-        'mm0','mm1','mm2','mm3','mm4','mm5','mm6','mm7',
-        'xmm0','xmm1','xmm2','xmm3','xmm4','xmm5','xmm6','xmm7'
+      TOpPostfix = (PF_None,
+        { update condition flags }
+        PF_S,
+        { load/store }
+        PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T,
+        { multiple load/store address modes }
+        PF_IA,PF_IB,PF_DA,PF_DB,PF_DF,PF_FA,PF_ED,PF_EA
       );
+    const
+      oppostfix2str : array[TOpPostfix] of string[2] = ('',
+        's',
+        'b','sb','bt','h','sh','t',
+        'ia','ib','da','db','df','fa','ed','ea');
 
 {*****************************************************************************
                                 Conditions
@@ -186,13 +209,14 @@ uses
       );
 
     const
-      cond2str:array[TAsmCond] of string[2]=('',
+      cond2str : array[TAsmCond] of string[2]=('',
         'eq','ne','cs','cc','mi','pl','vs','vc','hi','ls',
         'ge','lt','gt','le','al','nv'
       );
 
-      inverse_cond:array[TAsmCond] of TAsmCond=(C_None,
-
+      inverse_cond : array[TAsmCond] of TAsmCond=(C_None,
+        C_NE,C_EQ,C_CC,C_CS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI,
+        C_LT,C_GE,C_LE,C_GT,C_None,C_None
       );
 
 {*****************************************************************************
@@ -200,7 +224,8 @@ uses
 *****************************************************************************}
 
     type
-      TResFlags = (F_E,F_NE,F_G,F_L,F_GE,F_LE,F_C,F_NC,F_A,F_AE,F_B,F_BE);
+      TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS,
+        F_GE,F_LT,F_GT,F_LE);
 
 {*****************************************************************************
                                 Reference
@@ -209,10 +234,12 @@ uses
     type
       trefoptions=(ref_none,ref_parafixup,ref_localfixup,ref_selffixup);
 
+      taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED);
+      tshiftmode = (SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
+
       { reference record }
       preference = ^treference;
       treference = packed record
-         segment,
          base,
          index       : tregister;
          scalefactor : byte;
@@ -220,6 +247,8 @@ uses
          symbol      : tasmsymbol;
          offsetfixup : longint;
          options     : trefoptions;
+         addressmode : taddressmode;
+         shiftmode   : tshiftmode;
       end;
 
       { reference record }
@@ -234,16 +263,31 @@ uses
 *****************************************************************************}
 
       { Types of operand }
-      toptype=(top_none,top_reg,top_ref,top_const,top_symbol);
+      toptype=(top_none,top_reg,top_ref,top_const,top_symbol,top_regset,top_shifter);
+
+      tupdatereg = (UR_None,UR_Update);
+
+
+      tshiftertype = (SO_None,SO_ASR,SO_LSL,SO_LSR,SO_ROR,SO_RRX);
 
-      toper=record
-        ot  : longint;
+      pshifterop = ^tshifterop;
+
+      tshifterop = record
+        imm : dword;
+        rm : tregister;
+        rs : tregister;
+        shiftimm : byte;
+      end;
+
+      toper = record
         case typ : toptype of
          top_none   : ();
-         top_reg    : (reg:tregister);
+         top_reg    : (reg:tregister;update:tupdatereg);
          top_ref    : (ref:preference);
          top_const  : (val:aword);
          top_symbol : (sym:tasmsymbol;symofs:longint);
+         top_regset : (regset:tsupregset);
+         top_shifter : (shifterop : pshifterop);
       end;
 
 {*****************************************************************************
@@ -251,32 +295,15 @@ uses
 *****************************************************************************}
 
     type
-      TLoc=(
-        LOC_INVALID,      { added for tracking problems}
-        LOC_CONSTANT,     { constant value }
-        LOC_JUMP,         { boolean results only, jump to false or true label }
-        LOC_FLAGS,        { boolean results only, flags are set }
-        LOC_CREFERENCE,   { in memory constant value reference (cannot change) }
-        LOC_REFERENCE,    { in memory value }
-        LOC_REGISTER,     { in a processor register }
-        LOC_CREGISTER,    { Constant register which shouldn't be modified }
-        LOC_FPUREGISTER,  { FPU stack }
-        LOC_CFPUREGISTER, { if it is a FPU register variable on the fpu stack }
-        LOC_MMXREGISTER,  { MMX register }
-        LOC_CMMXREGISTER, { MMX register variable }
-        LOC_SSEREGISTER,
-        LOC_CSSEREGISTER
-      );
-
       { tparamlocation describes where a parameter for a procedure is stored.
         References are given from the caller's point of view. The usual
         TLocation isn't used, because contains a lot of unnessary fields.
       }
       tparalocation = packed record
          size : TCGSize;
-         loc  : TLoc;
+         loc  : TCGLoc;
          sp_fixup : longint;
-         case TLoc of
+         case TCGLoc of
             LOC_REFERENCE : (reference : tparareference);
             { segment in reference at the same place as in loc_register }
             LOC_REGISTER,LOC_CREGISTER : (
@@ -293,9 +320,9 @@ uses
       end;
 
       tlocation = packed record
-         loc  : TLoc;
+         loc  : TCGLoc;
          size : TCGSize;
-         case TLoc of
+         case TCGLoc of
             LOC_FLAGS : (resflags : tresflags);
             LOC_CONSTANT : (
               case longint of
@@ -333,23 +360,18 @@ uses
 
       max_operands = 3;
 
-      lvaluelocations = [LOC_REFERENCE,LOC_CFPUREGISTER,
-        LOC_CREGISTER,LOC_MMXREGISTER,LOC_CMMXREGISTER];
-
       {# Constant defining possibly all registers which might require saving }
       ALL_REGISTERS = [firstreg..lastreg];
 
-      general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
-
       {# low and high of the available maximum width integer general purpose }
       { registers                                                            }
-      LoGPReg = R_EAX;
-      HiGPReg = R_EDX;
+      LoGPReg = R_R0;
+      HiGPReg = R_R14;
 
       {# low and high of every possible width general purpose register (same as }
       { above on most architctures apart from the 80x86)                        }
-      LoReg = R_EAX;
-      HiReg = R_DH;
+      LoReg = R_R0;
+      HiReg = R_R14;
 
       {# Table of registers which can be allocated by the code generator
          internally, when generating the code.
@@ -363,177 +385,253 @@ uses
       {           passing on ABI's that define this)                           }
       { c_countusableregsxxx = amount of registers in the usableregsxxx set    }
 
-      maxintregs = 4;
-      intregs = [R_EAX..R_BL];
-      usableregsint = [R_EAX,R_EBX,R_ECX,R_EDX];
-      c_countusableregsint = 4;
+      maxintregs = 15;
+      intregs = [R_R0..R_R14];
+      usableregsint = [RS_R4..RS_R10];
+      c_countusableregsint = 7;
 
       maxfpuregs = 8;
-      fpuregs = [R_ST0..R_ST7];
-      usableregsfpu = [];
-      c_countusableregsfpu = 0;
+      fpuregs = [R_F0..R_F7];
+      usableregsfpu = [R_F4..R_F7];
+      c_countusableregsfpu = 4;
+
+      mmregs = [R_S0..R_D7];
+      usableregsmm = [R_S16..R_S31];
+      c_countusableregsmm  = 16;
+
+{*****************************************************************************
+                                Operand Sizes
+*****************************************************************************}
+
+    type
+      topsize = (S_NO,
+        S_B,S_W,S_L,S_BW,S_BL,S_WL,
+        S_IS,S_IL,S_IQ,
+        S_FS,S_FL,S_FX,S_D,S_Q,S_FV,S_FXX
+      );
+
+{*****************************************************************************
+                                Registers
+*****************************************************************************}
+    const
+        { Standard opcode string table (for each tasmop enumeration). The
+          opcode strings should conform to the names as defined by the
+          processor manufacturer.
+        }
+        std_op2str : op2strtable = (
+                '','adc','add','and','n','bic','bkpt','b','bl','blx','bx',
+                'cdp','cdp2','clz','cmn','cmp','eor','ldc','ldc2',
+                'ldm','ldr','ldrb','ldrd','ldrbt','ldrh','ldrsb',
+                'ldrsh','ldrt','mcr','mcr2','mcrr','mla','mov',
+                'mrc','mrc2','mrrc','rs','msr','mul','mvn',
+                'orr','pld','qadd','qdadd','qdsub','qsub','rsb','rsc',
+                'sbc','smlal','smull','smul',
+                'smulw','stc','stc2','stm','str','strb','strbt','strd',
+                'strh','strt','sub','swi','swp','swpb','teq','tst',
+                'umlal','umull'
+                { FPA coprocessor codes }
+                { VPA coprocessor codes }
+                );
+
+        { Standard register table (for each tregister enumeration). The
+          register strings should conform to the the names as defined
+          by the processor manufacturer
+        }
+        std_reg2str : reg2strtable = ('',
+          'r0','r1','r2','r3','r4','r5','r6','r7',
+          'r8','r9','r10','r11','r12','r13','r14','pc',
+          'cpsr',
+          { FPA registers }
+          'f0','f1','f2','f3','f4','f5','f6','f7',
+          'f8','f9','f10','f11','f12','f13','f14','f15',
+          { VPA registers }
+          's0','s1','s2','s3','s4','s5','s6','s7',
+          's8','s9','s10','s11','s12','s13','s14','s15',
+          's16','s17','s18','s19','s20','s21','s22','s23',
+          's24','s25','s26','s27','s28','s29','s30','s31',
+          'd0','d1','d2','d3','d4','d5','d6','d7',
+          'd8','d9','d10','d11','d12','d13','d14','d15'
+        );
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
 
-      mmregs = [R_MM0..R_MM7];
-      usableregsmm = [R_MM0..R_MM7];
-      c_countusableregsmm  = 8;
+      firstsaveintreg = R_R4;
+      lastsaveintreg  = R_R10;
+      firstsavefpureg = R_F4;
+      lastsavefpureg  = R_F7;
+      firstsavemmreg  = R_S16;
+      lastsavemmreg   = R_S31;
 
-      firstsaveintreg = R_EAX;
-      lastsaveintreg  = R_EBX;
-      firstsavefpureg = R_NO;
-      lastsavefpureg  = R_NO;
-      firstsavemmreg  = R_MM0;
-      lastsavemmreg   = R_MM7;
+//!!!      general_registers = [R_EAX,R_EBX,R_ECX,R_EDX];
+//!!!      general_superregisters = [RS_EAX,RS_EBX,RS_ECX,RS_EDX];
 
-      maxvarregs = 4;
-      varregs : array[1..maxvarregs] of tregister =
-         (R_EBX,R_EDX,R_ECX,R_EAX);
 
-      maxfpuvarregs = 8;
+//!!!      usableregsint = [first_imreg..last_imreg];
+//!!!      c_countusableregsint = 4;
 
-      {# Registers which are defined as scratch and no need to save across
-         routine calls or in assembler blocks.
-      }
-      max_scratch_regs = 1;
-      scratch_regs : array[1..max_scratch_regs] of tregister = (R_EDI);
+      maxaddrregs = 0;
+      addrregs    = [];
+      usableregsaddr = [];
+      c_countusableregsaddr = 0;
 
+      maxvarregs = 7;
+      varregs : Array [1..maxvarregs] of Tnewregister =
+                (RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,RS_R10);
+
+      maxfpuvarregs = 4;
+      fpuvarregs : Array [1..maxfpuvarregs] of Toldregister =
+                (R_F4,R_F5,R_F6,R_F7);
 
 {*****************************************************************************
                                GDB Information
 *****************************************************************************}
 
-      {# Register indexes for stabs information, when some
-         parameters or variables are stored in registers.
-
-         Taken from i386.c (dbx_register_map) and i386.h
-          (FIXED_REGISTERS) from GCC 3.x source code
-
+      {
+        I don't know where I could get this information for the arm
       }
-          stab_regindex : array[tregister] of shortint =
-          (-1,
-          0,1,2,3,4,5,6,7,
-          0,1,2,3,4,5,6,7,
-          0,1,2,3,0,1,2,3,
-          -1,-1,-1,-1,-1,-1,
-          12,12,13,14,15,16,17,18,19,
-          -1,-1,-1,-1,-1,-1,
-          -1,-1,-1,-1,
-          -1,-1,-1,-1,-1,
-          29,30,31,32,33,34,35,36,
-          21,22,23,24,25,26,27,28
-        );
+      stab_regindex : array[0..0] of shortint =
+        (0
+      );
 
 {*****************************************************************************
                           Default generic sizes
 *****************************************************************************}
 
-      {# Defines the default address size for a processor, }
+      { Defines the default address size for a processor, }
       OS_ADDR = OS_32;
-      {# the natural int size for a processor,             }
+      { the natural int size for a processor,             }
       OS_INT = OS_32;
-      {# the maximum float size for a processor,           }
-      OS_FLOAT = OS_F80;
-      {# the size of a vector register for a processor     }
-      OS_VECTOR = OS_M64;
+      { the maximum float size for a processor,           }
+      OS_FLOAT = OS_F64;
+      { the size of a vector register for a processor     }
+      OS_VECTOR = OS_M32;
 
 {*****************************************************************************
                           Generic Register names
 *****************************************************************************}
 
-      {# Stack pointer register }
-      stack_pointer_reg = R_ESP;
-      {# Frame pointer register }
-      frame_pointer_reg = R_EBP;
-      {# Self pointer register : contains the instance address of an
-         object or class. }
-      self_pointer_reg  = R_ESI;
-      {# Register for addressing absolute data in a position independant way,
-         such as in PIC code. The exact meaning is ABI specific. For
-         further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
+      { Stack pointer register }
+      NR_STACK_POINTER_REG = NR_R13;
+      RS_STACK_POINTER_REG = RS_R13;
+      { Frame pointer register }
+      frame_pointer_reg = R_R11;
+      RS_FRAME_POINTER_REG = RS_R11;
+      NR_FRAME_POINTER_REG = NR_R11;
+      { Register for addressing absolute data in a position independant way,
+        such as in PIC code. The exact meaning is ABI specific. For
+        further information look at GCC source : PIC_OFFSET_TABLE_REGNUM
       }
-      pic_offset_reg = R_EBX;
-      {# Results are returned in this register (32-bit values) }
-      accumulator   = R_EAX;
-      {# Hi-Results are returned in this register (64-bit value high register) }
-      accumulatorhigh = R_EDX;
-      { WARNING: don't change to R_ST0!! See comments above implementation of }
-      { a_loadfpu* methods in rgcpu (JM)                                      }
-      fpu_result_reg = R_ST;
-      mmresultreg = R_MM0;
+      NR_PIC_OFFSET_REG = NR_R9;
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_R0;
+      RS_FUNCTION_RETURN_REG = RS_R0;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_R0;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_R0;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_R1;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_R1;
+      { The value returned from a function is available in this register }
+      NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
+      RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
+      { The lowh part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
+      RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
+      { The high part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
+      RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
+
+      fpu_result_reg = R_F0;
+//!!!      mmresultreg = R_MM0;
+
+      { Offset where the parent framepointer is pushed }
+      PARENT_FRAMEPOINTER_OFFSET = 0;
 
 {*****************************************************************************
                        GCC /ABI linking information
 *****************************************************************************}
 
     const
-      {# Registers which must be saved when calling a routine declared as
-         cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
-         saved should be the ones as defined in the target ABI and / or GCC.
+      { Registers which must be saved when calling a routine declared as
+        cppdecl, cdecl, stdcall, safecall, palmossyscall. The registers
+        saved should be the ones as defined in the target ABI and / or GCC.
 
-         This value can be deduced from the CALLED_USED_REGISTERS array in the
-         GCC source.
+        This value can be deduced from the CALLED_USED_REGISTERS array in the
+        GCC source.
       }
-      std_saved_registers = [R_ESI,R_EDI,R_EBX];
-      {# Required parameter alignment when calling a routine declared as
-         stdcall and cdecl. The alignment value should be the one defined
-         by GCC or the target ABI.
+      std_saved_registers = [R_R4..R_R10];
+      { Required parameter alignment when calling a routine declared as
+        stdcall and cdecl. The alignment value should be the one defined
+        by GCC or the target ABI.
 
-         The value of this constant is equal to the constant
-         PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
+        The value of this constant is equal to the constant
+        PARM_BOUNDARY / BITS_PER_UNIT in the GCC source.
       }
       std_param_align = 4;
 
-{*****************************************************************************
-                            CPU Dependent Constants
-*****************************************************************************}
 
 {*****************************************************************************
                                   Helpers
 *****************************************************************************}
 
+    procedure convert_register_to_enum(var r:Tregister);
+    function cgsize2subreg(s:Tcgsize):Tsubregister;
+    function reg2opsize(r:tregister):topsize;
     function is_calljmp(o:tasmop):boolean;
-
+    procedure inverse_flags(var f: TResFlags);
     function flags_to_cond(const f: TResFlags) : TAsmCond;
-
+    function supreg_name(r:Tsuperregister):string;
 
 implementation
 
-{*****************************************************************************
-                                  Helpers
-*****************************************************************************}
+    procedure convert_register_to_enum(var r:Tregister);
+      begin
+      end;
+
+
+    function cgsize2subreg(s:Tcgsize):Tsubregister;
+      begin
+      end;
+
+
+    function reg2opsize(r:tregister):topsize;
+      begin
+      end;
+
 
     function is_calljmp(o:tasmop):boolean;
       begin
-        case o of
-          A_CALL,
-          A_JCXZ,
-          A_JECXZ,
-          A_JMP,
-          A_LOOP,
-          A_LOOPE,
-          A_LOOPNE,
-          A_LOOPNZ,
-          A_LOOPZ,
-          A_Jcc :
-            is_calljmp:=true;
-          else
-            is_calljmp:=false;
-        end;
+        { This isn't 100% perfect because the arm allows jumps also by writing to PC=R15.
+          To overcome this problem we simply forbid that FPC generates jumps by loading R15 }
+        is_calljmp:= o in [A_B,A_BL,A_BX,A_BLX];
+      end;
+
+
+    procedure inverse_flags(var f: TResFlags);
+      begin
       end;
 
 
     function flags_to_cond(const f: TResFlags) : TAsmCond;
-      const
-        flags_2_cond : array[TResFlags] of TAsmCond =
-          (C_E,C_NE,C_G,C_L,C_GE,C_LE,C_C,C_NC,C_A,C_AE,C_B,C_BE);
       begin
-        result := flags_2_cond[f];
       end;
 
 
+    function supreg_name(r:Tsuperregister):string;
+      begin
+      end;
+
+
+
 end.
 {
   $Log$
-  Revision 1.2  2003-07-26 00:55:57  florian
+  Revision 1.3  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+
+  Revision 1.2  2003/07/26 00:55:57  florian
     * basic stuff fixed
 
   Revision 1.1  2003/07/21 16:35:30  florian

+ 37 - 62
compiler/arm/cpupara.pas

@@ -39,7 +39,6 @@ unit cpupara;
           function getintparaloc(list: taasmoutput; nr : longint) : tparalocation;override;
           procedure freeintparaloc(list: taasmoutput; nr : longint); override;
           procedure create_paraloc_info(p : tabstractprocdef; side: tcallercallee);override;
-          function getfuncretparaloc(p : tabstractprocdef) : tparalocation;override;
        end;
 
   implementation
@@ -303,80 +302,56 @@ unit cpupara;
                  else
                    internalerror(2002071002);
               end;
-              if side = callerside then
-                hp.callerparaloc:=paraloc
-              else
+              if side = calleeside then
                 begin
                   if (paraloc.loc = LOC_REFERENCE) then
                     paraloc.reference.offset := tvarsym(hp.parasym).adjusted_address;
-                  hp.calleeparaloc:=paraloc;
                 end;
+              hp.paraloc[side]:=paraloc;
               hp:=tparaitem(hp.next);
            end;
-      end;
-
-
-    function tarmparamanager.getfuncretparaloc(p : tabstractprocdef) : tparalocation;
-      begin
-         fillchar(result,sizeof(result),0);
-         case p.rettype.def.deftype of
-            orddef,
-            enumdef:
-              begin
-                getfuncretparaloc.loc:=LOC_REGISTER;
-                getfuncretparaloc.register.enum:=R_INTREGISTER;
-                getfuncretparaloc.register.number:=NR_R0;
-                getfuncretparaloc.size:=def_cgsize(p.rettype.def);
-                if getfuncretparaloc.size in [OS_S64,OS_64] then
-                  begin
-                    getfuncretparaloc.registerhigh.enum:=R_INTREGISTER;
-                    getfuncretparaloc.registerhigh.number:=NR_R0;
-		    getfuncretparaloc.register.number:=NR_R1;
-                  end;
-              end;
-            floatdef:
-              begin
-                getfuncretparaloc.loc:=LOC_FPUREGISTER;
-                getfuncretparaloc.register.enum:=R_F0;
-                getfuncretparaloc.size:=def_cgsize(p.rettype.def);
-              end;
-            { smallsets are OS_INT in R0, others are OS_ADDR in R0 -> the same }
-            { ugly, I know :) (JM)                                             }
-            setdef,
-            variantdef,
-            pointerdef,
-            formaldef,
-            classrefdef,
-            recorddef,
-            objectdef,
-            procvardef,
-            filedef,
-            arraydef,
-            stringdef:
-              begin
-                if (p.rettype.def.deftype <> stringdef) or
-                   (is_ansistring(p.rettype.def) or
-                    is_widestring(p.rettype.def)) then
-                  begin
-                    getfuncretparaloc.loc:=LOC_REGISTER;
-                    getfuncretparaloc.register.enum:=R_INTREGISTER;
-                    getfuncretparaloc.register.number:=NR_R0;
-                    getfuncretparaloc.size:=OS_ADDR;
-                  end
-                else
-                  internalerror(2003061601);
-              end;
+        { Function return }
+        fillchar(paraloc,sizeof(tparalocation),0);
+        paraloc.size:=def_cgsize(p.rettype.def);
+        { Return in FPU register? }
+        if p.rettype.def.deftype=floatdef then
+          begin
+            paraloc.loc:=LOC_FPUREGISTER;
+            paraloc.register.enum:=FPU_RESULT_REG;
+          end
+        else
+         { Return in register? }
+         if not ret_in_param(p.rettype.def,p.proccalloption) then
+          begin
+            paraloc.loc:=LOC_REGISTER;
+            if paraloc.size in [OS_64,OS_S64] then
+             begin
+               paraloc.register64.reglo.enum:=R_INTREGISTER;
+               paraloc.register64.reglo.number:=NR_FUNCTION_RETURN64_LOW_REG;
+               paraloc.register64.reghi.enum:=R_INTREGISTER;
+               paraloc.register64.reghi.number:=NR_FUNCTION_RETURN64_HIGH_REG;
+             end
             else
-              internalerror(2002090903);
-        end;
+             begin
+               paraloc.register.enum:=R_INTREGISTER;
+               paraloc.register.number:=NR_FUNCTION_RETURN_REG;
+             end;
+          end
+        else
+          begin
+            paraloc.loc:=LOC_REFERENCE;
+          end;
+        p.funcret_paraloc[side]:=paraloc;
       end;
 
-
 begin
    paramanager:=tarmparamanager.create;
 end.
 {
   $Log$
-  Revision 1.1  2003-07-21 16:35:30  florian
+  Revision 1.2  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+
+  Revision 1.1  2003/07/21 16:35:30  florian
     * very basic stuff for the arm
 }

+ 10 - 7
compiler/arm/radirect.pas

@@ -53,7 +53,7 @@ interface
        { codegen }
        cgbase,
        { constants }
-       agppcgas,
+       agarmgas,
        cpubase
        ;
 
@@ -66,8 +66,8 @@ interface
          is_register:=false;
          if length(s)>5 then
            exit;
-         for r:=low(gas_reg2str) to high(gas_reg2str) do
-           if gas_reg2str[r]=s then
+         for r:=low(std_reg2str) to high(std_reg2str) do
+           if std_reg2str[r]=s then
               begin
                  is_register:=true;
                  exit;
@@ -195,11 +195,11 @@ interface
                                                     if (tvarsym(sym).reg.enum<>R_NO) then
 // until new regallocator stuff settles down
 //                                                      hs:=gas_reg2str[procinfo.framepointer.enum]
-                                                      hs:=gas_reg2str[framereg.enum]
+                                                      hs:=std_reg2str[framereg.enum]
                                                     else
                                                       hs:=tostr(tvarsym(sym).address)+
 //                                                        '('+gas_reg2str[procinfo.framepointer.enum]+')';
-                                                        '('+gas_reg2str[framereg.enum]+')';
+                                                        '('+std_reg2str[framereg.enum]+')';
                                                  end;
                                             end
                                           else
@@ -221,7 +221,7 @@ interface
                                                     { set offset }
                                                     inc(l,current_procinfo.procdef.parast.address_fixup);
 //                                                    hs:=tostr(l)+'('+gas_reg2str[procinfo.framepointer.enum]+')';
-                                                    hs:=tostr(l)+'('+gas_reg2str[framereg.enum]+')';
+                                                    hs:=tostr(l)+'('+std_reg2str[framereg.enum]+')';
                                                     if pos(',',s) > 0 then
                                                       tvarsym(sym).varstate:=vs_used;
                                                  end;
@@ -350,6 +350,9 @@ initialization
 end.
 {
   $Log$
-  Revision 1.1  2003-07-21 16:35:30  florian
+  Revision 1.2  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+
+  Revision 1.1  2003/07/21 16:35:30  florian
     * very basic stuff for the arm
 }

+ 69 - 0
compiler/arm/rasm.pas

@@ -0,0 +1,69 @@
+{
+    $Id$
+    Copyright (c) 1998-2002 by The Free Pascal Team
+
+    This unit does the parsing process for the inline assembler
+
+    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 Rasm;
+
+{$i fpcdefs.inc}
+
+Interface
+
+uses
+  node;
+
+   {
+     This routine is called to parse the instructions in assembler
+     blocks. It returns a complete list of directive and instructions
+   }
+   function assemble: tnode;
+
+
+Implementation
+
+    uses
+       { common }
+       cutils,cclasses,
+       { global }
+       globtype,globals,verbose,
+       systems,
+       { aasm }
+       cpubase,aasmbase,aasmtai,aasmcpu,
+       { symtable }
+       symconst,symbase,symtype,symsym,symtable,
+       { pass 1 }
+       nbas,
+       { parser }
+       scanner
+       // ,rautils
+       ;
+
+    function assemble : tnode;
+     begin
+     end;
+
+Begin
+end.
+{
+  $Log$
+  Revision 1.1  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+}

+ 168 - 0
compiler/arm/rgcpu.pas

@@ -0,0 +1,168 @@
+{
+    $Id$
+    Copyright (c) 1998-2003 by Florian Klaempfl
+
+    This unit implements the arm 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 fpcdefs.inc}
+
+  interface
+
+     uses
+       aasmbase,aasmtai,
+       cginfo,
+       cpubase,
+       rgobj;
+
+     type
+       trgcpu = class(trgobj)
+         function getexplicitregisterint(list: taasmoutput; reg: Tnewregister): tregister; override;
+         procedure ungetregisterint(list: taasmoutput; reg: tregister); override;
+         function getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;override;
+         procedure ungetregisterfpu(list: taasmoutput; r : tregister; size:TCGsize);override;
+{$ifndef newra}
+         procedure saveusedintregisters(list:Taasmoutput;
+                                         var saved:Tpushedsavedint;
+                                         const s:Tsupregset);override;
+         procedure saveusedotherregisters(list:Taasmoutput;
+                                           var saved:Tpushedsavedother;
+                                           const s:Tregisterset);override;
+{$endif newra}
+         procedure cleartempgen; override;
+        private
+         usedpararegs: Tsupregset;
+         usedparafpuregs: tregisterset;
+       end;
+
+  implementation
+
+    uses
+      cgobj, verbose, cutils;
+
+    function trgcpu.getexplicitregisterint(list: taasmoutput; reg: Tnewregister): tregister;
+
+      begin
+        if ((reg shr 8) in [RS_R0{$ifndef newra},RS_R2..RS_R12{$endif}]) and
+           not((reg shr 8) in is_reg_var_int) then
+          begin
+            if (reg shr 8) in usedpararegs then
+              internalerror(2003060701);
+{              comment(v_warning,'Double allocation of register '+tostr((reg shr 8)-1));}
+            include(usedpararegs,reg shr 8);
+            result.enum:=R_INTREGISTER;
+            result.number:=reg;
+            cg.a_reg_alloc(list,result);
+          end
+        else result := inherited getexplicitregisterint(list,reg);
+      end;
+
+
+    procedure trgcpu.ungetregisterint(list: taasmoutput; reg: tregister);
+
+      begin
+        if ((reg.number shr 8) in [RS_R0{$ifndef newra},RS_R2..RS_R12{$endif newra}]) and
+            not((reg.number shr 8) in is_reg_var_int) then
+          begin
+            if not((reg.number shr 8) in usedpararegs) then
+              internalerror(2003060702);
+{               comment(v_warning,'Double free of register '+tostr((reg.number shr 8)-1));}
+            exclude(usedpararegs,reg.number shr 8);
+            cg.a_reg_dealloc(list,reg);
+          end
+        else
+          inherited ungetregisterint(list,reg);
+      end;
+
+
+    function trgcpu.getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
+      begin
+        if (r in [R_F1..R_F13]) and
+           not is_reg_var_other[r] then
+          begin
+            if r in usedparafpuregs then
+              internalerror(2003060902);
+            include(usedparafpuregs,r);
+            result.enum := r;
+            cg.a_reg_alloc(list,result);
+          end
+        else
+          result := inherited getexplicitregisterfpu(list,r);
+      end;
+
+
+    procedure trgcpu.ungetregisterfpu(list: taasmoutput; r : tregister; size:TCGsize);
+      begin
+        if (r.enum in [R_F1..R_F13]) and
+           not is_reg_var_other[r.enum] then
+          begin
+            if not(r.enum in usedparafpuregs) then
+              internalerror(2003060903);
+            exclude(usedparafpuregs,r.enum);
+            cg.a_reg_dealloc(list,r);
+          end
+        else
+          inherited ungetregisterfpu(list,r,size);
+      end;
+
+
+{$ifndef newra}
+    procedure trgcpu.saveusedintregisters(list:Taasmoutput;
+                                         var saved:Tpushedsavedint;
+                                         const s:Tsupregset);
+      begin
+        // saving/restoring is done by the callee (except for registers
+        // which already contain parameters, but those aren't allocated
+        // correctly yet)
+        filldword(saved,sizeof(saved) div 4,reg_not_saved);
+      end;
+
+
+    procedure trgcpu.saveusedotherregisters(list:Taasmoutput;
+                                           var saved:Tpushedsavedother;
+                                           const s:Tregisterset);
+      begin
+        // saving/restoring is done by the callee (except for registers
+        // which already contain parameters, but those aren't allocated
+        // correctly yet)
+        filldword(saved,sizeof(saved) div 4,reg_not_saved);
+      end;
+{$endif newra}
+
+
+    procedure trgcpu.cleartempgen;
+
+      begin
+        inherited cleartempgen;
+        usedpararegs := [];
+        usedparafpuregs := [];
+      end;
+
+initialization
+  rg := trgcpu.create(last_supreg-first_supreg+1);
+end.
+
+{
+  $Log$
+  Revision 1.1  2003-08-16 13:23:01  florian
+    * several arm related stuff fixed
+}