| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 | {    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 n386add;{$i fpcdefs.inc}interface    uses       node,nadd,cpubase,nx86add;    type       ti386addnode = class(tx86addnode)         procedure second_add64bit;override;         procedure second_cmp64bit;override;         procedure second_mul;override;       end;  implementation    uses      globtype,systems,      cutils,verbose,globals,      symconst,symdef,paramgr,      aasmbase,aasmtai,aasmcpu,      cgbase,      ncon,nset,cgutils,tgobj,      cga,ncgutil,cgobj,cg64f32;{*****************************************************************************                                Add64bit*****************************************************************************}    procedure ti386addnode.second_add64bit;      var        op         : TOpCG;        op1,op2    : TAsmOp;        opsize     : TOpSize;        hregister,        hregister2 : tregister;        hl4        : tasmlabel;        mboverflow,        unsigned:boolean;        r:Tregister;      begin        firstcomplex(self);        pass_left_right;        op1:=A_NONE;        op2:=A_NONE;        mboverflow:=false;        opsize:=S_L;        unsigned:=((left.resulttype.def.deftype=orddef) and                   (torddef(left.resulttype.def).typ=u64bit)) or                  ((right.resulttype.def.deftype=orddef) and                   (torddef(right.resulttype.def).typ=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(exprasmlist,OS_INT);              hregister2:=cg.getintregister(exprasmlist,OS_INT);              cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));              location_reset(left.location,LOC_REGISTER,OS_64);              left.location.register64.reglo:=hregister;              left.location.register64.reghi:=hregister2;            end           else            begin              location_swap(left.location,right.location);              toggleflag(nf_swaped);            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_swaped in flags) then            begin              cg64.a_op64_reg_reg(exprasmlist,op,location.size,                left.location.register64,                right.location.register64);              location_swap(left.location,right.location);              toggleflag(nf_swaped);            end           else            begin              cg64.a_op64_reg_reg(exprasmlist,op,location.size,                right.location.register64,                left.location.register64);            end;         end        else         begin           { right.location<>LOC_REGISTER }           if (nodetype=subn) and (nf_swaped in flags) then            begin              r:=cg.getintregister(exprasmlist,OS_INT);              cg64.a_load64low_loc_reg(exprasmlist,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(exprasmlist,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(exprasmlist,op,location.size,right.location,                left.location.register64);            end;          location_freetemp(exprasmlist,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 aktlocalswitches  then            begin              objectlibrary.getlabel(hl4);              if unsigned then                cg.a_jmp_flags(exprasmlist,F_AE,hl4)              else                cg.a_jmp_flags(exprasmlist,F_NO,hl4);              cg.a_call_name(exprasmlist,'FPC_OVERFLOW');              cg.a_label(exprasmlist,hl4);            end;         end;        location_copy(location,left.location);      end;    procedure ti386addnode.second_cmp64bit;      var        hregister,        hregister2 : tregister;        href       : treference;        unsigned   : boolean;      procedure firstjmp64bitcmp;        var           oldnodetype : tnodetype;        begin{$ifdef OLDREGVARS}           load_all_regvars(exprasmlist);{$endif OLDREGVARS}           { the jump the sequence is a little bit hairy }           case nodetype of              ltn,gtn:                begin                   cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel);                   { cheat a little bit for the negative test }                   toggleflag(nf_swaped);                   cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel);                   toggleflag(nf_swaped);                end;              lten,gten:                begin                   oldnodetype:=nodetype;                   if nodetype=lten then                     nodetype:=ltn                   else                     nodetype:=gtn;                   cg.a_jmp_flags(exprasmlist,getresflags(unsigned),truelabel);                   { cheat for the negative test }                   if nodetype=ltn then                     nodetype:=gtn                   else                     nodetype:=ltn;                   cg.a_jmp_flags(exprasmlist,getresflags(unsigned),falselabel);                   nodetype:=oldnodetype;                end;              equaln:                cg.a_jmp_flags(exprasmlist,F_NE,falselabel);              unequaln:                cg.a_jmp_flags(exprasmlist,F_NE,truelabel);           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(exprasmlist,getresflags(true),truelabel);                   cg.a_jmp_always(exprasmlist,falselabel);                end;              equaln:                begin                   cg.a_jmp_flags(exprasmlist,F_NE,falselabel);                   cg.a_jmp_always(exprasmlist,truelabel);                end;              unequaln:                begin                   cg.a_jmp_flags(exprasmlist,F_NE,truelabel);                   cg.a_jmp_always(exprasmlist,falselabel);                end;           end;        end;      begin        firstcomplex(self);        pass_left_right;        unsigned:=((left.resulttype.def.deftype=orddef) and                   (torddef(left.resulttype.def).typ=u64bit)) or                  ((right.resulttype.def.deftype=orddef) and                   (torddef(right.resulttype.def).typ=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(exprasmlist,OS_INT);                 hregister2:=cg.getintregister(exprasmlist,OS_INT);                 cg64.a_load64_loc_reg(exprasmlist,left.location,joinreg64(hregister,hregister2));                 location_reset(left.location,LOC_REGISTER,OS_64);                 left.location.register64.reglo:=hregister;                 left.location.register64.reghi:=hregister2;               end;            end           else            begin              location_swap(left.location,right.location);              toggleflag(nf_swaped);            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                 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(exprasmlist,falselabel);                 location_freetemp(exprasmlist,right.location);               end;             LOC_CONSTANT :               begin                 exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,aint(hi(right.location.value64)),left.location.register64.reghi));                 firstjmp64bitcmp;                 exprasmlist.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;        location_freetemp(exprasmlist,left.location);        { we have LOC_JUMP as result }        location_reset(location,LOC_JUMP,OS_NO)      end;{*****************************************************************************                                x86 MUL*****************************************************************************}    procedure ti386addnode.second_mul;    var r:Tregister;        hl4 : tasmlabel;    begin      {The location.register will be filled in later (JM)}      location_reset(location,LOC_REGISTER,OS_INT);      {Get a temp register and load the left value into it       and free the location.}      r:=cg.getintregister(exprasmlist,OS_INT);      cg.a_load_loc_reg(exprasmlist,OS_INT,left.location,r);      {Allocate EAX.}      cg.getcpuregister(exprasmlist,NR_EAX);      {Load the right value.}      cg.a_load_loc_reg(exprasmlist,OS_INT,right.location,NR_EAX);      {Also allocate EDX, since it is also modified by a mul (JM).}      cg.getcpuregister(exprasmlist,NR_EDX);      emit_reg(A_MUL,S_L,r);      if cs_check_overflow in aktlocalswitches  then       begin         objectlibrary.getlabel(hl4);         cg.a_jmp_flags(exprasmlist,F_AE,hl4);         cg.a_call_name(exprasmlist,'FPC_OVERFLOW');         cg.a_label(exprasmlist,hl4);       end;      {Free EAX,EDX}      cg.ungetcpuregister(exprasmlist,NR_EDX);      cg.ungetcpuregister(exprasmlist,NR_EAX);      {Allocate a new register and store the result in EAX in it.}      location.register:=cg.getintregister(exprasmlist,OS_INT);      cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,NR_EAX,location.register);      location_freetemp(exprasmlist,left.location);      location_freetemp(exprasmlist,right.location);    end;begin   caddnode:=ti386addnode;end.
 |