From 301df6dab973bac3c4f799318c9fedcc3fb3afe8 Mon Sep 17 00:00:00 2001
From: florian <florian@freepascal.org>
Date: Fri, 29 Aug 2003 21:36:28 +0000
Subject: [PATCH]   * fixed procedure entry/exit code   * started to fix
 reference handling

---
 compiler/arm/aasmcpu.pas  |  38 +++++++-
 compiler/arm/agarmgas.pas | 126 ++++++++++++++++---------
 compiler/arm/cgcpu.pas    | 189 +++++++++++++++++++++++++++++++++++++-
 compiler/arm/cpubase.pas  |  21 +++--
 4 files changed, 317 insertions(+), 57 deletions(-)

diff --git a/compiler/arm/aasmcpu.pas b/compiler/arm/aasmcpu.pas
index 52967b7bfe..a3e2f0de32 100644
--- a/compiler/arm/aasmcpu.pas
+++ b/compiler/arm/aasmcpu.pas
@@ -42,6 +42,7 @@ uses
          oppostfix : TOpPostfix;
          roundingmode : troundingmode;
          procedure loadshifterop(opidx:longint;const so:tshifterop);
+         procedure loadregset(opidx:longint;const s:tsupregset);
          constructor op_none(op : tasmop);
 
          constructor op_reg(op : tasmop;_op1 : tregister);
@@ -50,6 +51,7 @@ uses
          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_reg_regset(op:tasmop; _op1: tregister; _op2: tsupregset);
 
          constructor op_const_const(op : tasmop;_op1,_op2 : longint);
 
@@ -108,13 +110,30 @@ implementation
         with oper[opidx] do
           begin
             if typ<>top_shifterop then
-              new(shifterop);
+              begin
+                clearop(opidx);
+                new(shifterop);
+              end;
             shifterop^:=so;
             typ:=top_shifterop;
           end;
       end;
 
 
+    procedure taicpu.loadregset(opidx:longint;const s:tsupregset);
+      begin
+        if opidx>=ops then
+         ops:=opidx+1;
+        with oper[opidx] do
+         begin
+           if typ<>top_regset then
+             clearop(opidx);
+           regset:=s;
+           typ:=top_regset;
+         end;
+      end;
+
+
 {*****************************************************************************
                                  taicpu Constructors
 *****************************************************************************}
@@ -167,6 +186,17 @@ implementation
       end;
 
 
+    constructor taicpu.op_reg_regset(op:tasmop; _op1: tregister; _op2: tsupregset);
+      begin
+         inherited create(op);
+         if (_op1.enum = R_INTREGISTER) and (_op1.number = NR_NO) then
+           internalerror(2003031208);
+         ops:=2;
+         loadreg(0,_op1);
+         loadregset(1,_op2);
+      end;
+
+
     constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference);
       begin
          inherited create(op);
@@ -693,7 +723,11 @@ implementation
 end.
 {
   $Log$
-  Revision 1.6  2003-08-28 00:05:29  florian
+  Revision 1.7  2003-08-29 21:36:28  florian
+    * fixed procedure entry/exit code
+    * started to fix reference handling
+
+  Revision 1.6  2003/08/28 00:05:29  florian
     * today's arm patches
 
   Revision 1.5  2003/08/27 00:27:56  florian
diff --git a/compiler/arm/agarmgas.pas b/compiler/arm/agarmgas.pas
index c0e4156db5..6f2eb3cf82 100644
--- a/compiler/arm/agarmgas.pas
+++ b/compiler/arm/agarmgas.pas
@@ -43,6 +43,10 @@ unit agarmgas;
     var
       gas_reg2str : reg2strtable;
 
+    const
+      gas_shiftmode2str : array[tshiftmode] of string[3] = (
+        '','lsl','lsr','asr','ror','rrx');
+
     function gas_regnum_search(const s:string):Tnewregister;
     function gas_regname(const r:Tnewregister):string;
 
@@ -77,50 +81,62 @@ unit agarmgas;
           );
 
     function getreferencestring(var ref : treference) : string;
-    var
-      s : string;
-    begin
-       with ref do
-        begin
-          inc(offset,offsetfixup);
+      var
+        s : string;
+        nobase,noindex : boolean;
+      begin
+         with ref do
+          begin
+            inc(offset,offsetfixup);
 
-          if not assigned(symbol) then
-            s := '['
-          else
-            s:='['+symbol.name;
+            noindex:=(index.enum=R_NO) or ((index.enum=R_INTREGISTER) and (index.number=NR_NO));
+{$ifdef extdebug}
+            nobase:=(base.enum=R_NO) or ((base.enum=R_INTREGISTER) and (base.number=NR_NO));
+            //!!!! if nobase then
+            //!!!!   internalerror(200308292);
 
-          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 (not(noindex) or (shiftmode<>SM_None)) and ((offset<>0) or (symbol<>nil)) then
+            // !!!   internalerror(200308293);
+{$endif extdebug}
+            if base.enum=R_INTREGISTER then
+              s:='['+gas_regname(base.number)
+            else
+              s:='['+gas_reg2str[base.enum];
+            if addressmode=AM_POSTINDEXED then
+              s:=s+']';
 
-           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;
-                if base.enum=R_INTREGISTER then
-                  s:=s+'('+gas_regname(base.number)+')'
-                else
-                  s:=s+'('+gas_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;
+            if not(noindex) then
+              begin
+                 if signindex<0 then
+                   s:=s+', -'
+                 else
+                   s:=s+', ';
+
+                 if index.enum=R_INTREGISTER then
+                   s:=s+gas_regname(index.number)
+                 else
+                   s:=s+gas_reg2str[index.enum];
+
+                 if shiftmode<>SM_None then
+                   s:=s+' ,'+gas_shiftmode2str[shiftmode]+' #'+tostr(shiftimm);
+              end
+            else
+              begin
+                { handle symbol and index }
+                if offset<>0 then
+                  s:=s+', #'+tostr(offset);
+                { !!!!!}
+              end;
+
+             case addressmode of
+               AM_OFFSET:
+                 s:=s+']';
+               AM_PREINDEXED:
+                 s:=s+']!';
+             end;
+          end;
+        getreferencestring:=s;
+      end;
 
 
     function getopstr_jmp(const o:toper) : string;
@@ -170,6 +186,8 @@ unit agarmgas;
     function getopstr(const o:toper) : string;
     var
       hs : string;
+      first : boolean;
+      r : tnewregister;
     begin
       case o.typ of
         top_reg:
@@ -194,6 +212,20 @@ unit agarmgas;
           end;
         top_const:
           getopstr:='#'+tostr(longint(o.val));
+        top_regset:
+          begin
+            getopstr:='{';
+            first:=true;
+            for r:=RS_R0 to RS_R15 do
+              if r in o.regset then
+                begin
+                  if not(first) then
+                    getopstr:=getopstr+',';
+                  getopstr:=getopstr+'r'+tostr(r-RS_R0);
+                  first:=false;
+                end;
+            getopstr:=getopstr+'}';
+          end;
         top_ref:
           getopstr:=getreferencestring(o.ref^);
         top_symbol:
@@ -225,9 +257,9 @@ unit agarmgas;
         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:
@@ -240,12 +272,12 @@ unit agarmgas;
 
           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];
+          s:=#9+std_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix];
           if taicpu(hp).ops<>0 then
             begin
             {
@@ -292,7 +324,11 @@ begin
 end.
 {
   $Log$
-  Revision 1.5  2003-08-28 13:26:10  florian
+  Revision 1.6  2003-08-29 21:36:28  florian
+    * fixed procedure entry/exit code
+    * started to fix reference handling
+
+  Revision 1.5  2003/08/28 13:26:10  florian
     * another couple of arm fixes
 
   Revision 1.4  2003/08/28 00:05:29  florian
diff --git a/compiler/arm/cgcpu.pas b/compiler/arm/cgcpu.pas
index bb6fe156ee..5aae902bd7 100644
--- a/compiler/arm/cgcpu.pas
+++ b/compiler/arm/cgcpu.pas
@@ -54,6 +54,7 @@ unit cgcpu;
           size: tcgsize; src1, src2, dst: tregister); override;
 
         { move instructions }
+        procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
         procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
         procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
         procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
@@ -267,7 +268,7 @@ unit cgcpu;
          tmpreg : tregister;
          so : tshifterop;
        begin
-          if is_shifter_const(a,shift) and (op<>OP_MUL) then
+          if is_shifter_const(a,shift) and (not(op in [OP_IMUL,OP_MUL])) then
             case op of
               OP_NEG,OP_NOT,
               OP_DIV,OP_IDIV:
@@ -316,6 +317,7 @@ unit cgcpu;
        size: tcgsize; src1, src2, dst: tregister);
        var
          so : tshifterop;
+         tmpreg : tregister;
        begin
          case op of
            OP_NEG:
@@ -345,6 +347,23 @@ unit cgcpu;
                so.shiftertype:=SO_LSL;
                list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src1,so));
              end;
+           OP_IMUL,
+           OP_MUL:
+             begin
+               { the arm doesn't allow that rd and rm are the same }
+               if dst.number=src2.number then
+                 begin
+                   if src1.number<>src2.number then
+                     list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
+                   else
+                     begin
+                       writeln('Warning: Fix MUL');
+                       list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
+                     end;
+                 end
+               else
+                 list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
+             end;
            else
              list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
          end;
@@ -398,13 +417,128 @@ unit cgcpu;
        end;
 
 
+    procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
+      var
+        tmpreg : tregister;
+        tmpref : treference;
+        instr : taicpu;
+      begin
+        tmpreg.enum:=R_INTREGISTER;
+        tmpreg.number:=NR_NO;
+
+        { Be sure to have a base register }
+        if (ref.base.number=NR_NO) then
+          begin
+            if ref.shiftmode<>SM_None then
+              internalerror(200308294);
+            ref.base:=ref.index;
+            ref.index.number:=NR_NO;
+          end;
+
+        { When need to use SETHI, do it first }
+        if assigned(ref.symbol) or
+           (ref.offset<-4095) or
+           (ref.offset>4095) then
+          begin
+{
+            tmpreg:=rg.getregisterint(list,OS_INT);
+            reference_reset(tmpref);
+            tmpref.symbol:=ref.symbol;
+            tmpref.offset:=ref.offset;
+            tmpref.symaddr:=refs_hi;
+            list.concat(taicpu.op_ref_reg(A_SETHI,tmpref,tmpreg));
+            { Load the low part is left }
+{$warning TODO Maybe not needed to load symbol}
+            tmpref.symaddr:=refs_lo;
+            list.concat(taicpu.op_reg_ref_reg(A_OR,tmpreg,tmpref,tmpreg));
+            { The offset and symbol are loaded, reset in reference }
+            ref.offset:=0;
+            ref.symbol:=nil;
+            { Only an index register or offset is allowed }
+            if tmpreg.number<>NR_NO then
+              begin
+                if (ref.index.number<>NR_NO) then
+                  begin
+                    list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.index,tmpreg));
+                    ref.index:=tmpreg;
+                  end
+                else
+                  begin
+                    if ref.base.number<>NR_NO then
+                      ref.index:=tmpreg
+                    else
+                      ref.base:=tmpreg;
+                  end;
+              end;
+}
+          end;
+{
+        if (ref.base.number<>NR_NO) then
+          begin
+            if (ref.index.number<>NR_NO) and
+               ((ref.offset<>0) or assigned(ref.symbol)) then
+              begin
+                if tmpreg.number=NR_NO then
+                  tmpreg:=rg.getregisterint(list,OS_INT);
+                if (ref.index.number<>NR_NO) then
+                  begin
+                    list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.index,tmpreg));
+                    ref.index.number:=NR_NO;
+                  end;
+              end;
+          end;
+}
+        instr:=taicpu.op_reg_ref(op,reg,ref);
+        instr.oppostfix:=oppostfix;
+        list.concat(instr);
+        if (tmpreg.number<>NR_NO) then
+          rg.ungetregisterint(list,tmpreg);
+      end;
+
+
      procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
+       var
+         oppostfix:toppostfix;
        begin
+         case ToSize of
+           { signed integer registers }
+           OS_8,
+           OS_S8:
+             oppostfix:=PF_B;
+           OS_16,
+           OS_S16:
+             oppostfix:=PF_H;
+           OS_32,
+           OS_S32:
+             oppostfix:=PF_None;
+           else
+             InternalError(200308295);
+         end;
+         handle_load_store(list,A_STR,oppostfix,reg,ref);
        end;
 
 
      procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
+       var
+         oppostfix:toppostfix;
        begin
+         case ToSize of
+           { signed integer registers }
+           OS_8:
+             oppostfix:=PF_B;
+           OS_S8:
+             oppostfix:=PF_SB;
+           OS_16:
+             oppostfix:=PF_H;
+           OS_S16:
+             oppostfix:=PF_SH;
+           OS_32,
+           OS_S32:
+             oppostfix:=PF_None;
+           else
+             InternalError(200308291);
+         end;
+         handle_load_store(list,A_LDR,oppostfix,reg,ref);
        end;
 
 
@@ -522,12 +656,59 @@ unit cgcpu;
 
 
      procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
+       var
+         rip,rsp,rfp : tregister;
+         instr : taicpu;
        begin
+         rsp.enum:=R_INTREGISTER;
+         rsp.number:=NR_STACK_POINTER_REG;
+         a_reg_alloc(list,rsp);
+
+         rfp.enum:=R_INTREGISTER;
+         rfp.number:=NR_FRAME_POINTER_REG;
+         a_reg_alloc(list,rfp);
+
+         rip.enum:=R_INTREGISTER;
+         rip.number:=NR_R12;
+         a_reg_alloc(list,rip);
+
+         list.concat(taicpu.op_reg_reg(A_MOV,rip,rsp));
+         { restore int registers and return }
+         instr:=taicpu.op_reg_regset(A_STM,rsp,rg.used_in_proc_int-[RS_R0..RS_R4]+[RS_R11,RS_R12,RS_R15]);
+         instr.oppostfix:=PF_FD;
+         list.concat(instr);
+
+         list.concat(taicpu.op_reg_reg_const(A_SUB,rfp,rip,4));
+         a_reg_alloc(list,rip);
+
+         { allocate necessary stack size }
+         list.concat(taicpu.op_reg_reg_const(A_SUB,rsp,rsp,4));
        end;
 
 
      procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
+       var
+         r1,r2 : tregister;
+         instr : taicpu;
        begin
+         if (current_procinfo.framepointer.number=NR_STACK_POINTER_REG) then
+           begin
+             r1.enum:=R_INTREGISTER;
+             r1.number:=NR_R15;
+             r2.enum:=R_INTREGISTER;
+             r2.number:=NR_R14;
+
+             list.concat(taicpu.op_reg_reg(A_MOV,r1,r2));
+           end
+         else
+           begin
+             r1.enum:=R_INTREGISTER;
+             r1.number:=NR_R11;
+             { restore int registers and return }
+             instr:=taicpu.op_reg_regset(A_LDM,r1,rg.used_in_proc_int-[RS_R0..RS_R4]+[RS_R11,RS_R13,RS_R15]);
+             instr.oppostfix:=PF_EA;
+             list.concat(instr);
+           end;
        end;
 
 
@@ -617,7 +798,11 @@ begin
 end.
 {
   $Log$
-  Revision 1.7  2003-08-28 13:26:10  florian
+  Revision 1.8  2003-08-29 21:36:28  florian
+    * fixed procedure entry/exit code
+    * started to fix reference handling
+
+  Revision 1.7  2003/08/28 13:26:10  florian
     * another couple of arm fixes
 
   Revision 1.6  2003/08/28 00:05:29  florian
diff --git a/compiler/arm/cpubase.pas b/compiler/arm/cpubase.pas
index 621d1b49a8..cab99952e6 100644
--- a/compiler/arm/cpubase.pas
+++ b/compiler/arm/cpubase.pas
@@ -134,7 +134,7 @@ uses
       last_supreg = RS_R15;
 
       { registers which may be destroyed by calls }
-      VOLATILE_INTREGISTERS = [RS_R0..RS_R3];
+      VOLATILE_INTREGISTERS = [RS_R0..RS_R3,RS_R12..RS_R15];
       VOLATILE_FPUREGISTERS = [R_F0..R_F3];
 
       { Number of first and last imaginary register. }
@@ -201,7 +201,7 @@ uses
         { 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
+        PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA
       );
 
       TRoundingMode = (RM_None,RM_P,RM_M,RM_Z);
@@ -211,7 +211,7 @@ uses
         's',
         'd','e','p','ep',
         'b','sb','bt','h','sh','t',
-        'ia','ib','da','db','df','fa','ed','ea');
+        'ia','ib','da','db','fd','fa','ed','ea');
 
       roundingmode2str : array[TRoundingMode] of string[1] = ('',
         'p','m','z');
@@ -253,14 +253,15 @@ uses
       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);
+      tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR,SM_RRX);
 
       { reference record }
       preference = ^treference;
       treference = packed record
          base,
          index       : tregister;
-         scalefactor : byte;
+         shiftimm    : byte;
+         signindex   : shortint;
          offset      : longint;
          symbol      : tasmsymbol;
          offsetfixup : longint;
@@ -483,8 +484,8 @@ uses
                                  Constants
 *****************************************************************************}
 
-      firstsaveintreg = R_R4;
-      lastsaveintreg  = R_R10;
+      firstsaveintreg = RS_R4;
+      lastsaveintreg  = RS_R10;
       firstsavefpureg = R_F4;
       lastsavefpureg  = R_F7;
       firstsavemmreg  = R_S16;
@@ -690,7 +691,11 @@ uses
 end.
 {
   $Log$
-  Revision 1.8  2003-08-28 00:05:29  florian
+  Revision 1.9  2003-08-29 21:36:28  florian
+    * fixed procedure entry/exit code
+    * started to fix reference handling
+
+  Revision 1.8  2003/08/28 00:05:29  florian
     * today's arm patches
 
   Revision 1.7  2003/08/25 23:20:38  florian