|
@@ -0,0 +1,426 @@
|
|
|
|
+{
|
|
|
|
+ $Id$
|
|
|
|
+ Copyright (c) 1993-98 by Florian Klaempfl
|
|
|
|
+
|
|
|
|
+ This unit handles the codegeneration pass
|
|
|
|
+
|
|
|
|
+ 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.
|
|
|
|
+
|
|
|
|
+ ****************************************************************************
|
|
|
|
+}
|
|
|
|
+{$ifdef TP}
|
|
|
|
+ {$E+,F+,N+}
|
|
|
|
+{$endif}
|
|
|
|
+unit pass_2;
|
|
|
|
+interface
|
|
|
|
+
|
|
|
|
+uses
|
|
|
|
+ tree;
|
|
|
|
+
|
|
|
|
+{ produces assembler for the expression in variable p }
|
|
|
|
+{ and produces an assembler node at the end }
|
|
|
|
+procedure generatecode(var p : pnode);
|
|
|
|
+
|
|
|
|
+{ produces the actual code }
|
|
|
|
+function do_secondpass(p : pnode) : boolean;
|
|
|
|
+procedure secondpass(p : pnode);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+implementation
|
|
|
|
+
|
|
|
|
+ uses
|
|
|
|
+ globtype,systems,
|
|
|
|
+ cobjects,verbose,comphook,globals,files,
|
|
|
|
+ symtable,types,aasm,scanner,
|
|
|
|
+ pass_1,tgobj,cgbase,cgobj,tgcpu
|
|
|
|
+{$ifdef GDB}
|
|
|
|
+ ,gdb
|
|
|
|
+{$endif}
|
|
|
|
+{$i cpuunit.inc}
|
|
|
|
+ ;
|
|
|
|
+ type
|
|
|
|
+ perrornode = ^terrornode;
|
|
|
|
+
|
|
|
|
+ terrornode = object(tnode)
|
|
|
|
+ constructor init;
|
|
|
|
+ procedure secondpass;virtual;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ tstatementnode = object(tbinarynode)
|
|
|
|
+ procedure secondpass;virtual;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ tblocknode = object(tunarynode)
|
|
|
|
+ procedure secondpass;virtual;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ tasmnode = object(tnode)
|
|
|
|
+ p_asm : paasmoutput;
|
|
|
|
+ object_preserved : boolean;
|
|
|
|
+ procedure secondpass;virtual;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+{****************************************************************************
|
|
|
|
+ TERRORNODE
|
|
|
|
+ ****************************************************************************}
|
|
|
|
+
|
|
|
|
+ constructor terrornode.init;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ inherited init;
|
|
|
|
+ treetype:=errorn;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure terrornode.secondpass;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ error:=true;
|
|
|
|
+ codegenerror:=true;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+{****************************************************************************
|
|
|
|
+ TSTATEMENTNODE
|
|
|
|
+ ****************************************************************************}
|
|
|
|
+
|
|
|
|
+ procedure tstatementnode.secondpass;
|
|
|
|
+
|
|
|
|
+ var
|
|
|
|
+ hp : pbinarynode;
|
|
|
|
+ oldrl : plinkedlist;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ hp:=@self;
|
|
|
|
+ while assigned(hp) do
|
|
|
|
+ begin
|
|
|
|
+ if assigned(hp^.right) then
|
|
|
|
+ begin
|
|
|
|
+ tg.cleartempgen;
|
|
|
|
+ oldrl:=temptoremove;
|
|
|
|
+ temptoremove:=new(plinkedlist,init);
|
|
|
|
+ hp^.right^.secondpass;
|
|
|
|
+ { release temp. ansi strings }
|
|
|
|
+ cg^.g_removetemps(exprasmlist,temptoremove);
|
|
|
|
+ dispose(temptoremove,done);
|
|
|
|
+ temptoremove:=oldrl;
|
|
|
|
+ end;
|
|
|
|
+ hp:=pbinarynode(hp^.left);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure tblocknode.secondpass;
|
|
|
|
+ begin
|
|
|
|
+ { do second pass on left node }
|
|
|
|
+ if assigned(left) then
|
|
|
|
+ left^.secondpass;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure tasmnode.secondpass;
|
|
|
|
+ begin
|
|
|
|
+ exprasmlist^.concatlist(p_asm);
|
|
|
|
+ if not object_preserved then
|
|
|
|
+ cg^.g_maybe_loadself(exprasmlist);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure secondpass(p : pnode);
|
|
|
|
+
|
|
|
|
+ var
|
|
|
|
+ oldcodegenerror : boolean;
|
|
|
|
+ oldlocalswitches : tlocalswitches;
|
|
|
|
+ oldpos : tfileposinfo;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ if not(p^.error) then
|
|
|
|
+ begin
|
|
|
|
+ oldcodegenerror:=codegenerror;
|
|
|
|
+ oldlocalswitches:=aktlocalswitches;
|
|
|
|
+ oldpos:=aktfilepos;
|
|
|
|
+
|
|
|
|
+ aktfilepos:=p^.fileinfo;
|
|
|
|
+ aktlocalswitches:=p^.localswitches;
|
|
|
|
+ codegenerror:=false;
|
|
|
|
+ p^.secondpass;
|
|
|
|
+ p^.error:=codegenerror;
|
|
|
|
+
|
|
|
|
+ codegenerror:=codegenerror or oldcodegenerror;
|
|
|
|
+ aktlocalswitches:=oldlocalswitches;
|
|
|
|
+ aktfilepos:=oldpos;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ codegenerror:=true;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ function do_secondpass(p : pnode) : boolean;
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ codegenerror:=false;
|
|
|
|
+ if not(p^.error) then
|
|
|
|
+ secondpass(p);
|
|
|
|
+ do_secondpass:=codegenerror;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ var
|
|
|
|
+ regvars : array[1..maxvarregs] of pvarsym;
|
|
|
|
+ regvars_para : array[1..maxvarregs] of boolean;
|
|
|
|
+ regvars_refs : array[1..maxvarregs] of longint;
|
|
|
|
+ parasym : boolean;
|
|
|
|
+
|
|
|
|
+ procedure searchregvars(p : pnamedindexobject);
|
|
|
|
+ var
|
|
|
|
+ i,j,k : longint;
|
|
|
|
+ begin
|
|
|
|
+ if (pvarsym(p)^.typ=varsym) and ((pvarsym(p)^.var_options and vo_regable)<>0) then
|
|
|
|
+ begin
|
|
|
|
+ { walk through all momentary register variables }
|
|
|
|
+ for i:=1 to maxvarregs do
|
|
|
|
+ begin
|
|
|
|
+ { free register ? }
|
|
|
|
+ if regvars[i]=nil then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]:=pvarsym(p);
|
|
|
|
+ regvars_para[i]:=parasym;
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ { else throw out a variable ? }
|
|
|
|
+ j:=pvarsym(p)^.refs;
|
|
|
|
+ { parameter get a less value }
|
|
|
|
+ if parasym then
|
|
|
|
+ begin
|
|
|
|
+ if cs_littlesize in aktglobalswitches then
|
|
|
|
+ dec(j,1)
|
|
|
|
+ else
|
|
|
|
+ dec(j,100);
|
|
|
|
+ end;
|
|
|
|
+ if (j>regvars_refs[i]) and (j>0) then
|
|
|
|
+ begin
|
|
|
|
+ for k:=maxvarregs-1 downto i do
|
|
|
|
+ begin
|
|
|
|
+ regvars[k+1]:=regvars[k];
|
|
|
|
+ regvars_para[k+1]:=regvars_para[k];
|
|
|
|
+ end;
|
|
|
|
+ { calc the new refs
|
|
|
|
+ pvarsym(p)^.refs:=j; }
|
|
|
|
+ regvars[i]:=pvarsym(p);
|
|
|
|
+ regvars_para[i]:=parasym;
|
|
|
|
+ regvars_refs[i]:=j;
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ procedure generatecode(var p : pnode);
|
|
|
|
+ var
|
|
|
|
+ i : longint;
|
|
|
|
+ regsize : topsize;
|
|
|
|
+ hr : preference;
|
|
|
|
+ label
|
|
|
|
+ nextreg;
|
|
|
|
+ begin
|
|
|
|
+ temptoremove:=nil;
|
|
|
|
+ tg.cleartempgen;
|
|
|
|
+ { when size optimization only count occurrence }
|
|
|
|
+ if cs_littlesize in aktglobalswitches then
|
|
|
|
+ t_times:=1
|
|
|
|
+ else
|
|
|
|
+ { reference for repetition is 100 }
|
|
|
|
+ t_times:=100;
|
|
|
|
+ { clear register count }
|
|
|
|
+ tg.clearregistercount;
|
|
|
|
+ use_esp_stackframe:=false;
|
|
|
|
+
|
|
|
|
+ if not(do_firstpassnode(p)) then
|
|
|
|
+ begin
|
|
|
|
+ { max. optimizations }
|
|
|
|
+ { only if no asm is used }
|
|
|
|
+ { and no try statement }
|
|
|
|
+ if (cs_regalloc in aktglobalswitches) and
|
|
|
|
+ ((procinfo.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
|
|
|
|
+ begin
|
|
|
|
+ { can we omit the stack frame ? }
|
|
|
|
+ { conditions:
|
|
|
|
+ 1. procedure (not main block)
|
|
|
|
+ 2. no constructor or destructor
|
|
|
|
+ 3. no call to other procedures
|
|
|
|
+ 4. no interrupt handler
|
|
|
|
+ }
|
|
|
|
+ if assigned(aktprocsym) then
|
|
|
|
+ begin
|
|
|
|
+ if (aktprocsym^.definition^.options and
|
|
|
|
+ (poconstructor+podestructor{+poinline}+pointerrupt)=0) and
|
|
|
|
+ ((procinfo.flags and pi_do_call)=0) and
|
|
|
|
+ (lexlevel>=normal_function_level) then
|
|
|
|
+ begin
|
|
|
|
+ { use ESP as frame pointer }
|
|
|
|
+ procinfo.framepointer:=stack_pointer;
|
|
|
|
+ use_esp_stackframe:=true;
|
|
|
|
+
|
|
|
|
+ { calc parameter distance new }
|
|
|
|
+ dec(procinfo.framepointer_offset,pointersize);
|
|
|
|
+ dec(procinfo.selfpointer_offset,pointersize);
|
|
|
|
+
|
|
|
|
+ { is this correct ???}
|
|
|
|
+ { retoffset can be negativ for results in eax !! }
|
|
|
|
+ { the value should be decreased only if positive }
|
|
|
|
+ if procinfo.retoffset>=0 then
|
|
|
|
+ dec(procinfo.retoffset,4);
|
|
|
|
+
|
|
|
|
+ dec(procinfo.call_offset,4);
|
|
|
|
+ aktprocsym^.definition^.parast^.address_fixup:=procinfo.call_offset;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if (p^.registersint<maxvarregs) then
|
|
|
|
+ begin
|
|
|
|
+ for i:=1 to maxvarregs do
|
|
|
|
+ regvars[i]:=nil;
|
|
|
|
+ parasym:=false;
|
|
|
|
+ {$ifdef tp}
|
|
|
|
+ symtablestack^.foreach(searchregvars);
|
|
|
|
+ {$else}
|
|
|
|
+ symtablestack^.foreach(@searchregvars);
|
|
|
|
+ {$endif}
|
|
|
|
+ { copy parameter into a register ? }
|
|
|
|
+ parasym:=true;
|
|
|
|
+ {$ifdef tp}
|
|
|
|
+ symtablestack^.next^.foreach(searchregvars);
|
|
|
|
+ {$else}
|
|
|
|
+ symtablestack^.next^.foreach(@searchregvars);
|
|
|
|
+ {$endif}
|
|
|
|
+ { hold needed registers free }
|
|
|
|
+ for i:=maxvarregs downto maxvarregs-p^.registersint+1 do
|
|
|
|
+ regvars[i]:=nil;
|
|
|
|
+ { now assign register }
|
|
|
|
+ for i:=1 to maxvarregs-p^.registersint do
|
|
|
|
+ begin
|
|
|
|
+ if assigned(regvars[i]) then
|
|
|
|
+ begin
|
|
|
|
+ { it is nonsens, to copy the variable to }
|
|
|
|
+ { a register because we need then much }
|
|
|
|
+ { pushes ? }
|
|
|
|
+ if reg_pushes[varregs[i]]>=regvars[i]^.refs then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]:=nil;
|
|
|
|
+ goto nextreg;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { register is no longer available for }
|
|
|
|
+ { expressions }
|
|
|
|
+ { search the register which is the most }
|
|
|
|
+ { unused }
|
|
|
|
+ exclude(tg.availabletempregsint,varregs[i]);
|
|
|
|
+ is_reg_var[varregs[i]]:=true;
|
|
|
|
+ dec(tg.c_countusableregsint);
|
|
|
|
+
|
|
|
|
+ { possibly no 32 bit register are needed }
|
|
|
|
+ { call by reference/const ? }
|
|
|
|
+ {!!!!!!!!!!!!!!
|
|
|
|
+ if (regvars[i]^.varspez=vs_var) or
|
|
|
|
+ ((regvars[i]^.varspez=vs_const) and
|
|
|
|
+ dont_copy_const_param(regvars[i]^.definition)) then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]^.reg:=varregs[i];
|
|
|
|
+ regsize:=sizepostfix_pointer;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ }
|
|
|
|
+ if (regvars[i]^.definition^.deftype=orddef) and
|
|
|
|
+ (porddef(regvars[i]^.definition)^.size=1) then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]^.reg:=regtoreg8(varregs[i]);
|
|
|
|
+ regsize:=S_B;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ if (regvars[i]^.definition^.deftype=orddef) and
|
|
|
|
+ (porddef(regvars[i]^.definition)^.size=2) then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]^.reg:=regtoreg16(varregs[i]);
|
|
|
|
+ regsize:=S_W;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ if (regvars[i]^.definition^.deftype=orddef) and
|
|
|
|
+ (porddef(regvars[i]^.definition)^.size=4) then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]^.reg:=regtoreg32(varregs[i]);
|
|
|
|
+ regsize:=S_L;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ if (cf_registers64 in cpuflags) and
|
|
|
|
+ (regvars[i]^.definition^.deftype=orddef) and
|
|
|
|
+ (porddef(regvars[i]^.definition)^.size=8) then
|
|
|
|
+ begin
|
|
|
|
+ regvars[i]^.reg:=regtoreg64(varregs[i]);
|
|
|
|
+ regsize:=S_Q;
|
|
|
|
+ end;
|
|
|
|
+ { parameter must be load }
|
|
|
|
+ if regvars_para[i] then
|
|
|
|
+ begin
|
|
|
|
+ { procinfo is there actual, }
|
|
|
|
+ { because we can't never be in a }
|
|
|
|
+ { nested procedure }
|
|
|
|
+ { when loading parameter to reg }
|
|
|
|
+ new(hr);
|
|
|
|
+ reset_reference(hr^);
|
|
|
|
+ hr^.offset:=pvarsym(regvars[i])^.address+procinfo.call_offset;
|
|
|
|
+ hr^.base:=procinfo.framepointer;
|
|
|
|
+{$ifdef i386}
|
|
|
|
+ procinfo.aktentrycode^.concat(new(pai386,op_ref_reg(A_MOV,regsize,
|
|
|
|
+ hr,regvars[i]^.reg)));
|
|
|
|
+{$endif i386}
|
|
|
|
+{$ifdef m68k}
|
|
|
|
+ procinfo.aktentrycode^.concat(new(pai68k,op_ref_reg(A_MOVE,regsize,
|
|
|
|
+ hr,regvars[i]^.reg)));
|
|
|
|
+{$endif m68k}
|
|
|
|
+ tg.unusedregsint:=tg.unusedregsint - [regvars[i]^.reg];
|
|
|
|
+ end;
|
|
|
|
+ { procedure uses this register }
|
|
|
|
+ include(tg.usedinproc,varregs[i]);
|
|
|
|
+ end;
|
|
|
|
+ nextreg:
|
|
|
|
+ { dummy }
|
|
|
|
+ regsize:=S_W;
|
|
|
|
+ end;
|
|
|
|
+ if (status.verbosity and v_debug)=v_debug then
|
|
|
|
+ begin
|
|
|
|
+ for i:=1 to maxvarregs do
|
|
|
|
+ begin
|
|
|
|
+ if assigned(regvars[i]) then
|
|
|
|
+ Message3(cg_d_register_weight,reg2str(regvars[i]^.reg),
|
|
|
|
+ tostr(regvars[i]^.refs),regvars[i]^.name);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if assigned(aktprocsym) and
|
|
|
|
+ ((aktprocsym^.definition^.options and poinline)<>0) then
|
|
|
|
+ make_const_global:=true;
|
|
|
|
+ do_secondpass(p);
|
|
|
|
+
|
|
|
|
+ if assigned(procinfo.def) then
|
|
|
|
+ procinfo.def^.fpu_used:=p^.registersfpu;
|
|
|
|
+
|
|
|
|
+ { all registers can be used again }
|
|
|
|
+ tg.resetusableregisters;
|
|
|
|
+ end;
|
|
|
|
+ procinfo.aktproccode^.concatlist(exprasmlist);
|
|
|
|
+ make_const_global:=false;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+end.
|
|
|
|
+{
|
|
|
|
+ $Log$
|
|
|
|
+ Revision 1.1 1999-08-03 00:07:16 florian
|
|
|
|
+ * initial revision
|
|
|
|
+
|
|
|
|
+}
|