Browse Source

added n8086add.pas (copy of n386add.pas), TODO: adapt to i8086

git-svn-id: branches/i8086@23762 -
nickysn 12 years ago
parent
commit
8d346d162b
4 changed files with 455 additions and 4 deletions
  1. 1 0
      .gitattributes
  2. 2 3
      compiler/i8086/cpunode.pas
  3. 446 0
      compiler/i8086/n8086add.pas
  4. 6 1
      compiler/ppc8086.lpi

+ 1 - 0
.gitattributes

@@ -252,6 +252,7 @@ compiler/i8086/i386nop.inc svneol=native#text/plain
 compiler/i8086/i386op.inc svneol=native#text/plain
 compiler/i8086/i386op.inc svneol=native#text/plain
 compiler/i8086/i386prop.inc svneol=native#text/plain
 compiler/i8086/i386prop.inc svneol=native#text/plain
 compiler/i8086/i386tab.inc svneol=native#text/plain
 compiler/i8086/i386tab.inc svneol=native#text/plain
+compiler/i8086/n8086add.pas svneol=native#text/plain
 compiler/i8086/r386ari.inc svneol=native#text/plain
 compiler/i8086/r386ari.inc svneol=native#text/plain
 compiler/i8086/r386att.inc svneol=native#text/plain
 compiler/i8086/r386att.inc svneol=native#text/plain
 compiler/i8086/r386con.inc svneol=native#text/plain
 compiler/i8086/r386con.inc svneol=native#text/plain

+ 2 - 3
compiler/i8086/cpunode.pas

@@ -41,16 +41,15 @@ unit cpunode;
        ncginl,
        ncginl,
        ncgopt,
        ncgopt,
        ncgobjc,
        ncgobjc,
-       ncgadd,
        { to be able to only parts of the generic code,
        { to be able to only parts of the generic code,
          the processor specific nodes must be included
          the processor specific nodes must be included
          after the generic one (FK)
          after the generic one (FK)
        }
        }
        nx86set,
        nx86set,
        nx86con,
        nx86con,
-       nx86cnv{,
+       nx86cnv,
 
 
-       n386add,
+       n8086add{,
        n386cal,
        n386cal,
        n386mem,
        n386mem,
        n386set,
        n386set,

+ 446 - 0
compiler/i8086/n8086add.pas

@@ -0,0 +1,446 @@
+{
+    Copyright (c) 2000-2002 by Florian Klaempfl
+
+    Code generation for add nodes on the i386
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit n8086add;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       node,nadd,cpubase,nx86add;
+
+    type
+       ti8086addnode = class(tx86addnode)
+         function use_generic_mul32to64: boolean; override;
+         procedure second_addordinal; override;
+         procedure second_add64bit;override;
+         procedure second_cmp64bit;override;
+         procedure second_mul(unsigned: boolean);
+       end;
+
+  implementation
+
+    uses
+      globtype,systems,
+      cutils,verbose,globals,
+      symconst,symdef,paramgr,defutil,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      cgbase,procinfo,
+      ncon,nset,cgutils,tgobj,
+      cga,ncgutil,cgobj,cg64f32,cgx86,
+      hlcgobj;
+
+{*****************************************************************************
+                                use_generic_mul32to64
+*****************************************************************************}
+
+    function ti8086addnode.use_generic_mul32to64: boolean;
+    begin
+      result := False;
+    end;
+
+    { handles all unsigned multiplications, and 32->64 bit signed ones.
+      32bit-only signed mul is handled by generic codegen }
+    procedure ti8086addnode.second_addordinal;
+    var
+      unsigned: boolean;
+    begin
+      unsigned:=not(is_signed(left.resultdef)) or
+                not(is_signed(right.resultdef));
+      if (nodetype=muln) and (unsigned or is_64bit(resultdef)) then
+        second_mul(unsigned)
+      else
+        inherited second_addordinal;
+    end;
+
+{*****************************************************************************
+                                Add64bit
+*****************************************************************************}
+
+    procedure ti8086addnode.second_add64bit;
+      var
+        op         : TOpCG;
+        op1,op2    : TAsmOp;
+        opsize     : TOpSize;
+        hregister,
+        hregister2 : tregister;
+        hl4        : tasmlabel;
+        mboverflow,
+        unsigned:boolean;
+        r:Tregister;
+      begin
+        pass_left_right;
+
+        op1:=A_NONE;
+        op2:=A_NONE;
+        mboverflow:=false;
+        opsize:=S_L;
+        unsigned:=((left.resultdef.typ=orddef) and
+                   (torddef(left.resultdef).ordtype=u64bit)) or
+                  ((right.resultdef.typ=orddef) and
+                   (torddef(right.resultdef).ordtype=u64bit));
+        case nodetype of
+          addn :
+            begin
+              op:=OP_ADD;
+              mboverflow:=true;
+            end;
+          subn :
+            begin
+              op:=OP_SUB;
+              op1:=A_SUB;
+              op2:=A_SBB;
+              mboverflow:=true;
+            end;
+          xorn:
+            op:=OP_XOR;
+          orn:
+            op:=OP_OR;
+          andn:
+            op:=OP_AND;
+          else
+            begin
+              { everything should be handled in pass_1 (JM) }
+              internalerror(200109051);
+            end;
+        end;
+
+        { left and right no register?  }
+        { then one must be demanded    }
+        if (left.location.loc<>LOC_REGISTER) then
+         begin
+           if (right.location.loc<>LOC_REGISTER) then
+            begin
+              hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+              hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+              cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
+              location_reset(left.location,LOC_REGISTER,left.location.size);
+              left.location.register64.reglo:=hregister;
+              left.location.register64.reghi:=hregister2;
+            end
+           else
+            begin
+              location_swap(left.location,right.location);
+              toggleflag(nf_swapped);
+            end;
+         end;
+
+        { at this point, left.location.loc should be LOC_REGISTER }
+        if right.location.loc=LOC_REGISTER then
+         begin
+           { when swapped another result register }
+           if (nodetype=subn) and (nf_swapped in flags) then
+            begin
+              cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
+                left.location.register64,
+                right.location.register64);
+              location_swap(left.location,right.location);
+              toggleflag(nf_swapped);
+            end
+           else
+            begin
+              cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
+                right.location.register64,
+                left.location.register64);
+            end;
+         end
+        else
+         begin
+           { right.location<>LOC_REGISTER }
+           if (nodetype=subn) and (nf_swapped in flags) then
+            begin
+              r:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+              cg64.a_load64low_loc_reg(current_asmdata.CurrAsmList,right.location,r);
+              emit_reg_reg(op1,opsize,left.location.register64.reglo,r);
+              emit_reg_reg(A_MOV,opsize,r,left.location.register64.reglo);
+              cg64.a_load64high_loc_reg(current_asmdata.CurrAsmList,right.location,r);
+              { the carry flag is still ok }
+              emit_reg_reg(op2,opsize,left.location.register64.reghi,r);
+              emit_reg_reg(A_MOV,opsize,r,left.location.register64.reghi);
+            end
+           else
+            begin
+              cg64.a_op64_loc_reg(current_asmdata.CurrAsmList,op,location.size,right.location,
+                left.location.register64);
+            end;
+          location_freetemp(current_asmdata.CurrAsmList,right.location);
+         end;
+
+        { only in case of overflow operations }
+        { produce overflow code }
+        { we must put it here directly, because sign of operation }
+        { is in unsigned VAR!!                              }
+        if mboverflow then
+         begin
+           if cs_check_overflow in current_settings.localswitches  then
+            begin
+              current_asmdata.getjumplabel(hl4);
+              if unsigned then
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4)
+              else
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl4);
+              cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
+              cg.a_label(current_asmdata.CurrAsmList,hl4);
+            end;
+         end;
+
+        location_copy(location,left.location);
+      end;
+
+
+    procedure ti8086addnode.second_cmp64bit;
+      var
+        hregister,
+        hregister2 : tregister;
+        href       : treference;
+        unsigned   : boolean;
+
+      procedure firstjmp64bitcmp;
+
+        var
+           oldnodetype : tnodetype;
+
+        begin
+{$ifdef OLDREGVARS}
+           load_all_regvars(current_asmdata.CurrAsmList);
+{$endif OLDREGVARS}
+           { the jump the sequence is a little bit hairy }
+           case nodetype of
+              ltn,gtn:
+                begin
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
+                   { cheat a little bit for the negative test }
+                   toggleflag(nf_swapped);
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
+                   toggleflag(nf_swapped);
+                end;
+              lten,gten:
+                begin
+                   oldnodetype:=nodetype;
+                   if nodetype=lten then
+                     nodetype:=ltn
+                   else
+                     nodetype:=gtn;
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrTrueLabel);
+                   { cheat for the negative test }
+                   if nodetype=ltn then
+                     nodetype:=gtn
+                   else
+                     nodetype:=ltn;
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),current_procinfo.CurrFalseLabel);
+                   nodetype:=oldnodetype;
+                end;
+              equaln:
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
+              unequaln:
+                cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
+           end;
+        end;
+
+      procedure secondjmp64bitcmp;
+
+        begin
+           { the jump the sequence is a little bit hairy }
+           case nodetype of
+              ltn,gtn,lten,gten:
+                begin
+                   { the comparisaion of the low dword have to be }
+                   {  always unsigned!                            }
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),current_procinfo.CurrTrueLabel);
+                   cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
+                end;
+              equaln:
+                begin
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrFalseLabel);
+                   cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrTrueLabel);
+                end;
+              unequaln:
+                begin
+                   cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,current_procinfo.CurrTrueLabel);
+                   cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
+                end;
+           end;
+        end;
+
+      begin
+        pass_left_right;
+
+        unsigned:=((left.resultdef.typ=orddef) and
+                   (torddef(left.resultdef).ordtype=u64bit)) or
+                  ((right.resultdef.typ=orddef) and
+                   (torddef(right.resultdef).ordtype=u64bit));
+
+        { left and right no register?  }
+        { then one must be demanded    }
+        if (left.location.loc<>LOC_REGISTER) then
+         begin
+           if (right.location.loc<>LOC_REGISTER) then
+            begin
+              { we can reuse a CREGISTER for comparison }
+              if (left.location.loc<>LOC_CREGISTER) then
+               begin
+                 hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+                 hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+                 cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
+                 location_freetemp(current_asmdata.CurrAsmList,left.location);
+                 location_reset(left.location,LOC_REGISTER,left.location.size);
+                 left.location.register64.reglo:=hregister;
+                 left.location.register64.reghi:=hregister2;
+               end;
+            end
+           else
+            begin
+              location_swap(left.location,right.location);
+              toggleflag(nf_swapped);
+            end;
+         end;
+
+        { at this point, left.location.loc should be LOC_REGISTER }
+        if right.location.loc=LOC_REGISTER then
+         begin
+           emit_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi);
+           firstjmp64bitcmp;
+           emit_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo);
+           secondjmp64bitcmp;
+         end
+        else
+         begin
+           case right.location.loc of
+             LOC_CREGISTER :
+               begin
+                 emit_reg_reg(A_CMP,S_L,right.location.register64.reghi,left.location.register64.reghi);
+                 firstjmp64bitcmp;
+                 emit_reg_reg(A_CMP,S_L,right.location.register64.reglo,left.location.register64.reglo);
+                 secondjmp64bitcmp;
+               end;
+             LOC_CREFERENCE,
+             LOC_REFERENCE :
+               begin
+                 tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,right.location.reference);
+                 href:=right.location.reference;
+                 inc(href.offset,4);
+                 emit_ref_reg(A_CMP,S_L,href,left.location.register64.reghi);
+                 firstjmp64bitcmp;
+                 emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.register64.reglo);
+                 secondjmp64bitcmp;
+                 cg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrFalseLabel);
+                 location_freetemp(current_asmdata.CurrAsmList,right.location);
+               end;
+             LOC_CONSTANT :
+               begin
+                 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(hi(right.location.value64)),left.location.register64.reghi));
+                 firstjmp64bitcmp;
+                 current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_L,aint(lo(right.location.value64)),left.location.register64.reglo));
+                 secondjmp64bitcmp;
+               end;
+             else
+               internalerror(200203282);
+           end;
+         end;
+
+        { we have LOC_JUMP as result }
+        location_reset(location,LOC_JUMP,OS_NO)
+      end;
+
+
+{*****************************************************************************
+                                x86 MUL
+*****************************************************************************}
+
+    procedure ti8086addnode.second_mul(unsigned: boolean);
+
+    var reg:Tregister;
+        ref:Treference;
+        use_ref:boolean;
+        hl4 : tasmlabel;
+
+    const
+      asmops: array[boolean] of tasmop = (A_IMUL, A_MUL);
+
+    begin
+      pass_left_right;
+
+      {The location.register will be filled in later (JM)}
+      location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+      { Mul supports registers and references, so if not register/reference,
+        load the location into a register.
+        The variant of IMUL which is capable of doing 32->64 bits has the same restrictions. }
+      use_ref:=false;
+      if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
+        reg:=left.location.register
+      else if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
+        begin
+          tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
+          ref:=left.location.reference;
+          use_ref:=true;
+        end
+      else
+        begin
+          {LOC_CONSTANT for example.}
+          reg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+          hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,osuinttype,left.location,reg);
+        end;
+      {Allocate EAX.}
+      cg.getcpuregister(current_asmdata.CurrAsmList,NR_EAX);
+      {Load the right value.}
+      hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,NR_EAX);
+      {Also allocate EDX, since it is also modified by a mul (JM).}
+      cg.getcpuregister(current_asmdata.CurrAsmList,NR_EDX);
+      if use_ref then
+        emit_ref(asmops[unsigned],S_L,ref)
+      else
+        emit_reg(asmops[unsigned],S_L,reg);
+      if (cs_check_overflow in current_settings.localswitches) and
+        { 32->64 bit cannot overflow }
+        (not is_64bit(resultdef)) then
+        begin
+          current_asmdata.getjumplabel(hl4);
+          cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4);
+          cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
+          cg.a_label(current_asmdata.CurrAsmList,hl4);
+        end;
+      {Free EAX,EDX}
+      cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EDX);
+      if is_64bit(resultdef) then
+      begin
+        {Allocate a couple of registers and store EDX:EAX into it}
+        location.register64.reghi := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, NR_EDX, location.register64.reghi);
+        cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
+        location.register64.reglo := cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList, OS_INT, OS_INT, NR_EAX, location.register64.reglo);
+      end
+      else
+      begin
+        {Allocate a new register and store the result in EAX in it.}
+        location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
+        cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_EAX);
+        cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_EAX,location.register);
+      end;
+      location_freetemp(current_asmdata.CurrAsmList,left.location);
+      location_freetemp(current_asmdata.CurrAsmList,right.location);
+    end;
+
+
+begin
+   caddnode:=ti8086addnode;
+end.

+ 6 - 1
compiler/ppc8086.lpi

@@ -28,7 +28,7 @@
         <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
         <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
       </local>
       </local>
     </RunParams>
     </RunParams>
-    <Units Count="12">
+    <Units Count="13">
       <Unit0>
       <Unit0>
         <Filename Value="pp.pas"/>
         <Filename Value="pp.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -88,6 +88,11 @@
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="rgcpu"/>
         <UnitName Value="rgcpu"/>
       </Unit11>
       </Unit11>
+      <Unit12>
+        <Filename Value="i8086\n8086add.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="n8086add"/>
+      </Unit12>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>