mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 15:39:24 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1541 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1541 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    $Id$
 | 
						|
    Copyright (c) 1993-98 by Florian Klaempfl, Carl Eric Codere
 | 
						|
 | 
						|
    This unit generates 68000 (or better) assembler from the parse tree
 | 
						|
 | 
						|
    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 cga68k;
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
    uses
 | 
						|
       globtype,cobjects,tree,m68k,aasm,symtable;
 | 
						|
 | 
						|
    procedure emitl(op : tasmop;var l : plabel);
 | 
						|
    procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
 | 
						|
    procedure emitcall(const routine:string;add_to_externals : boolean);
 | 
						|
    procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
 | 
						|
                              destreg:Tregister;delloc:boolean);
 | 
						|
    procedure emit_to_reg32(var hr:tregister);
 | 
						|
    procedure loadsetelement(var p : ptree);
 | 
						|
    { produces jumps to true respectively false labels using boolean expressions }
 | 
						|
    procedure maketojumpbool(p : ptree);
 | 
						|
    procedure emitoverflowcheck(p: ptree);
 | 
						|
    procedure push_int(l : longint);
 | 
						|
    function maybe_push(needed : byte;p : ptree) : boolean;
 | 
						|
    procedure restore(p : ptree);
 | 
						|
    procedure emit_push_mem(const ref : treference);
 | 
						|
    procedure emitpushreferenceaddr(list : paasmoutput;const ref : treference);
 | 
						|
    procedure copystring(const dref,sref : treference;len : byte);
 | 
						|
    procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
 | 
						|
    { see implementation }
 | 
						|
    procedure maybe_loada5;
 | 
						|
    procedure emit_bounds_check(hp: treference; index: tregister);
 | 
						|
    procedure loadstring(p:ptree);
 | 
						|
    procedure decransiref(const ref : treference);
 | 
						|
 | 
						|
    procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
 | 
						|
    { return a float op_size from a floatb type  }
 | 
						|
    { also does some error checking for problems }
 | 
						|
    function getfloatsize(t: tfloattype): topsize;
 | 
						|
    procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
 | 
						|
{    procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
 | 
						|
    procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize); }
 | 
						|
 | 
						|
    procedure firstcomplex(p : ptree);
 | 
						|
 | 
						|
    { generate stackframe for interrupt procedures }
 | 
						|
    procedure generate_interrupt_stackframe_entry;
 | 
						|
    procedure generate_interrupt_stackframe_exit;
 | 
						|
    { generate entry code for a procedure.}
 | 
						|
    procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
 | 
						|
                           stackframe:longint;
 | 
						|
                           var parasize:longint;var nostackframe:boolean;
 | 
						|
                           inlined : boolean);
 | 
						|
    { generate the exit code for a procedure. }
 | 
						|
    procedure genexitcode(list : paasmoutput;parasize:longint;
 | 
						|
                          nostackframe,inlined:boolean);
 | 
						|
 | 
						|
    procedure removetemps(list : paasmoutput;p : plinkedlist);
 | 
						|
    procedure releasedata(p : plinkedlist);
 | 
						|
 | 
						|
{$ifdef test_dest_loc}
 | 
						|
const   { used to avoid temporary assignments }
 | 
						|
        dest_loc_known : boolean = false;
 | 
						|
        in_dest_loc : boolean = false;
 | 
						|
        dest_loc_tree : ptree = nil;
 | 
						|
 | 
						|
var dest_loc : tlocation;
 | 
						|
 | 
						|
procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
 | 
						|
 | 
						|
{$endif test_dest_loc}
 | 
						|
 | 
						|
 | 
						|
  implementation
 | 
						|
 | 
						|
    uses
 | 
						|
       systems,globals,verbose,files,types,pbase,
 | 
						|
       tgen68k,hcodegen,temp_gen,ppu
 | 
						|
{$ifdef GDB}
 | 
						|
       ,gdb
 | 
						|
{$endif}
 | 
						|
       ;
 | 
						|
 | 
						|
 | 
						|
    {
 | 
						|
    procedure genconstadd(size : topsize;l : longint;const str : string);
 | 
						|
 | 
						|
      begin
 | 
						|
         if l=0 then
 | 
						|
         else if l=1 then
 | 
						|
           exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
 | 
						|
         else if l=-1 then
 | 
						|
           exprasmlist^.concat(new(pai68k,op_A_INC,size,str)
 | 
						|
         else
 | 
						|
           exprasmlist^.concat(new(pai68k,op_ADD,size,'$'+tostr(l)+','+str);
 | 
						|
      end;
 | 
						|
    }
 | 
						|
    procedure copystring(const dref,sref : treference;len : byte);
 | 
						|
 | 
						|
      var
 | 
						|
         pushed : tpushed;
 | 
						|
 | 
						|
      begin
 | 
						|
         pushusedregisters(pushed,$ffff);
 | 
						|
{         emitpushreferenceaddr(dref);       }
 | 
						|
{         emitpushreferenceaddr(sref);       }
 | 
						|
{         push_int(len);                     }
 | 
						|
         { This speeds up from 116 cycles to 24 cycles on the 68000 }
 | 
						|
         { when passing register parameters!                        }
 | 
						|
         exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dref),R_A1)));
 | 
						|
         exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(sref),R_A0)));
 | 
						|
         exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,len,R_D0)));
 | 
						|
         emitcall('FPC_STRCOPY',true);
 | 
						|
         maybe_loada5;
 | 
						|
         popusedregisters(pushed);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure decransiref(const ref : treference);
 | 
						|
      begin
 | 
						|
         emitpushreferenceaddr(exprasmlist,ref);
 | 
						|
         emitcall('FPC_ANSISTR_DECR_REF',true);
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure loadstring(p:ptree);
 | 
						|
      begin
 | 
						|
        case p^.right^.resulttype^.deftype of
 | 
						|
         stringdef : begin
 | 
						|
                       { load a string ... }
 | 
						|
                       { here two possible choices:      }
 | 
						|
                       { if it is a char, then simply    }
 | 
						|
                       { load 0 length string            }
 | 
						|
                       if (p^.right^.treetype=stringconstn) and
 | 
						|
                          (str_length(p^.right)=0) then
 | 
						|
                        exprasmlist^.concat(new(pai68k,op_const_ref(
 | 
						|
                           A_MOVE,S_B,0,newreference(p^.left^.location.reference))))
 | 
						|
                       else
 | 
						|
                        copystring(p^.left^.location.reference,p^.right^.location.reference,
 | 
						|
                           min(pstringdef(p^.right^.resulttype)^.len,pstringdef(p^.left^.resulttype)^.len));
 | 
						|
                     end;
 | 
						|
            orddef : begin
 | 
						|
                       if p^.right^.treetype=ordconstn then
 | 
						|
                        begin
 | 
						|
                            { offset 0: length of string }
 | 
						|
                            { offset 1: character        }
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_W,1*256+p^.right^.value,
 | 
						|
                              newreference(p^.left^.location.reference))))
 | 
						|
                        end
 | 
						|
                       else
 | 
						|
                         begin
 | 
						|
                            { not so elegant (goes better with extra register }
 | 
						|
                            if (p^.right^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
 | 
						|
                              begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_reg(
 | 
						|
                                    A_MOVE,S_B,p^.right^.location.register,R_D0)));
 | 
						|
                                 ungetregister32(p^.right^.location.register);
 | 
						|
                              end
 | 
						|
                            else
 | 
						|
                              begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_ref_reg(
 | 
						|
                                    A_MOVE,S_B,newreference(p^.right^.location.reference),R_D0)));
 | 
						|
                                 del_reference(p^.right^.location.reference);
 | 
						|
                              end;
 | 
						|
                            { alignment can cause problems }
 | 
						|
                            { add length of string to ref }
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_const_ref(A_MOVE,S_B,1,
 | 
						|
                               newreference(p^.left^.location.reference))));
 | 
						|
(*                            if abs(p^.left^.location.reference.offset) >= 1 then
 | 
						|
                              Begin *)
 | 
						|
                              { temporarily decrease offset }
 | 
						|
                                Inc(p^.left^.location.reference.offset);
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,R_D0,
 | 
						|
                                  newreference(p^.left^.location.reference))));
 | 
						|
                                Dec(p^.left^.location.reference.offset);
 | 
						|
                                { restore offset }
 | 
						|
(*                              end
 | 
						|
                            else
 | 
						|
                              Begin
 | 
						|
                                Comment(V_Debug,'SecondChar2String() internal error.');
 | 
						|
                                internalerror(34);
 | 
						|
                              end; *)
 | 
						|
                         end;
 | 
						|
                       end;
 | 
						|
        else
 | 
						|
         CGMessage(type_e_mismatch);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    procedure restore(p : ptree);
 | 
						|
 | 
						|
      var
 | 
						|
         hregister :  tregister;
 | 
						|
 | 
						|
      begin
 | 
						|
         if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
 | 
						|
            hregister:=getregister32
 | 
						|
         else
 | 
						|
            hregister:=getaddressreg;
 | 
						|
 | 
						|
         exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SPPULL,hregister)));
 | 
						|
         if (p^.location.loc=LOC_REGISTER) or (p^.location.loc=LOC_CREGISTER) then
 | 
						|
           begin
 | 
						|
              p^.location.register:=hregister;
 | 
						|
           end
 | 
						|
         else
 | 
						|
           begin
 | 
						|
              reset_reference(p^.location.reference);
 | 
						|
              p^.location.reference.base:=hregister;
 | 
						|
              set_location(p^.left^.location,p^.location);
 | 
						|
           end;
 | 
						|
      end;
 | 
						|
 | 
						|
    function maybe_push(needed : byte;p : ptree) : boolean;
 | 
						|
 | 
						|
      var
 | 
						|
         pushed : boolean;
 | 
						|
      begin
 | 
						|
         if (needed>usablereg32) or (needed > usableaddress) then
 | 
						|
           begin
 | 
						|
              if (p^.location.loc=LOC_REGISTER) or
 | 
						|
                 (p^.location.loc=LOC_CREGISTER) then
 | 
						|
                begin
 | 
						|
                   pushed:=true;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,p^.location.register,R_SPPUSH)));
 | 
						|
                   ungetregister32(p^.location.register);
 | 
						|
                end
 | 
						|
               else
 | 
						|
                 if ((p^.location.loc=LOC_MEM) or(p^.location.loc=LOC_REFERENCE)) and
 | 
						|
                    ((p^.location.reference.base<>R_NO) or
 | 
						|
                    (p^.location.reference.index<>R_NO)) then
 | 
						|
                  begin
 | 
						|
                     del_reference(p^.location.reference);
 | 
						|
                     exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
 | 
						|
                        R_A0)));
 | 
						|
                     exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A0,R_SPPUSH)));
 | 
						|
                     pushed:=true;
 | 
						|
                  end
 | 
						|
              else pushed:=false;
 | 
						|
           end
 | 
						|
         else pushed:=false;
 | 
						|
         maybe_push:=pushed;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    { emit out of range check for arrays and sets}
 | 
						|
    procedure emit_bounds_check(hp: treference; index: tregister);
 | 
						|
    { index = index of array to check }
 | 
						|
    { memory of range check information for array }
 | 
						|
     var
 | 
						|
      hl : plabel;
 | 
						|
     begin
 | 
						|
        if (aktoptprocessor = MC68020) then
 | 
						|
          begin
 | 
						|
             exprasmlist^.concat(new(pai68k, op_ref_reg(A_CMP2,S_L,newreference(hp),index)));
 | 
						|
             getlabel(hl);
 | 
						|
             emitl(A_BCC, hl);
 | 
						|
             exprasmlist^.concat(new(pai68k, op_const_reg(A_MOVE,S_L,201,R_D0)));
 | 
						|
             emitcall('FPC_HALT_ERROR',true);
 | 
						|
             emitl(A_LABEL, hl);
 | 
						|
          end
 | 
						|
        else
 | 
						|
          begin
 | 
						|
            exprasmlist^.concat(new(pai68k, op_ref_reg(A_LEA,S_L,newreference(hp), R_A1)));
 | 
						|
            exprasmlist^.concat(new(pai68k, op_reg_reg(A_MOVE, S_L, index, R_D0)));
 | 
						|
            emitcall('FPC_RE_BOUNDS_CHECK',true);
 | 
						|
          end;
 | 
						|
     end;
 | 
						|
 | 
						|
 | 
						|
    procedure emit_to_reg32(var hr:tregister);
 | 
						|
      begin
 | 
						|
(*        case hr of
 | 
						|
      R_AX..R_DI : begin
 | 
						|
                     hr:=reg16toreg32(hr);
 | 
						|
                     exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ffff,hr)));
 | 
						|
                   end;
 | 
						|
      R_AL..R_DL : begin
 | 
						|
                     hr:=reg8toreg32(hr);
 | 
						|
                     exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff,hr)));
 | 
						|
                   end;
 | 
						|
      R_AH..R_DH : begin
 | 
						|
                     hr:=reg8toreg32(hr);
 | 
						|
                     exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,$ff00,hr)));
 | 
						|
                   end;
 | 
						|
        end; *)
 | 
						|
      end;
 | 
						|
 | 
						|
    function getfloatsize(t: tfloattype): topsize;
 | 
						|
    begin
 | 
						|
      case t of
 | 
						|
      s32real: getfloatsize := S_FS;
 | 
						|
      s64real: getfloatsize := S_FL;
 | 
						|
      s80real: getfloatsize := S_FX;
 | 
						|
{$ifdef extdebug}
 | 
						|
    else {else case }
 | 
						|
      begin
 | 
						|
        Comment(V_Debug,' getfloatsize() trying to get unknown size.');
 | 
						|
        internalerror(12);
 | 
						|
      end;
 | 
						|
{$endif}
 | 
						|
     end;
 | 
						|
    end;
 | 
						|
 | 
						|
    procedure emitl(op : tasmop;var l : plabel);
 | 
						|
 | 
						|
      begin
 | 
						|
         if op=A_LABEL then
 | 
						|
           exprasmlist^.concat(new(pai_label,init(l)))
 | 
						|
         else
 | 
						|
           exprasmlist^.concat(new(pai_labeled,init(op,l)))
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
 | 
						|
 | 
						|
      begin
 | 
						|
         if (reg1 <> reg2) or (i <> A_MOVE) then
 | 
						|
           exprasmlist^.concat(new(pai68k,op_reg_reg(i,s,reg1,reg2)));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure emitcall(const routine:string;add_to_externals : boolean);
 | 
						|
 | 
						|
     begin
 | 
						|
        exprasmlist^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol(routine,0))));
 | 
						|
        if add_to_externals and
 | 
						|
           not (cs_compilesystem in aktmoduleswitches) then
 | 
						|
          concat_external(routine,EXT_NEAR);
 | 
						|
     end;
 | 
						|
 | 
						|
 | 
						|
    procedure maketojumpbool(p : ptree);
 | 
						|
 | 
						|
      begin
 | 
						|
         if p^.error then
 | 
						|
           exit;
 | 
						|
         if (p^.resulttype^.deftype=orddef) and
 | 
						|
            (porddef(p^.resulttype)^.typ=bool8bit) then
 | 
						|
           begin
 | 
						|
              if is_constboolnode(p) then
 | 
						|
                begin
 | 
						|
                   if p^.value<>0 then
 | 
						|
                     emitl(A_JMP,truelabel)
 | 
						|
                   else emitl(A_JMP,falselabel);
 | 
						|
                end
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                   case p^.location.loc of
 | 
						|
                      LOC_CREGISTER,LOC_REGISTER : begin
 | 
						|
                                        exprasmlist^.concat(new(pai68k,op_reg(A_TST,S_B,p^.location.register)));
 | 
						|
                                        ungetregister32(p^.location.register);
 | 
						|
                                        emitl(A_BNE,truelabel);
 | 
						|
                                        emitl(A_JMP,falselabel);
 | 
						|
                                     end;
 | 
						|
                      LOC_MEM,LOC_REFERENCE : begin
 | 
						|
                                        exprasmlist^.concat(new(pai68k,op_ref(
 | 
						|
                                          A_TST,S_B,newreference(p^.location.reference))));
 | 
						|
                                        del_reference(p^.location.reference);
 | 
						|
                                        emitl(A_BNE,truelabel);
 | 
						|
                                        emitl(A_JMP,falselabel);
 | 
						|
                                     end;
 | 
						|
                      LOC_FLAGS : begin
 | 
						|
                                     emitl(flag_2_jmp[p^.location.resflags],truelabel);
 | 
						|
                                     emitl(A_JMP,falselabel);
 | 
						|
                                  end;
 | 
						|
                   end;
 | 
						|
                end;
 | 
						|
           end
 | 
						|
         else
 | 
						|
          CGMessage(type_e_mismatch);
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure emitoverflowcheck(p: ptree);
 | 
						|
 | 
						|
      var
 | 
						|
         hl : plabel;
 | 
						|
 | 
						|
      begin
 | 
						|
         if cs_check_overflow in aktlocalswitches  then
 | 
						|
           begin
 | 
						|
              getlabel(hl);
 | 
						|
              if not ((p^.resulttype^.deftype=pointerdef) or
 | 
						|
                     ((p^.resulttype^.deftype=orddef) and
 | 
						|
                (porddef(p^.resulttype)^.typ in [u16bit,u32bit,u8bit,uchar,bool8bit]))) then
 | 
						|
                emitl(A_BVC,hl)
 | 
						|
              else
 | 
						|
                emitl(A_BCC,hl);
 | 
						|
              emitcall('FPC_OVERFLOW',true);
 | 
						|
              emitl(A_LABEL,hl);
 | 
						|
           end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure push_int(l : longint);
 | 
						|
 | 
						|
      begin
 | 
						|
         if (l = 0) and (aktoptprocessor = MC68020) then
 | 
						|
           begin
 | 
						|
          exprasmlist^.concat(new(pai68k,op_reg(A_CLR,S_L,R_D6)));
 | 
						|
              exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
 | 
						|
              R_D6, R_SPPUSH)));
 | 
						|
           end
 | 
						|
         else
 | 
						|
         if not(cs_littlesize in aktglobalswitches) and (l >= -128) and (l <= 127) then
 | 
						|
           begin
 | 
						|
           exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVEQ,S_L,l,R_D6)));
 | 
						|
           exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_D6,R_SPPUSH)));
 | 
						|
           end
 | 
						|
         else
 | 
						|
           exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,l,R_SPPUSH)));
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure emit_push_mem(const ref : treference);
 | 
						|
    { Push a value on to the stack }
 | 
						|
      begin
 | 
						|
         if ref.isintvalue then
 | 
						|
           push_int(ref.offset)
 | 
						|
         else
 | 
						|
           exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),R_SPPUSH)));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    { USES REGISTER R_A1 }
 | 
						|
    procedure emitpushreferenceaddr(list : paasmoutput;const ref : treference);
 | 
						|
    { Push a pointer to a value on the stack }
 | 
						|
      begin
 | 
						|
         if ref.isintvalue then
 | 
						|
           push_int(ref.offset)
 | 
						|
         else
 | 
						|
           begin
 | 
						|
              if (ref.base=R_NO) and (ref.index=R_NO) then
 | 
						|
                list^.concat(new(pai68k,op_ref(A_PEA,S_L,
 | 
						|
                    newreference(ref))))
 | 
						|
              else if (ref.base=R_NO) and (ref.index<>R_NO) and
 | 
						|
                 (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
 | 
						|
                list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,
 | 
						|
                    ref.index,R_SPPUSH)))
 | 
						|
              else if (ref.base<>R_NO) and (ref.index=R_NO) and
 | 
						|
                 (ref.offset=0) and (ref.symbol=nil) then
 | 
						|
                list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,ref.base,R_SPPUSH)))
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                   list^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(ref),R_A1)));
 | 
						|
                   list^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A1,R_SPPUSH)));
 | 
						|
                end;
 | 
						|
           end;
 | 
						|
        end;
 | 
						|
 | 
						|
    { This routine needs to be further checked to see if it works correctly  }
 | 
						|
    { because contrary to the intel version, all large set elements are read }
 | 
						|
    { as 32-bit value_str, and then decomposed to find the correct byte.        }
 | 
						|
 | 
						|
    { CHECKED : Depending on the result size, if reference, a load may be    }
 | 
						|
    { required on word, long or byte.                                        }
 | 
						|
    procedure loadsetelement(var p : ptree);
 | 
						|
 | 
						|
      var
 | 
						|
         hr : tregister;
 | 
						|
         opsize : topsize;
 | 
						|
 | 
						|
      begin
 | 
						|
         { copy the element in the d0.b register, slightly complicated }
 | 
						|
         case p^.location.loc of
 | 
						|
            LOC_REGISTER,
 | 
						|
            LOC_CREGISTER : begin
 | 
						|
                              hr:=p^.location.register;
 | 
						|
                              emit_reg_reg(A_MOVE,S_L,hr,R_D0);
 | 
						|
                              ungetregister32(hr);
 | 
						|
                           end;
 | 
						|
            else
 | 
						|
               begin
 | 
						|
                 { This is quite complicated, because of the endian on }
 | 
						|
                 { the m68k!                                           }
 | 
						|
                 opsize:=S_NO;
 | 
						|
                 case integer(p^.resulttype^.savesize) of
 | 
						|
                   1 : opsize:=S_B;
 | 
						|
                   2 : opsize:=S_W;
 | 
						|
                   4 : opsize:=S_L;
 | 
						|
                 else
 | 
						|
                   internalerror(19);
 | 
						|
                 end;
 | 
						|
                 exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,opsize,
 | 
						|
                    newreference(p^.location.reference),R_D0)));
 | 
						|
                 exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
 | 
						|
                    255,R_D0)));
 | 
						|
{
 | 
						|
                  exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
 | 
						|
                    newreference(p^.location.reference),R_D0)));        }
 | 
						|
{                  exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
 | 
						|
                    $ff,R_D0))); }
 | 
						|
                  del_reference(p^.location.reference);
 | 
						|
               end;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure generate_interrupt_stackframe_entry;
 | 
						|
      begin
 | 
						|
         { save the registers of an interrupt procedure }
 | 
						|
 | 
						|
         { .... also the segment registers }
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure generate_interrupt_stackframe_exit;
 | 
						|
 | 
						|
      begin
 | 
						|
         { restore the registers of an interrupt procedure }
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure genentrycode(list : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
 | 
						|
                           stackframe:longint;
 | 
						|
                           var parasize:longint;var nostackframe:boolean;
 | 
						|
                           inlined : boolean);
 | 
						|
{Generates the entry code for a procedure.}
 | 
						|
 | 
						|
var hs:string;
 | 
						|
    hp:Pused_unit;
 | 
						|
    unitinits:taasmoutput;
 | 
						|
{$ifdef GDB}
 | 
						|
    stab_function_name:Pai_stab_function_name;
 | 
						|
{$endif GDB}
 | 
						|
begin
 | 
						|
    if (aktprocsym^.definition^.options and poproginit<>0) then
 | 
						|
        begin
 | 
						|
            {Init the stack checking.}
 | 
						|
            if (cs_check_stack in aktlocalswitches) and
 | 
						|
             (target_info.target=target_m68k_linux) then
 | 
						|
                begin
 | 
						|
                    procinfo.aktentrycode^.insert(new(pai68k,
 | 
						|
                     op_csymbol(A_JSR,S_NO,newcsymbol('FPC_INIT_STACK_CHECK',0))));
 | 
						|
                end
 | 
						|
            else
 | 
						|
            { The main program has already allocated its stack - so we simply compare }
 | 
						|
            { with a value of ZERO, and the comparison will directly check!           }
 | 
						|
            if (cs_check_stack in aktlocalswitches) then
 | 
						|
                begin
 | 
						|
                  procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
 | 
						|
                      newcsymbol('FPC_STACKCHECK',0))));
 | 
						|
                  procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
 | 
						|
                      0,R_D0)));
 | 
						|
                  concat_external('FPC_STACKCHECK',EXT_NEAR);
 | 
						|
                end;
 | 
						|
 | 
						|
 | 
						|
            unitinits.init;
 | 
						|
 | 
						|
            {Call the unit init procedures.}
 | 
						|
            hp:=pused_unit(usedunits.first);
 | 
						|
            while assigned(hp) do
 | 
						|
                begin
 | 
						|
                    { call the unit init code and make it external }
 | 
						|
                    if (hp^.u^.flags and uf_init)<>0 then
 | 
						|
                        begin
 | 
						|
                           unitinits.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('INIT$$'+hp^.u^.modulename^,0))));
 | 
						|
                           concat_external('INIT$$'+hp^.u^.modulename^,EXT_NEAR);
 | 
						|
                        end;
 | 
						|
                   hp:=pused_unit(hp^.next);
 | 
						|
                end;
 | 
						|
              procinfo.aktentrycode^.insertlist(@unitinits);
 | 
						|
              unitinits.done;
 | 
						|
        end;
 | 
						|
 | 
						|
        { a constructor needs a help procedure }
 | 
						|
        if (aktprocsym^.definition^.options and poconstructor)<>0 then
 | 
						|
        begin
 | 
						|
           if procinfo._class^.isclass then
 | 
						|
             begin
 | 
						|
              procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
 | 
						|
              procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
 | 
						|
              newcsymbol('FPC_NEW_CLASS',0))));
 | 
						|
              concat_external('FPC_NEW_CLASS',EXT_NEAR);
 | 
						|
             end
 | 
						|
           else
 | 
						|
             begin
 | 
						|
              procinfo.aktentrycode^.insert(new(pai_labeled,init(A_BEQ,quickexitlabel)));
 | 
						|
              procinfo.aktentrycode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
 | 
						|
              newcsymbol('FPC_HELP_CONSTRUCTOR',0))));
 | 
						|
              concat_external('FPC_HELP_CONSTRUCTOR',EXT_NEAR);
 | 
						|
              procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,procinfo._class^.vmt_offset,R_D0)));
 | 
						|
             end;
 | 
						|
        end;
 | 
						|
    { don't load ESI, does the caller }
 | 
						|
 | 
						|
{$ifdef GDB}
 | 
						|
      if (cs_debuginfo in aktmoduleswitches) then
 | 
						|
         list^.insert(new(pai_force_line,init));
 | 
						|
{$endif GDB}
 | 
						|
 | 
						|
    { omit stack frame ? }
 | 
						|
    if procinfo.framepointer=stack_pointer then
 | 
						|
        begin
 | 
						|
            CGMessage(cg_d_stackframe_omited);
 | 
						|
            nostackframe:=true;
 | 
						|
            if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
 | 
						|
                parasize:=0
 | 
						|
            else
 | 
						|
                parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset;
 | 
						|
        end
 | 
						|
    else
 | 
						|
        begin
 | 
						|
             if (aktprocsym^.definition^.options and (pounitinit or poproginit or pounitfinalize)<>0) then
 | 
						|
                parasize:=0
 | 
						|
             else
 | 
						|
                parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
 | 
						|
            nostackframe:=false;
 | 
						|
            if stackframe<>0 then
 | 
						|
                begin
 | 
						|
                    if cs_littlesize in aktglobalswitches  then
 | 
						|
                        begin
 | 
						|
                            if (cs_check_stack in aktlocalswitches) and
 | 
						|
                               (target_info.target<>target_m68k_linux) then
 | 
						|
                                begin
 | 
						|
                                  { If only not in main program, do we setup stack checking }
 | 
						|
                                  if (aktprocsym^.definition^.options and poproginit=0) then
 | 
						|
                                   Begin
 | 
						|
                                       procinfo.aktentrycode^.insert(new(pai68k,
 | 
						|
                                         op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
 | 
						|
                                       procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,stackframe,R_D0)));
 | 
						|
                                       concat_external('FPC_STACKCHECK',EXT_NEAR);
 | 
						|
                                   end;
 | 
						|
                                end;
 | 
						|
                            { to allocate stack space }
 | 
						|
                            { here we allocate space using link signed 16-bit version }
 | 
						|
                            { -ve offset to allocate stack space! }
 | 
						|
                            if (stackframe > -32767) and (stackframe < 32769) then
 | 
						|
                              procinfo.aktentrycode^.insert(new(pai68k,op_reg_const(A_LINK,S_W,R_A6,-stackframe)))
 | 
						|
                            else
 | 
						|
                              CGMessage(cg_e_stacklimit_in_local_routine);
 | 
						|
                        end
 | 
						|
                    else
 | 
						|
                        begin
 | 
						|
                          { Not to complicate the code generator too much, and since some  }
 | 
						|
                          { of the systems only support this format, the stackframe cannot }
 | 
						|
                          { exceed 32K in size.                                            }
 | 
						|
                          if (stackframe > -32767) and (stackframe < 32769) then
 | 
						|
                            begin
 | 
						|
                              procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_SUB,S_L,stackframe,R_SP)));
 | 
						|
                              { IF only NOT in main program do we check the stack normally }
 | 
						|
                              if (cs_check_stack in aktlocalswitches)
 | 
						|
                              and (aktprocsym^.definition^.options and poproginit=0) then
 | 
						|
                                begin
 | 
						|
                                  procinfo.aktentrycode^.insert(new(pai68k,
 | 
						|
                                   op_csymbol(A_JSR,S_NO,newcsymbol('FPC_STACKCHECK',0))));
 | 
						|
                                  procinfo.aktentrycode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,
 | 
						|
                                    stackframe,R_D0)));
 | 
						|
                                  concat_external('FPC_STACKCHECK',EXT_NEAR);
 | 
						|
                                end;
 | 
						|
                               procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
 | 
						|
                               procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
 | 
						|
                            end
 | 
						|
                          else
 | 
						|
                            CGMessage(cg_e_stacklimit_in_local_routine);
 | 
						|
                        end;
 | 
						|
                end {endif stackframe<>0 }
 | 
						|
            else
 | 
						|
               begin
 | 
						|
                 procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_SP,R_A6)));
 | 
						|
                 procinfo.aktentrycode^.insert(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A6,R_SPPUSH)));
 | 
						|
               end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
    if (aktprocsym^.definition^.options and pointerrupt)<>0 then
 | 
						|
        generate_interrupt_stackframe_entry;
 | 
						|
 | 
						|
    {proc_names.insert(aktprocsym^.definition^.mangledname);}
 | 
						|
 | 
						|
    if (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
 | 
						|
     ((procinfo._class<>nil) and (procinfo._class^.owner^.
 | 
						|
     symtabletype=globalsymtable)) then
 | 
						|
        make_global:=true;
 | 
						|
    hs:=proc_names.get;
 | 
						|
 | 
						|
{$IfDef GDB}
 | 
						|
    if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
 | 
						|
        stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
 | 
						|
{$EndIf GDB}
 | 
						|
 | 
						|
 | 
						|
    while hs<>'' do
 | 
						|
        begin
 | 
						|
              if make_global then
 | 
						|
                procinfo.aktentrycode^.insert(new(pai_symbol,init_global(hs)))
 | 
						|
              else
 | 
						|
                procinfo.aktentrycode^.insert(new(pai_symbol,init(hs)));
 | 
						|
{$ifdef GDB}
 | 
						|
            if (cs_debuginfo in aktmoduleswitches) then
 | 
						|
             begin
 | 
						|
               if target_os.use_function_relative_addresses then
 | 
						|
                list^.insert(new(pai_stab_function_name,init(strpnew(hs))));
 | 
						|
 | 
						|
            { This is not a nice solution to save the name, change it and restore when done }
 | 
						|
            { not only not nice but also completely wrong !!! (PM) }
 | 
						|
            {   aktprocsym^.setname(hs);
 | 
						|
               list^.insert(new(pai_stabs,init(aktprocsym^.stabstring))); }
 | 
						|
             end;
 | 
						|
{$endif GDB}
 | 
						|
              hs:=proc_names.get;
 | 
						|
        end;
 | 
						|
{$ifdef GDB}
 | 
						|
 | 
						|
    if (cs_debuginfo in aktmoduleswitches) then
 | 
						|
        begin
 | 
						|
            if target_os.use_function_relative_addresses then
 | 
						|
                procinfo.aktentrycode^.insert(stab_function_name);
 | 
						|
            if make_global or ((procinfo.flags and pi_is_global) <> 0) then
 | 
						|
                aktprocsym^.is_global := True;
 | 
						|
            aktprocsym^.isstabwritten:=true;
 | 
						|
        end;
 | 
						|
{$endif GDB}
 | 
						|
    { Alignment required for Motorola }
 | 
						|
    procinfo.aktentrycode^.insert(new(pai_align,init(2)));
 | 
						|
end;
 | 
						|
 | 
						|
{Generate the exit code for a procedure.}
 | 
						|
procedure genexitcode(list : paasmoutput;parasize:longint; nostackframe,inlined:boolean);
 | 
						|
var hr:Preference;          {This is for function results.}
 | 
						|
    op:Tasmop;
 | 
						|
    s:Topsize;
 | 
						|
 | 
						|
begin
 | 
						|
    { !!!! insert there automatic destructors }
 | 
						|
 | 
						|
    procinfo.aktexitcode^.insert(new(pai_label,init(aktexitlabel)));
 | 
						|
 | 
						|
    { call the destructor help procedure }
 | 
						|
    if (aktprocsym^.definition^.options and podestructor)<>0 then
 | 
						|
     begin
 | 
						|
       if procinfo._class^.isclass then
 | 
						|
         begin
 | 
						|
           procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
 | 
						|
             newcsymbol('FPC_DISPOSE_CLASS',0))));
 | 
						|
           concat_external('FPC_DISPOSE_CLASS',EXT_NEAR);
 | 
						|
         end
 | 
						|
       else
 | 
						|
         begin
 | 
						|
           procinfo.aktexitcode^.insert(new(pai68k,op_csymbol(A_JSR,S_NO,
 | 
						|
             newcsymbol('FPC_HELP_DESTRUCTOR',0))));
 | 
						|
           procinfo.aktexitcode^.insert(new(pai68k,op_const_reg(A_MOVE,S_L,procinfo._class^.vmt_offset,R_D0)));
 | 
						|
           concat_external('FPC_HELP_DESTRUCTOR',EXT_NEAR);
 | 
						|
         end;
 | 
						|
     end;
 | 
						|
 | 
						|
    { call __EXIT for main program }
 | 
						|
    { ????????? }
 | 
						|
    if ((aktprocsym^.definition^.options and poproginit)<>0) and
 | 
						|
      (target_info.target<>target_m68k_PalmOS) then
 | 
						|
     begin
 | 
						|
       procinfo.aktexitcode^.concat(new(pai68k,op_csymbol(A_JSR,S_NO,newcsymbol('FPC_DO_EXIT',0))));
 | 
						|
       externals^.concat(new(pai_external,init('FPC_DO_EXIT',EXT_NEAR)));
 | 
						|
     end;
 | 
						|
 | 
						|
    { handle return value }
 | 
						|
    if (aktprocsym^.definition^.options and poassembler)=0 then
 | 
						|
        if (aktprocsym^.definition^.options and poconstructor)=0 then
 | 
						|
            begin
 | 
						|
                if procinfo.retdef<>pdef(voiddef) then
 | 
						|
                    begin
 | 
						|
                        if not procinfo.funcret_is_valid then
 | 
						|
                          CGMessage(sym_w_function_result_not_set);
 | 
						|
                        new(hr);
 | 
						|
                        reset_reference(hr^);
 | 
						|
                        hr^.offset:=procinfo.retoffset;
 | 
						|
                        hr^.base:=procinfo.framepointer;
 | 
						|
                        if (procinfo.retdef^.deftype in [orddef,enumdef]) then
 | 
						|
                            begin
 | 
						|
                                case procinfo.retdef^.size of
 | 
						|
                                 4 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
 | 
						|
                                 2 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,hr,R_D0)));
 | 
						|
                                 1 : procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,hr,R_D0)));
 | 
						|
                                end;
 | 
						|
                            end
 | 
						|
                        else
 | 
						|
                            if (procinfo.retdef^.deftype in [pointerdef,enumdef,procvardef]) or
 | 
						|
                             ((procinfo.retdef^.deftype=setdef) and
 | 
						|
                             (psetdef(procinfo.retdef)^.settype=smallset)) then
 | 
						|
                                procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)))
 | 
						|
                            else
 | 
						|
                                if (procinfo.retdef^.deftype=floatdef) then
 | 
						|
                                    begin
 | 
						|
                                        if pfloatdef(procinfo.retdef)^.typ=f32bit then
 | 
						|
                                            begin
 | 
						|
                                                { Isnt this missing ? }
 | 
						|
                                                procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hr,R_D0)));
 | 
						|
                                            end
 | 
						|
                                        else
 | 
						|
                                            begin
 | 
						|
                                             { how the return value is handled                          }
 | 
						|
                                             { if single value, then return in d0, otherwise return in  }
 | 
						|
                                             { TRUE FPU register (does not apply in emulation mode)     }
 | 
						|
                                             if (pfloatdef(procinfo.retdef)^.typ = s32real) then
 | 
						|
                                              begin
 | 
						|
                                                procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
 | 
						|
                                                  S_L,hr,R_D0)))
 | 
						|
                                              end
 | 
						|
                                             else
 | 
						|
                                              begin
 | 
						|
                                               if cs_fp_emulation in aktmoduleswitches then
 | 
						|
                                                 procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_MOVE,
 | 
						|
                                                    S_L,hr,R_D0)))
 | 
						|
                                               else
 | 
						|
                                                 procinfo.aktexitcode^.concat(new(pai68k,op_ref_reg(A_FMOVE,
 | 
						|
                                                 getfloatsize(pfloatdef(procinfo.retdef)^.typ),hr,R_FP0)));
 | 
						|
                                             end;
 | 
						|
                                           end;
 | 
						|
                                    end
 | 
						|
                                else
 | 
						|
                                    dispose(hr);
 | 
						|
                    end
 | 
						|
            end
 | 
						|
        else
 | 
						|
            begin
 | 
						|
                { successful constructor deletes the zero flag }
 | 
						|
                { and returns self in accumulator              }
 | 
						|
                procinfo.aktexitcode^.concat(new(pai_label,init(quickexitlabel)));
 | 
						|
                { eax must be set to zero if the allocation failed !!! }
 | 
						|
                procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,R_A5,R_D0)));
 | 
						|
                { faster then OR on mc68000/mc68020 }
 | 
						|
                procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_TST,S_L,R_D0)));
 | 
						|
            end;
 | 
						|
    procinfo.aktexitcode^.concat(new(pai_label,init(aktexit2label)));
 | 
						|
    if not(nostackframe) then
 | 
						|
        procinfo.aktexitcode^.concat(new(pai68k,op_reg(A_UNLK,S_NO,R_A6)));
 | 
						|
 | 
						|
    { at last, the return is generated }
 | 
						|
 | 
						|
    if (aktprocsym^.definition^.options and pointerrupt)<>0 then
 | 
						|
        generate_interrupt_stackframe_exit
 | 
						|
    else
 | 
						|
        if (parasize=0) or ((aktprocsym^.definition^.options and poclearstack)<>0)
 | 
						|
        then
 | 
						|
            {Routines with the poclearstack flag set use only a ret.}
 | 
						|
            { also routines with parasize=0           }
 | 
						|
            procinfo.aktexitcode^.concat(new(pai68k,op_none(A_RTS,S_NO)))
 | 
						|
        else
 | 
						|
            { return with immediate size possible here }
 | 
						|
            { signed!                                  }
 | 
						|
            if (aktoptprocessor = MC68020) and (parasize < $7FFF) then
 | 
						|
                procinfo.aktexitcode^.concat(new(pai68k,op_const(
 | 
						|
                 A_RTD,S_NO,parasize)))
 | 
						|
            { manually restore the stack }
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                    { We must pull the PC Counter from the stack, before  }
 | 
						|
                    { restoring the stack pointer, otherwise the PC would }
 | 
						|
                    { point to nowhere!                                   }
 | 
						|
 | 
						|
                    { save the PC counter (pop it from the stack)         }
 | 
						|
                    procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
 | 
						|
                         A_MOVE,S_L,R_SPPULL,R_A0)));
 | 
						|
                    { can we do a quick addition ... }
 | 
						|
                    if (parasize > 0) and (parasize < 9) then
 | 
						|
                       procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
 | 
						|
                         A_ADD,S_L,parasize,R_SP)))
 | 
						|
                    else { nope ... }
 | 
						|
                       procinfo.aktexitcode^.concat(new(pai68k,op_const_reg(
 | 
						|
                         A_ADD,S_L,parasize,R_SP)));
 | 
						|
                    { endif }
 | 
						|
                    { restore the PC counter (push it on the stack)       }
 | 
						|
                    procinfo.aktexitcode^.concat(new(pai68k,op_reg_reg(
 | 
						|
                         A_MOVE,S_L,R_A0,R_SPPUSH)));
 | 
						|
                    procinfo.aktexitcode^.concat(new(pai68k,op_none(
 | 
						|
                      A_RTS,S_NO)))
 | 
						|
               end;
 | 
						|
{$ifdef GDB}
 | 
						|
    if cs_debuginfo in aktmoduleswitches  then
 | 
						|
        begin
 | 
						|
            aktprocsym^.concatstabto(procinfo.aktexitcode);
 | 
						|
            if assigned(procinfo._class) then
 | 
						|
                procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
 | 
						|
                 '"$t:v'+procinfo._class^.numberstring+'",'+
 | 
						|
                 tostr(N_PSYM)+',0,0,'+tostr(procinfo.esi_offset)))));
 | 
						|
 | 
						|
            if (porddef(aktprocsym^.definition^.retdef) <> voiddef) then
 | 
						|
                procinfo.aktexitcode^.concat(new(pai_stabs,init(strpnew(
 | 
						|
                 '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.retdef^.numberstring+'",'+
 | 
						|
                 tostr(N_PSYM)+',0,0,'+tostr(procinfo.retoffset)))));
 | 
						|
 | 
						|
            procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('192,0,0,'
 | 
						|
             +aktprocsym^.definition^.mangledname))));
 | 
						|
 | 
						|
            procinfo.aktexitcode^.concat(new(pai_stabn,init(strpnew('224,0,0,'
 | 
						|
             +lab2str(aktexit2label)))));
 | 
						|
        end;
 | 
						|
{$endif GDB}
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
    { USES REGISTERS R_A0 AND R_A1 }
 | 
						|
    { maximum size of copy is 65535 bytes                                       }
 | 
						|
    procedure concatcopy(source,dest : treference;size : longint;delsource : boolean);
 | 
						|
 | 
						|
      var
 | 
						|
         ecxpushed : boolean;
 | 
						|
         helpsize : longint;
 | 
						|
         i : byte;
 | 
						|
         reg8,reg32 : tregister;
 | 
						|
         swap : boolean;
 | 
						|
         hregister : tregister;
 | 
						|
         iregister : tregister;
 | 
						|
         jregister : tregister;
 | 
						|
         hp1 : treference;
 | 
						|
         hp2 : treference;
 | 
						|
         hl : plabel;
 | 
						|
         hl2: plabel;
 | 
						|
      begin
 | 
						|
         { this should never occur }
 | 
						|
         if size > 65535 then
 | 
						|
           internalerror(0);
 | 
						|
         hregister := getregister32;
 | 
						|
         if delsource then
 | 
						|
           del_reference(source);
 | 
						|
 | 
						|
         { from 12 bytes movs is being used }
 | 
						|
         if (size<=8) or (not(cs_littlesize in aktglobalswitches) and (size<=12)) then
 | 
						|
           begin
 | 
						|
              helpsize:=size div 4;
 | 
						|
              { move a dword x times }
 | 
						|
              for i:=1 to helpsize do
 | 
						|
                begin
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(source),hregister)));
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,hregister,newreference(dest))));
 | 
						|
                   inc(source.offset,4);
 | 
						|
                   inc(dest.offset,4);
 | 
						|
                   dec(size,4);
 | 
						|
                end;
 | 
						|
              { move a word }
 | 
						|
              if size>1 then
 | 
						|
                begin
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,newreference(source),hregister)));
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_W,hregister,newreference(dest))));
 | 
						|
                   inc(source.offset,2);
 | 
						|
                   inc(dest.offset,2);
 | 
						|
                   dec(size,2);
 | 
						|
                end;
 | 
						|
              { move a single byte }
 | 
						|
              if size>0 then
 | 
						|
                begin
 | 
						|
                  exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,newreference(source),hregister)));
 | 
						|
                  exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_B,hregister,newreference(dest))));
 | 
						|
                end
 | 
						|
 | 
						|
           end
 | 
						|
           else
 | 
						|
           begin
 | 
						|
              if (usableaddress > 1) then
 | 
						|
                begin
 | 
						|
                    iregister := getaddressreg;
 | 
						|
                    jregister := getaddressreg;
 | 
						|
                end
 | 
						|
              else
 | 
						|
              if (usableaddress = 1) then
 | 
						|
                begin
 | 
						|
                    iregister := getaddressreg;
 | 
						|
                    jregister := R_A1;
 | 
						|
                end
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                    iregister := R_A0;
 | 
						|
                    jregister := R_A1;
 | 
						|
                end;
 | 
						|
              { reference for move (An)+,(An)+ }
 | 
						|
              reset_reference(hp1);
 | 
						|
              hp1.base := iregister;   { source register }
 | 
						|
              hp1.direction := dir_inc;
 | 
						|
              reset_reference(hp2);
 | 
						|
              hp2.base := jregister;
 | 
						|
              hp2.direction := dir_inc;
 | 
						|
              { iregister = source }
 | 
						|
              { jregister = destination }
 | 
						|
 | 
						|
 | 
						|
              exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(source),iregister)));
 | 
						|
              exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,newreference(dest),jregister)));
 | 
						|
 | 
						|
              { double word move only on 68020+ machines }
 | 
						|
              { because of possible alignment problems   }
 | 
						|
              { use fast loop mode }
 | 
						|
              if (aktoptprocessor=MC68020) then
 | 
						|
                begin
 | 
						|
                   helpsize := size - size mod 4;
 | 
						|
                   size := size mod 4;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize div 4,hregister)));
 | 
						|
                   getlabel(hl2);
 | 
						|
                   emitl(A_BRA,hl2);
 | 
						|
                   getlabel(hl);
 | 
						|
                   emitl(A_LABEL,hl);
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_L,newreference(hp1),newreference(hp2))));
 | 
						|
                   emitl(A_LABEL,hl2);
 | 
						|
                   exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
 | 
						|
                   if size > 1 then
 | 
						|
                     begin
 | 
						|
                        dec(size,2);
 | 
						|
                        exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_W,newreference(hp1), newreference(hp2))));
 | 
						|
                     end;
 | 
						|
                   if size = 1 then
 | 
						|
                    exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1), newreference(hp2))));
 | 
						|
                end
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                   { Fast 68010 loop mode with no possible alignment problems }
 | 
						|
                   helpsize := size;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_const_reg(A_MOVE,S_L,helpsize,hregister)));
 | 
						|
                   getlabel(hl2);
 | 
						|
                   emitl(A_BRA,hl2);
 | 
						|
                   getlabel(hl);
 | 
						|
                   emitl(A_LABEL,hl);
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_ref(A_MOVE,S_B,newreference(hp1),newreference(hp2))));
 | 
						|
                   emitl(A_LABEL,hl2);
 | 
						|
                   exprasmlist^.concat(new(pai_labeled, init_reg(A_DBRA,hl,hregister)));
 | 
						|
                end;
 | 
						|
 | 
						|
       { restore the registers that we have just used olny if they are used! }
 | 
						|
              if jregister = R_A1 then
 | 
						|
                hp2.base := R_NO;
 | 
						|
              if iregister = R_A0 then
 | 
						|
                hp1.base := R_NO;
 | 
						|
              del_reference(hp1);
 | 
						|
              del_reference(hp2);
 | 
						|
           end;
 | 
						|
 | 
						|
           { loading SELF-reference again }
 | 
						|
           maybe_loada5;
 | 
						|
 | 
						|
           if delsource then
 | 
						|
               ungetiftemp(source);
 | 
						|
 | 
						|
           ungetregister32(hregister);
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
    procedure emitloadord2reg(location:Tlocation;orddef:Porddef;
 | 
						|
                              destreg:Tregister;delloc:boolean);
 | 
						|
 | 
						|
    {A lot smaller and less bug sensitive than the original unfolded loads.}
 | 
						|
 | 
						|
    var tai:pai68k;
 | 
						|
        r:Preference;
 | 
						|
 | 
						|
    begin
 | 
						|
        case location.loc of
 | 
						|
            LOC_REGISTER,LOC_CREGISTER:
 | 
						|
                begin
 | 
						|
                    case orddef^.typ of
 | 
						|
                        u8bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
 | 
						|
                               end;
 | 
						|
                        s8bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_B,location.register,destreg)));
 | 
						|
                                 if (aktoptprocessor <> MC68020) then
 | 
						|
                                  begin
 | 
						|
                                 { byte to word }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
 | 
						|
                                 { word to long }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
 | 
						|
                                  end
 | 
						|
                                 else { 68020+ and later only }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
 | 
						|
                                end;
 | 
						|
                        u16bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FFFF,destreg)));
 | 
						|
                                end;
 | 
						|
                        s16bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_W,location.register,destreg)));
 | 
						|
                                 { word to long }
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
 | 
						|
                                end;
 | 
						|
                        u32bit:
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
 | 
						|
                        s32bit:
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_reg_reg(A_MOVE,S_L,location.register,destreg)));
 | 
						|
                    end;
 | 
						|
                    if delloc then
 | 
						|
                        ungetregister(location.register);
 | 
						|
                end;
 | 
						|
            LOC_REFERENCE:
 | 
						|
                begin
 | 
						|
                    r:=newreference(location.reference);
 | 
						|
                    case orddef^.typ of
 | 
						|
                        u8bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$FF,destreg)));
 | 
						|
                               end;
 | 
						|
                        s8bit:  begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_B,r,destreg)));
 | 
						|
                                 if (aktoptprocessor <> MC68020) then
 | 
						|
                                  begin
 | 
						|
                                 { byte to word }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_W,destreg)));
 | 
						|
                                 { word to long }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
 | 
						|
                                  end
 | 
						|
                                 else { 68020+ and later only }
 | 
						|
                                     exprasmlist^.concat(new(pai68k,op_reg(A_EXTB,S_L,destreg)));
 | 
						|
                                end;
 | 
						|
                        u16bit: begin
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_const_reg(A_ANDI,S_L,$ffff,destreg)));
 | 
						|
                                end;
 | 
						|
                        s16bit: begin
 | 
						|
                                       exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_W,r,destreg)));
 | 
						|
                                 { word to long }
 | 
						|
                                 exprasmlist^.concat(new(pai68k,op_reg(A_EXT,S_L,destreg)));
 | 
						|
                                end;
 | 
						|
                        u32bit:
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
 | 
						|
                        s32bit:
 | 
						|
                            exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,r,destreg)));
 | 
						|
                    end;
 | 
						|
                    if delloc then
 | 
						|
                        del_reference(location.reference);
 | 
						|
                end
 | 
						|
            else
 | 
						|
                internalerror(6);
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
 | 
						|
 | 
						|
    { if necessary A5 is reloaded after a call}
 | 
						|
    procedure maybe_loada5;
 | 
						|
 | 
						|
      var
 | 
						|
         hp : preference;
 | 
						|
         p : pprocinfo;
 | 
						|
         i : longint;
 | 
						|
 | 
						|
      begin
 | 
						|
         if assigned(procinfo._class) then
 | 
						|
           begin
 | 
						|
              if lexlevel>normal_function_level then
 | 
						|
                begin
 | 
						|
                   new(hp);
 | 
						|
                   reset_reference(hp^);
 | 
						|
                   hp^.offset:=procinfo.framepointer_offset;
 | 
						|
                   hp^.base:=procinfo.framepointer;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
 | 
						|
                   p:=procinfo.parent;
 | 
						|
                   for i:=3 to lexlevel-1 do
 | 
						|
                     begin
 | 
						|
                        new(hp);
 | 
						|
                        reset_reference(hp^);
 | 
						|
                        hp^.offset:=p^.framepointer_offset;
 | 
						|
                        hp^.base:=R_A5;
 | 
						|
                        exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
 | 
						|
                        p:=p^.parent;
 | 
						|
                     end;
 | 
						|
                   new(hp);
 | 
						|
                   reset_reference(hp^);
 | 
						|
                   hp^.offset:=p^.ESI_offset;
 | 
						|
                   hp^.base:=R_A5;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
 | 
						|
                end
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                   new(hp);
 | 
						|
                   reset_reference(hp^);
 | 
						|
                   hp^.offset:=procinfo.ESI_offset;
 | 
						|
                   hp^.base:=procinfo.framepointer;
 | 
						|
                   exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,hp,R_A5)));
 | 
						|
                end;
 | 
						|
           end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
  (***********************************************************************)
 | 
						|
  (* PROCEDURE FLOATLOAD                                                 *)
 | 
						|
  (*  Description: This routine is to be called each time a location     *)
 | 
						|
  (*   must be set to LOC_FPU and a value loaded into a FPU register.    *)
 | 
						|
  (*                                                                     *)
 | 
						|
  (*  Remark: The routine sets up the register field of LOC_FPU correctly*)
 | 
						|
  (***********************************************************************)
 | 
						|
 | 
						|
    procedure floatload(t : tfloattype;const ref : treference; var location:tlocation);
 | 
						|
 | 
						|
      var
 | 
						|
         op : tasmop;
 | 
						|
         s : topsize;
 | 
						|
 | 
						|
      begin
 | 
						|
        { no emulation }
 | 
						|
        case t of
 | 
						|
            s32real : s := S_FS;
 | 
						|
            s64real : s := S_FL;
 | 
						|
            s80real : s := S_FX;
 | 
						|
         else
 | 
						|
           begin
 | 
						|
             CGMessage(cg_f_unknown_float_type);
 | 
						|
           end;
 | 
						|
        end; { end case }
 | 
						|
        location.loc := LOC_FPU;
 | 
						|
        if not ((cs_fp_emulation) in aktmoduleswitches) then
 | 
						|
        begin
 | 
						|
            location.fpureg := getfloatreg;
 | 
						|
            exprasmlist^.concat(new(pai68k,op_ref_reg(A_FMOVE,s,newreference(ref),location.fpureg)))
 | 
						|
        end
 | 
						|
        else
 | 
						|
        { handle emulation }
 | 
						|
        begin
 | 
						|
          if t = s32real then
 | 
						|
          begin
 | 
						|
            location.fpureg := getregister32;
 | 
						|
            exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(ref),location.fpureg)))
 | 
						|
          end
 | 
						|
          else
 | 
						|
             { other floating types are not supported in emulation mode }
 | 
						|
            CGMessage(sym_e_type_id_not_defined);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
{    procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
 | 
						|
 | 
						|
      begin
 | 
						|
         case t of
 | 
						|
            s32real : begin
 | 
						|
                         op:=A_FSTP;
 | 
						|
                         s:=S_FS;
 | 
						|
                      end;
 | 
						|
            s64real : begin
 | 
						|
                         op:=A_FSTP;
 | 
						|
                         s:=S_FL;
 | 
						|
                      end;
 | 
						|
            s80real : begin
 | 
						|
                         op:=A_FSTP;
 | 
						|
                         s:=S_FX;
 | 
						|
                      end;
 | 
						|
            s64bit : begin
 | 
						|
                         op:=A_FISTP;
 | 
						|
                         s:=S_IQ;
 | 
						|
                      end;
 | 
						|
            else internalerror(17);
 | 
						|
         end;
 | 
						|
      end; }
 | 
						|
 | 
						|
 | 
						|
    { stores an FPU value to memory }
 | 
						|
    { location:tlocation used to free up FPU register }
 | 
						|
    { ref: destination of storage                     }
 | 
						|
    procedure floatstore(t : tfloattype;var location:tlocation; const ref:treference);
 | 
						|
 | 
						|
      var
 | 
						|
         op : tasmop;
 | 
						|
         s : topsize;
 | 
						|
 | 
						|
      begin
 | 
						|
        if location.loc <> LOC_FPU then
 | 
						|
         InternalError(34);
 | 
						|
        { no emulation }
 | 
						|
        case t of
 | 
						|
            s32real : s := S_FS;
 | 
						|
            s64real : s := S_FL;
 | 
						|
            s80real : s := S_FX;
 | 
						|
         else
 | 
						|
           begin
 | 
						|
             CGMessage(cg_f_unknown_float_type);
 | 
						|
           end;
 | 
						|
        end; { end case }
 | 
						|
        if not ((cs_fp_emulation) in aktmoduleswitches) then
 | 
						|
        begin
 | 
						|
            { This permits the mixing of emulation and non-emulation routines }
 | 
						|
            { only possible for REAL = SINGLE value_str                          }
 | 
						|
            if not (location.fpureg in [R_FP0..R_FP7]) then
 | 
						|
             Begin
 | 
						|
               if s = S_FS then
 | 
						|
                 exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))))
 | 
						|
               else
 | 
						|
                 internalerror(255);
 | 
						|
             end
 | 
						|
            else
 | 
						|
               exprasmlist^.concat(new(pai68k,op_reg_ref(A_FMOVE,s,location.fpureg,newreference(ref))));
 | 
						|
            ungetregister(location.fpureg);
 | 
						|
        end
 | 
						|
        else
 | 
						|
        { handle emulation }
 | 
						|
        begin
 | 
						|
          if t = s32real then
 | 
						|
          begin
 | 
						|
            exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,S_L,location.fpureg,newreference(ref))));
 | 
						|
            ungetregister32(location.fpureg);
 | 
						|
          end
 | 
						|
          else
 | 
						|
             { other floating types are not supported in emulation mode }
 | 
						|
            CGMessage(sym_e_type_id_not_defined);
 | 
						|
        end;
 | 
						|
        location.fpureg:=R_NO;  { no register in LOC_FPU now }
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure firstcomplex(p : ptree);
 | 
						|
 | 
						|
      var
 | 
						|
         hp : ptree;
 | 
						|
 | 
						|
      begin
 | 
						|
         { always calculate boolean AND and OR from left to right }
 | 
						|
         if ((p^.treetype=orn) or (p^.treetype=andn)) and
 | 
						|
           (p^.left^.resulttype^.deftype=orddef) and
 | 
						|
           (porddef(p^.left^.resulttype)^.typ=bool8bit) then
 | 
						|
           p^.swaped:=false
 | 
						|
         else if (p^.left^.registers32<p^.right^.registers32)
 | 
						|
 | 
						|
           { the following check is appropriate, because all }
 | 
						|
           { 4 registers are rarely used and it is thereby   }
 | 
						|
                      { achieved that the extra code is being dropped   }
 | 
						|
           { by exchanging not commutative operators         }
 | 
						|
           and (p^.right^.registers32<=4) then
 | 
						|
           begin
 | 
						|
              hp:=p^.left;
 | 
						|
              p^.left:=p^.right;
 | 
						|
              p^.right:=hp;
 | 
						|
              p^.swaped:=true;
 | 
						|
           end
 | 
						|
         else p^.swaped:=false;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{$ifdef test_dest_loc}
 | 
						|
        procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
 | 
						|
 | 
						|
          begin
 | 
						|
             if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
 | 
						|
               begin
 | 
						|
                 emit_reg_reg(A_MOVE,s,reg,dest_loc.register);
 | 
						|
                 set_location(p^.location,dest_loc);
 | 
						|
                 in_dest_loc:=true;
 | 
						|
               end
 | 
						|
             else
 | 
						|
             if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
 | 
						|
               begin
 | 
						|
                 exprasmlist^.concat(new(pai68k,op_reg_ref(A_MOVE,s,reg,newreference(dest_loc.reference))));
 | 
						|
                 set_location(p^.location,dest_loc);
 | 
						|
                 in_dest_loc:=true;
 | 
						|
               end
 | 
						|
             else
 | 
						|
               internalerror(20080);
 | 
						|
          end;
 | 
						|
 | 
						|
{$endif test_dest_loc}
 | 
						|
 | 
						|
    procedure removetemps(list : paasmoutput;p : plinkedlist);
 | 
						|
 | 
						|
      var
 | 
						|
         hp : ptemptodestroy;
 | 
						|
 | 
						|
      begin
 | 
						|
         hp:=ptemptodestroy(p^.first);
 | 
						|
         while assigned(hp) do
 | 
						|
           begin
 | 
						|
              if is_ansistring(hp^.typ) then
 | 
						|
                begin
 | 
						|
                   emitpushreferenceaddr(list,hp^.address);
 | 
						|
                   list^.concat(new(pai68k,
 | 
						|
                     op_csymbol(A_JSR,S_NO,newcsymbol('FPC_ANSISTR_DECR_REF',0))));
 | 
						|
                   if not (cs_compilesystem in aktmoduleswitches) then
 | 
						|
                     concat_external('FPC_ANSISTR_DECR_REF',EXT_NEAR);
 | 
						|
                end;
 | 
						|
              hp:=ptemptodestroy(hp^.next);
 | 
						|
           end;
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure releasedata(p : plinkedlist);
 | 
						|
 | 
						|
      var
 | 
						|
         hp : ptemptodestroy;
 | 
						|
 | 
						|
      begin
 | 
						|
         hp:=ptemptodestroy(p^.first);
 | 
						|
         while assigned(hp) do
 | 
						|
           begin
 | 
						|
              ungetiftemp(hp^.address);
 | 
						|
              hp:=ptemptodestroy(hp^.next);
 | 
						|
           end;
 | 
						|
      end;
 | 
						|
 | 
						|
end.
 | 
						|
{
 | 
						|
  $Log$
 | 
						|
  Revision 1.31  1998-12-11 00:03:09  peter
 | 
						|
    + globtype,tokens,version unit splitted from globals
 | 
						|
 | 
						|
  Revision 1.30  1998/11/30 09:43:05  pierre
 | 
						|
    * some range check bugs fixed (still not working !)
 | 
						|
    + added DLL writing support for win32 (also accepts variables)
 | 
						|
    + TempAnsi for code that could be used for Temporary ansi strings
 | 
						|
      handling
 | 
						|
 | 
						|
  Revision 1.29  1998/11/13 15:40:16  pierre
 | 
						|
    + added -Se in Makefile cvstest target
 | 
						|
    + lexlevel cleanup
 | 
						|
      normal_function_level main_program_level and unit_init_level defined
 | 
						|
    * tins_cache grown to A_EMMS (gave range check error in asm readers)
 | 
						|
      (test added in code !)
 | 
						|
    * -Un option was wrong
 | 
						|
    * _FAIL and _SELF only keyword inside
 | 
						|
      constructors and methods respectively
 | 
						|
 | 
						|
  Revision 1.28  1998/11/12 11:19:42  pierre
 | 
						|
   * fix for first line of function break
 | 
						|
 | 
						|
  Revision 1.27  1998/11/12 09:46:17  pierre
 | 
						|
    + break main stops before calls to unit inits
 | 
						|
    + break at constructors stops before call to FPC_NEW_CLASS
 | 
						|
      or FPC_HELP_CONSTRUCTOR
 | 
						|
 | 
						|
  Revision 1.26  1998/10/20 08:06:46  pierre
 | 
						|
    * several memory corruptions due to double freemem solved
 | 
						|
      => never use p^.loc.location:=p^.left^.loc.location;
 | 
						|
    + finally I added now by default
 | 
						|
      that ra386dir translates global and unit symbols
 | 
						|
    + added a first field in tsymtable and
 | 
						|
      a nextsym field in tsym
 | 
						|
      (this allows to obtain ordered type info for
 | 
						|
      records and objects in gdb !)
 | 
						|
 | 
						|
  Revision 1.25  1998/10/16 13:12:48  pierre
 | 
						|
    * added vmt_offsets in destructors code also !!!
 | 
						|
    * vmt_offset code for m68k
 | 
						|
 | 
						|
  Revision 1.24  1998/10/15 12:37:42  pierre
 | 
						|
    + passes vmt offset to HELP_CONSTRUCTOR for objects
 | 
						|
 | 
						|
  Revision 1.23  1998/10/14 11:28:22  florian
 | 
						|
    * emitpushreferenceaddress gets now the asmlist as parameter
 | 
						|
    * m68k version compiles with -duseansistrings
 | 
						|
 | 
						|
  Revision 1.22  1998/10/13 16:50:12  pierre
 | 
						|
    * undid some changes of Peter that made the compiler wrong
 | 
						|
      for m68k (I had to reinsert some ifdefs)
 | 
						|
    * removed several memory leaks under m68k
 | 
						|
    * removed the meory leaks for assembler readers
 | 
						|
    * cross compiling shoud work again better
 | 
						|
      ( crosscompiling sysamiga works
 | 
						|
       but as68k still complain about some code !)
 | 
						|
 | 
						|
  Revision 1.21  1998/10/13 13:10:12  peter
 | 
						|
    * new style for m68k/i386 infos and enums
 | 
						|
 | 
						|
  Revision 1.20  1998/10/13 08:19:29  pierre
 | 
						|
    + source_os is now set correctly for cross-processor compilers
 | 
						|
      (tos contains all target_infos and
 | 
						|
       we use CPU86 and CPU68 conditionnals to
 | 
						|
       get the source operating system
 | 
						|
       this only works if you do not undefine
 | 
						|
       the source target  !!)
 | 
						|
    * several cg68k memory leaks fixed
 | 
						|
    + started to change the code so that it should be possible to have
 | 
						|
      a complete compiler (both for m68k and i386 !!)
 | 
						|
 | 
						|
  Revision 1.19  1998/10/08 13:48:40  peter
 | 
						|
    * fixed memory leaks for do nothing source
 | 
						|
    * fixed unit interdependency
 | 
						|
 | 
						|
  Revision 1.18  1998/09/28 16:57:17  pierre
 | 
						|
    * changed all length(p^.value_str^) into str_length(p)
 | 
						|
      to get it work with and without ansistrings
 | 
						|
    * changed sourcefiles field of tmodule to a pointer
 | 
						|
 | 
						|
  Revision 1.17  1998/09/17 09:42:30  peter
 | 
						|
    + pass_2 for cg386
 | 
						|
    * Message() -> CGMessage() for pass_1/pass_2
 | 
						|
 | 
						|
  Revision 1.16  1998/09/14 10:44:04  peter
 | 
						|
    * all internal RTL functions start with FPC_
 | 
						|
 | 
						|
  Revision 1.15  1998/09/07 18:46:00  peter
 | 
						|
    * update smartlinking, uses getdatalabel
 | 
						|
    * renamed ptree.value vars to value_str,value_real,value_set
 | 
						|
 | 
						|
  Revision 1.14  1998/09/04 08:41:50  peter
 | 
						|
    * updated some error CGMessages
 | 
						|
 | 
						|
  Revision 1.13  1998/09/01 12:48:02  peter
 | 
						|
    * use pdef^.size instead of orddef^.typ
 | 
						|
 | 
						|
  Revision 1.12  1998/09/01 09:07:09  peter
 | 
						|
    * m68k fixes, splitted cg68k like cgi386
 | 
						|
 | 
						|
  Revision 1.11  1998/08/31 12:26:24  peter
 | 
						|
    * m68k and palmos updates from surebugfixes
 | 
						|
 | 
						|
  Revision 1.10  1998/08/21 14:08:41  pierre
 | 
						|
    + TEST_FUNCRET now default (old code removed)
 | 
						|
      works also for m68k (at least compiles)
 | 
						|
 | 
						|
  Revision 1.9  1998/08/17 10:10:04  peter
 | 
						|
    - removed OLDPPU
 | 
						|
 | 
						|
  Revision 1.8  1998/08/10 14:43:16  peter
 | 
						|
    * string type st_ fixed
 | 
						|
 | 
						|
  Revision 1.7  1998/07/10 10:51:01  peter
 | 
						|
    * m68k updates
 | 
						|
 | 
						|
  Revision 1.6  1998/06/08 13:13:39  pierre
 | 
						|
    + temporary variables now in temp_gen.pas unit
 | 
						|
      because it is processor independent
 | 
						|
    * mppc68k.bat modified to undefine i386 and support_mmx
 | 
						|
      (which are defaults for i386)
 | 
						|
 | 
						|
  Revision 1.5  1998/06/04 23:51:36  peter
 | 
						|
    * m68k compiles
 | 
						|
    + .def file creation moved to gendef.pas so it could also be used
 | 
						|
      for win32
 | 
						|
 | 
						|
  Revision 1.4  1998/05/07 00:17:00  peter
 | 
						|
    * smartlinking for sets
 | 
						|
    + consts labels are now concated/generated in hcodegen
 | 
						|
    * moved some cpu code to cga and some none cpu depended code from cga
 | 
						|
      to tree and hcodegen and cleanup of hcodegen
 | 
						|
    * assembling .. output reduced for smartlinking ;)
 | 
						|
 | 
						|
  Revision 1.3  1998/04/29 10:33:46  pierre
 | 
						|
    + added some code for ansistring (not complete nor working yet)
 | 
						|
    * corrected operator overloading
 | 
						|
    * corrected nasm output
 | 
						|
    + started inline procedures
 | 
						|
    + added starstarn : use ** for exponentiation (^ gave problems)
 | 
						|
    + started UseTokenInfo cond to get accurate positions
 | 
						|
}
 |