|
@@ -0,0 +1,1085 @@
|
|
|
+{
|
|
|
+ $Id$
|
|
|
+ Copyright (c) 1998-2000 by Florian Klaempfl
|
|
|
+
|
|
|
+ Helper routines for the i386 code generator
|
|
|
+
|
|
|
+ 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 n386util;
|
|
|
+
|
|
|
+{$i defines.inc}
|
|
|
+
|
|
|
+interface
|
|
|
+
|
|
|
+ uses
|
|
|
+ symtable,node;
|
|
|
+
|
|
|
+ function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ procedure restore(p : tnode;isint64 : boolean);
|
|
|
+ procedure pushsetelement(p : tnode);
|
|
|
+ procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
|
|
|
+ para_offset:longint;alignment : longint);
|
|
|
+
|
|
|
+ procedure maketojumpbool(p : tnode);
|
|
|
+ procedure emitoverflowcheck(p:tnode);
|
|
|
+ procedure emitrangecheck(p:tnode;todef:pdef);
|
|
|
+ procedure firstcomplex(p : tnode);
|
|
|
+
|
|
|
+implementation
|
|
|
+
|
|
|
+ uses
|
|
|
+ ncon;
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ Emit Push Functions
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
|
|
|
+ var
|
|
|
+ pushed : boolean;
|
|
|
+ {hregister : tregister; }
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ href : treference;
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ begin
|
|
|
+ if needed>usablereg32 then
|
|
|
+ begin
|
|
|
+ if (p.location.loc=LOC_REGISTER) then
|
|
|
+ begin
|
|
|
+ if isint64 then
|
|
|
+ begin
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ gettempofsizereference(href,8);
|
|
|
+ p.temp_offset:=href.offset;
|
|
|
+ href.offset:=href.offset+4;
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p.location.registerhigh,href)));
|
|
|
+ href.offset:=href.offset-4;
|
|
|
+{$else TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ ungetregister32(p.location.registerhigh);
|
|
|
+ end
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ gettempofsizereference(href,4);
|
|
|
+ p.temp_offset:=href.offset;
|
|
|
+ end
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ ;
|
|
|
+ pushed:=true;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p.location.register,href)));
|
|
|
+{$else TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ ungetregister32(p.location.register);
|
|
|
+ end
|
|
|
+ else if (p.location.loc in [LOC_MEM,LOC_REFERENCE]) and
|
|
|
+ ((p.location.reference.base<>R_NO) or
|
|
|
+ (p.location.reference.index<>R_NO)
|
|
|
+ ) then
|
|
|
+ begin
|
|
|
+ del_reference(p.location.reference);
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_LEA,S_L,newreference(p.location.reference),R_EDI);
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ gettempofsizereference(href,4);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
|
|
|
+ p.temp_offset:=href.offset;
|
|
|
+{$else TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ pushed:=true;
|
|
|
+ end
|
|
|
+ else pushed:=false;
|
|
|
+ end
|
|
|
+ else pushed:=false;
|
|
|
+ maybe_push:=pushed;
|
|
|
+ end;
|
|
|
+
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
|
|
|
+
|
|
|
+ var
|
|
|
+ pushed : boolean;
|
|
|
+ href : treference;
|
|
|
+
|
|
|
+ begin
|
|
|
+ if needed>usablereg32 then
|
|
|
+ begin
|
|
|
+ if (p^.location.loc=LOC_REGISTER) then
|
|
|
+ begin
|
|
|
+ if isint64(p^.resulttype) then
|
|
|
+ begin
|
|
|
+ gettempofsizereference(href,8);
|
|
|
+ p^.temp_offset:=href.offset;
|
|
|
+ href.offset:=href.offset+4;
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
|
|
|
+ href.offset:=href.offset-4;
|
|
|
+ ungetregister32(p^.location.registerhigh);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ gettempofsizereference(href,4);
|
|
|
+ p^.temp_offset:=href.offset;
|
|
|
+ end;
|
|
|
+ pushed:=true;
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
|
|
|
+ ungetregister32(p^.location.register);
|
|
|
+ end
|
|
|
+ else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
|
|
|
+ ((p^.location.reference.base<>R_NO) or
|
|
|
+ (p^.location.reference.index<>R_NO)
|
|
|
+ ) then
|
|
|
+ begin
|
|
|
+ del_reference(p^.location.reference);
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
|
|
|
+ R_EDI);
|
|
|
+ gettempofsizereference(href,4);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ p^.temp_offset:=href.offset;
|
|
|
+ pushed:=true;
|
|
|
+ end
|
|
|
+ else pushed:=false;
|
|
|
+ end
|
|
|
+ else pushed:=false;
|
|
|
+ maybe_push:=pushed;
|
|
|
+ end;
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+
|
|
|
+
|
|
|
+ procedure restore(p : tnode;isint64 : boolean);
|
|
|
+ var
|
|
|
+ hregister : tregister;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ href : treference;
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ begin
|
|
|
+ hregister:=getregister32;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ reset_reference(href);
|
|
|
+ href.base:=procinfo^.frame_pointer;
|
|
|
+ href.offset:=p.temp_offset;
|
|
|
+ emit_ref_reg(A_MOV,S_L,href,hregister);
|
|
|
+{$else TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
|
|
|
+ begin
|
|
|
+ p.location.register:=hregister;
|
|
|
+ if isint64 then
|
|
|
+ begin
|
|
|
+ p.location.registerhigh:=getregister32;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ href.offset:=p.temp_offset+4;
|
|
|
+ emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
|
|
|
+ { set correctly for release ! }
|
|
|
+ href.offset:=p.temp_offset;
|
|
|
+{$else TEMPS_NOT_PUSH}
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p.location.registerhigh)));
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ reset_reference(p.location.reference);
|
|
|
+ { any reasons why this was moved into the index register ? }
|
|
|
+ { normally usage of base register is much better (FK) }
|
|
|
+ p.location.reference.base:=hregister;
|
|
|
+ { Why is this done? We can never be sure about p.left
|
|
|
+ because otherwise secondload fails !!!
|
|
|
+ set_location(p.left^.location,p.location);}
|
|
|
+ end;
|
|
|
+{$ifdef TEMPS_NOT_PUSH}
|
|
|
+ ungetiftemp(href);
|
|
|
+{$endif TEMPS_NOT_PUSH}
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ procedure pushsetelement(p : tnode);
|
|
|
+ var
|
|
|
+ hr,hr16,hr32 : tregister;
|
|
|
+ begin
|
|
|
+ { copy the element on the stack, slightly complicated }
|
|
|
+ if p.nodetype=ordconstn then
|
|
|
+ begin
|
|
|
+ if target_os.stackalignment=4 then
|
|
|
+ exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,tordconstnode(p).value)))
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,tordconstnode(p).value)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ case p.location.loc of
|
|
|
+ LOC_REGISTER,
|
|
|
+ LOC_CREGISTER :
|
|
|
+ begin
|
|
|
+ hr:=p.location.register;
|
|
|
+ case hr of
|
|
|
+ R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
|
|
|
+ begin
|
|
|
+ hr16:=reg32toreg16(hr);
|
|
|
+ hr32:=hr;
|
|
|
+ end;
|
|
|
+ R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
|
|
|
+ begin
|
|
|
+ hr16:=hr;
|
|
|
+ hr32:=reg16toreg32(hr);
|
|
|
+ end;
|
|
|
+ R_AL,R_BL,R_CL,R_DL :
|
|
|
+ begin
|
|
|
+ hr16:=reg8toreg16(hr);
|
|
|
+ hr32:=reg8toreg32(hr);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ if target_os.stackalignment=4 then
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
|
|
|
+ ungetregister32(hr32);
|
|
|
+ end;
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { you can't push more bytes than the size of the element, }
|
|
|
+ { because this may cross a page boundary and you'll get a }
|
|
|
+ { sigsegv (JM) }
|
|
|
+ emit_push_mem_size(p.location.reference,1);
|
|
|
+ del_reference(p.location.reference);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
|
|
|
+ para_offset:longint;alignment : longint);
|
|
|
+ var
|
|
|
+ tempreference : treference;
|
|
|
+ r : preference;
|
|
|
+ opsize : topsize;
|
|
|
+ op : tasmop;
|
|
|
+ hreg : tregister;
|
|
|
+ size : longint;
|
|
|
+ hlabel : pasmlabel;
|
|
|
+ begin
|
|
|
+ case p.location.loc of
|
|
|
+ LOC_REGISTER,
|
|
|
+ LOC_CREGISTER:
|
|
|
+ begin
|
|
|
+ case p.location.register of
|
|
|
+ R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
|
|
|
+ R_EDI,R_ESP,R_EBP :
|
|
|
+ begin
|
|
|
+ if p.resulttype^.size=8 then
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,8);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
|
|
|
+ p.location.registerlow,r)));
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
|
|
|
+ p.location.registerhigh,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
|
|
|
+ ungetregister32(p.location.registerhigh);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerlow)));
|
|
|
+ ungetregister32(p.location.registerlow);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
|
|
|
+ p.location.register,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
|
|
|
+ ungetregister32(p.location.register);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
|
|
|
+ begin
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ hreg:=reg16toreg32(p.location.register);
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ hreg:=p.location.register;
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ end;
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
|
|
|
+ ungetregister32(reg16toreg32(p.location.register));
|
|
|
+ end;
|
|
|
+ R_AL,R_BL,R_CL,R_DL:
|
|
|
+ begin
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ hreg:=reg8toreg32(p.location.register);
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ hreg:=reg8toreg16(p.location.register);
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ end;
|
|
|
+ { we must push always 16 bit }
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
|
|
|
+ ungetregister32(reg8toreg32(p.location.register));
|
|
|
+ end;
|
|
|
+ else internalerror(1899);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ LOC_FPU:
|
|
|
+ begin
|
|
|
+ size:=align(pfloatdef(p.resulttype)^.size,alignment);
|
|
|
+ inc(pushedparasize,size);
|
|
|
+ if not inlined then
|
|
|
+ emit_const_reg(A_SUB,S_L,size,R_ESP);
|
|
|
+{$ifdef GDB}
|
|
|
+ if (cs_debuginfo in aktmoduleswitches) and
|
|
|
+ (exprasmlist^.first=exprasmlist^.last) then
|
|
|
+ exprasmlist^.concat(new(pai_force_line,init));
|
|
|
+{$endif GDB}
|
|
|
+ r:=new_reference(R_ESP,0);
|
|
|
+ floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
|
|
|
+ { this is the easiest case for inlined !! }
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r^.base:=procinfo^.framepointer;
|
|
|
+ r^.offset:=para_offset-pushedparasize;
|
|
|
+ end;
|
|
|
+ exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
|
|
|
+ dec(fpuvaroffset);
|
|
|
+ end;
|
|
|
+ LOC_CFPUREGISTER:
|
|
|
+ begin
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
|
|
|
+ correct_fpuregister(p.location.register,fpuvaroffset))));
|
|
|
+ size:=align(pfloatdef(p.resulttype)^.size,alignment);
|
|
|
+ inc(pushedparasize,size);
|
|
|
+ if not inlined then
|
|
|
+ emit_const_reg(A_SUB,S_L,size,R_ESP);
|
|
|
+{$ifdef GDB}
|
|
|
+ if (cs_debuginfo in aktmoduleswitches) and
|
|
|
+ (exprasmlist^.first=exprasmlist^.last) then
|
|
|
+ exprasmlist^.concat(new(pai_force_line,init));
|
|
|
+{$endif GDB}
|
|
|
+ r:=new_reference(R_ESP,0);
|
|
|
+ floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
|
|
|
+ { this is the easiest case for inlined !! }
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r^.base:=procinfo^.framepointer;
|
|
|
+ r^.offset:=para_offset-pushedparasize;
|
|
|
+ end;
|
|
|
+ exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
|
|
|
+ end;
|
|
|
+ LOC_REFERENCE,LOC_MEM:
|
|
|
+ begin
|
|
|
+ tempreference:=p.location.reference;
|
|
|
+ del_reference(p.location.reference);
|
|
|
+ case p.resulttype^.deftype of
|
|
|
+ enumdef,
|
|
|
+ orddef :
|
|
|
+ begin
|
|
|
+ case p.resulttype^.size of
|
|
|
+ 8 : begin
|
|
|
+ inc(pushedparasize,8);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ inc(tempreference.offset,4);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ inc(tempreference.offset,4);
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ dec(tempreference.offset,4);
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ 4 : begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end;
|
|
|
+ 1,2 : begin
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ hreg:=R_EDI;
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ hreg:=R_DI;
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ end;
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,opsize,
|
|
|
+ newreference(tempreference),hreg);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem_size(tempreference,p.resulttype^.size);
|
|
|
+ end;
|
|
|
+ else
|
|
|
+ internalerror(234231);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ floatdef :
|
|
|
+ begin
|
|
|
+ case pfloatdef(p.resulttype)^.typ of
|
|
|
+ f32bit,
|
|
|
+ s32real :
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end;
|
|
|
+ s64real,
|
|
|
+ s64comp :
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ inc(tempreference.offset,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ dec(tempreference.offset,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end;
|
|
|
+ s80real :
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if alignment=4 then
|
|
|
+ inc(tempreference.offset,8)
|
|
|
+ else
|
|
|
+ inc(tempreference.offset,6);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ dec(tempreference.offset,4);
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ hreg:=R_EDI;
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ dec(tempreference.offset,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ hreg:=R_DI;
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ dec(tempreference.offset,2);
|
|
|
+ end;
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,opsize,
|
|
|
+ newreference(tempreference),hreg);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
|
|
|
+ newreference(tempreference))));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ pointerdef,
|
|
|
+ procvardef,
|
|
|
+ classrefdef:
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(A_MOV,S_L,
|
|
|
+ newreference(tempreference),R_EDI);
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end;
|
|
|
+ arraydef,
|
|
|
+ recorddef,
|
|
|
+ stringdef,
|
|
|
+ setdef,
|
|
|
+ objectdef :
|
|
|
+ begin
|
|
|
+ { even some structured types are 32 bit }
|
|
|
+ if is_widestring(p.resulttype) or
|
|
|
+ is_ansistring(p.resulttype) or
|
|
|
+ is_smallset(p.resulttype) or
|
|
|
+ ((p.resulttype^.deftype in [recorddef,arraydef]) and
|
|
|
+ (
|
|
|
+ (p.resulttype^.deftype<>arraydef) or not
|
|
|
+ (parraydef(p.resulttype)^.IsConstructor or
|
|
|
+ parraydef(p.resulttype)^.isArrayOfConst or
|
|
|
+ is_open_array(p.resulttype))
|
|
|
+ ) and
|
|
|
+ (p.resulttype^.size<=4)
|
|
|
+ ) or
|
|
|
+ ((p.resulttype^.deftype=objectdef) and
|
|
|
+ pobjectdef(p.resulttype)^.is_class) then
|
|
|
+ begin
|
|
|
+ if (p.resulttype^.size>2) or
|
|
|
+ ((alignment=4) and (p.resulttype^.size>0)) then
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ concatcopy(tempreference,r^,4,false,false);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ emit_push_mem(tempreference);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ if p.resulttype^.size>0 then
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ concatcopy(tempreference,r^,2,false,false);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ { call by value open array ? }
|
|
|
+ else if is_cdecl then
|
|
|
+ begin
|
|
|
+ { push on stack }
|
|
|
+ size:=align(p.resulttype^.size,alignment);
|
|
|
+ inc(pushedparasize,size);
|
|
|
+ emit_const_reg(A_SUB,S_L,size,R_ESP);
|
|
|
+ r:=new_reference(R_ESP,0);
|
|
|
+ concatcopy(tempreference,r^,size,false,false);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ internalerror(8954);
|
|
|
+ end;
|
|
|
+ else
|
|
|
+ CGMessage(cg_e_illegal_expression);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ LOC_JUMP:
|
|
|
+ begin
|
|
|
+ getlabel(hlabel);
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ end;
|
|
|
+ emitlab(truelabel);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ emit_const_ref(A_MOV,opsize,1,r);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
|
|
|
+ emitjmp(C_None,hlabel);
|
|
|
+ emitlab(falselabel);
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ emit_const_ref(A_MOV,opsize,0,r);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
|
|
|
+ emitlab(hlabel);
|
|
|
+ end;
|
|
|
+ LOC_FLAGS:
|
|
|
+ begin
|
|
|
+ if not(R_EAX in unused) then
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
|
|
|
+ end;
|
|
|
+ emit_flag2reg(p.location.resflags,R_AL);
|
|
|
+ emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
|
|
|
+ if alignment=4 then
|
|
|
+ begin
|
|
|
+ opsize:=S_L;
|
|
|
+ hreg:=R_EAX;
|
|
|
+ inc(pushedparasize,4);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=S_W;
|
|
|
+ hreg:=R_AX;
|
|
|
+ inc(pushedparasize,2);
|
|
|
+ end;
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
|
|
|
+ if not(R_EAX in unused) then
|
|
|
+ begin
|
|
|
+ emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+{$ifdef SUPPORT_MMX}
|
|
|
+ LOC_MMXREGISTER,
|
|
|
+ LOC_CMMXREGISTER:
|
|
|
+ begin
|
|
|
+ inc(pushedparasize,8); { was missing !!! (PM) }
|
|
|
+ emit_const_reg(
|
|
|
+ A_SUB,S_L,8,R_ESP);
|
|
|
+{$ifdef GDB}
|
|
|
+ if (cs_debuginfo in aktmoduleswitches) and
|
|
|
+ (exprasmlist^.first=exprasmlist^.last) then
|
|
|
+ exprasmlist^.concat(new(pai_force_line,init));
|
|
|
+{$endif GDB}
|
|
|
+ if inlined then
|
|
|
+ begin
|
|
|
+ r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
|
|
|
+ p.location.register,r)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ r:=new_reference(R_ESP,0);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(
|
|
|
+ A_MOVQ,S_NO,p.location.register,r)));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+{$endif SUPPORT_MMX}
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ Emit Functions
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure maketojumpbool(p : tnode);
|
|
|
+ {
|
|
|
+ produces jumps to true respectively false labels using boolean expressions
|
|
|
+ }
|
|
|
+ var
|
|
|
+ opsize : topsize;
|
|
|
+ storepos : tfileposinfo;
|
|
|
+ begin
|
|
|
+ if p.error then
|
|
|
+ exit;
|
|
|
+ storepos:=aktfilepos;
|
|
|
+ aktfilepos:=p.fileinfo;
|
|
|
+ if is_boolean(p.resulttype) then
|
|
|
+ begin
|
|
|
+ if is_constboolnode(p) then
|
|
|
+ begin
|
|
|
+ if p.value<>0 then
|
|
|
+ emitjmp(C_None,truelabel)
|
|
|
+ else
|
|
|
+ emitjmp(C_None,falselabel);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ opsize:=def_opsize(p.resulttype);
|
|
|
+ case p.location.loc of
|
|
|
+ LOC_CREGISTER,LOC_REGISTER : begin
|
|
|
+ emit_reg_reg(A_OR,opsize,p.location.register,
|
|
|
+ p.location.register);
|
|
|
+ ungetregister(p.location.register);
|
|
|
+ emitjmp(C_NZ,truelabel);
|
|
|
+ emitjmp(C_None,falselabel);
|
|
|
+ end;
|
|
|
+ LOC_MEM,LOC_REFERENCE : begin
|
|
|
+ emit_const_ref(
|
|
|
+ A_CMP,opsize,0,newreference(p.location.reference));
|
|
|
+ del_reference(p.location.reference);
|
|
|
+ emitjmp(C_NZ,truelabel);
|
|
|
+ emitjmp(C_None,falselabel);
|
|
|
+ end;
|
|
|
+ LOC_FLAGS : begin
|
|
|
+ emitjmp(flag_2_cond[p.location.resflags],truelabel);
|
|
|
+ emitjmp(C_None,falselabel);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ CGMessage(type_e_mismatch);
|
|
|
+ aktfilepos:=storepos;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ { produces if necessary overflowcode }
|
|
|
+ procedure emitoverflowcheck(p:tnode);
|
|
|
+ var
|
|
|
+ hl : pasmlabel;
|
|
|
+ begin
|
|
|
+ if not(cs_check_overflow in aktlocalswitches) then
|
|
|
+ exit;
|
|
|
+ getlabel(hl);
|
|
|
+ if not ((p.resulttype^.deftype=pointerdef) or
|
|
|
+ ((p.resulttype^.deftype=orddef) and
|
|
|
+ (porddef(p.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
|
|
|
+ bool8bit,bool16bit,bool32bit]))) then
|
|
|
+ emitjmp(C_NO,hl)
|
|
|
+ else
|
|
|
+ emitjmp(C_NB,hl);
|
|
|
+ emitcall('FPC_OVERFLOW');
|
|
|
+ emitlab(hl);
|
|
|
+ end;
|
|
|
+
|
|
|
+ { produces range check code, while one of the operands is a 64 bit
|
|
|
+ integer }
|
|
|
+ procedure emitrangecheck64(p : tnode;todef : pdef);
|
|
|
+
|
|
|
+ begin
|
|
|
+
|
|
|
+ CGMessage(cg_w_64bit_range_check_not_supported);
|
|
|
+ {internalerror(28699);}
|
|
|
+ end;
|
|
|
+
|
|
|
+ { produces if necessary rangecheckcode }
|
|
|
+ procedure emitrangecheck(p:tnode;todef:pdef);
|
|
|
+ {
|
|
|
+ generate range checking code for the value at location t. The
|
|
|
+ type used is the checked against todefs ranges. fromdef (p.resulttype)
|
|
|
+ is the original type used at that location, when both defs are
|
|
|
+ equal the check is also insert (needed for succ,pref,inc,dec)
|
|
|
+ }
|
|
|
+ var
|
|
|
+ neglabel,
|
|
|
+ poslabel : pasmlabel;
|
|
|
+ href : treference;
|
|
|
+ rstr : string;
|
|
|
+ hreg : tregister;
|
|
|
+ opsize : topsize;
|
|
|
+ op : tasmop;
|
|
|
+ fromdef : pdef;
|
|
|
+ lto,hto,
|
|
|
+ lfrom,hfrom : longint;
|
|
|
+ doublebound,
|
|
|
+ is_reg,
|
|
|
+ popecx : boolean;
|
|
|
+ begin
|
|
|
+ { range checking on and range checkable value? }
|
|
|
+ if not(cs_check_range in aktlocalswitches) or
|
|
|
+ not(todef^.deftype in [orddef,enumdef,arraydef]) then
|
|
|
+ exit;
|
|
|
+ { only check when assigning to scalar, subranges are different,
|
|
|
+ when todef=fromdef then the check is always generated }
|
|
|
+ fromdef:=p.resulttype;
|
|
|
+ if is_64bitint(fromdef) or is_64bitint(todef) then
|
|
|
+ begin
|
|
|
+ emitrangecheck64(p,todef);
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ {we also need lto and hto when checking if we need to use doublebound!
|
|
|
+ (JM)}
|
|
|
+ getrange(todef,lto,hto);
|
|
|
+ if todef<>fromdef then
|
|
|
+ begin
|
|
|
+ getrange(p.resulttype,lfrom,hfrom);
|
|
|
+ { first check for not being u32bit, then if the to is bigger than
|
|
|
+ from }
|
|
|
+ if (lto<hto) and (lfrom<hfrom) and
|
|
|
+ (lto<=lfrom) and (hto>=hfrom) then
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ { generate the rangecheck code for the def where we are going to
|
|
|
+ store the result }
|
|
|
+ doublebound:=false;
|
|
|
+ case todef^.deftype of
|
|
|
+ orddef :
|
|
|
+ begin
|
|
|
+ porddef(todef)^.genrangecheck;
|
|
|
+ rstr:=porddef(todef)^.getrangecheckstring;
|
|
|
+ doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
|
|
|
+ end;
|
|
|
+ enumdef :
|
|
|
+ begin
|
|
|
+ penumdef(todef)^.genrangecheck;
|
|
|
+ rstr:=penumdef(todef)^.getrangecheckstring;
|
|
|
+ end;
|
|
|
+ arraydef :
|
|
|
+ begin
|
|
|
+ parraydef(todef)^.genrangecheck;
|
|
|
+ rstr:=parraydef(todef)^.getrangecheckstring;
|
|
|
+ doublebound:=(lto>hto);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ { get op and opsize }
|
|
|
+ opsize:=def2def_opsize(fromdef,u32bitdef);
|
|
|
+ if opsize in [S_B,S_W,S_L] then
|
|
|
+ op:=A_MOV
|
|
|
+ else
|
|
|
+ if is_signed(fromdef) then
|
|
|
+ op:=A_MOVSX
|
|
|
+ else
|
|
|
+ op:=A_MOVZX;
|
|
|
+ is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
|
|
|
+ if is_reg then
|
|
|
+ hreg:=p.location.register;
|
|
|
+ if not target_os.use_bound_instruction then
|
|
|
+ begin
|
|
|
+ { FPC_BOUNDCHECK needs to be called with
|
|
|
+ %ecx - value
|
|
|
+ %edi - pointer to the ranges }
|
|
|
+ popecx:=false;
|
|
|
+ if not(is_reg) or
|
|
|
+ (p.location.register<>R_ECX) then
|
|
|
+ begin
|
|
|
+ if not(R_ECX in unused) then
|
|
|
+ begin
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
|
|
|
+ popecx:=true;
|
|
|
+ end
|
|
|
+ else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
|
|
|
+ if is_reg then
|
|
|
+ emit_reg_reg(op,opsize,p.location.register,R_ECX)
|
|
|
+ else
|
|
|
+ emit_ref_reg(op,opsize,newreference(p.location.reference),R_ECX);
|
|
|
+ end;
|
|
|
+ if doublebound then
|
|
|
+ begin
|
|
|
+ getlabel(neglabel);
|
|
|
+ getlabel(poslabel);
|
|
|
+ emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
|
|
|
+ emitjmp(C_L,neglabel);
|
|
|
+ end;
|
|
|
+ { insert bound instruction only }
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
|
|
|
+ emitcall('FPC_BOUNDCHECK');
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ { u32bit needs 2 checks }
|
|
|
+ if doublebound then
|
|
|
+ begin
|
|
|
+ emitjmp(C_None,poslabel);
|
|
|
+ emitlab(neglabel);
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
|
|
|
+ emitcall('FPC_BOUNDCHECK');
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ emitlab(poslabel);
|
|
|
+ end;
|
|
|
+ if popecx then
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
|
|
|
+ else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ reset_reference(href);
|
|
|
+ href.symbol:=newasmsymbol(rstr);
|
|
|
+ { load the value in a register }
|
|
|
+ if is_reg then
|
|
|
+ begin
|
|
|
+ { be sure that hreg is a 32 bit reg, if not load it in %edi }
|
|
|
+ if p.location.register in [R_EAX..R_EDI] then
|
|
|
+ hreg:=p.location.register
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_reg_reg(op,opsize,p.location.register,R_EDI);
|
|
|
+ hreg:=R_EDI;
|
|
|
+ end;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ getexplicitregister32(R_EDI);
|
|
|
+ emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
|
|
|
+ hreg:=R_EDI;
|
|
|
+ end;
|
|
|
+ if doublebound then
|
|
|
+ begin
|
|
|
+ getlabel(neglabel);
|
|
|
+ getlabel(poslabel);
|
|
|
+ emit_reg_reg(A_TEST,S_L,hreg,hreg);
|
|
|
+ emitjmp(C_L,neglabel);
|
|
|
+ end;
|
|
|
+ { insert bound instruction only }
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
|
|
|
+ { u32bit needs 2 checks }
|
|
|
+ if doublebound then
|
|
|
+ begin
|
|
|
+ href.offset:=8;
|
|
|
+ emitjmp(C_None,poslabel);
|
|
|
+ emitlab(neglabel);
|
|
|
+ exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
|
|
|
+ emitlab(poslabel);
|
|
|
+ end;
|
|
|
+ if hreg = R_EDI then
|
|
|
+ ungetregister32(R_EDI);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ { DO NOT RELY on the fact that the tnode is not yet swaped
|
|
|
+ because of inlining code PM }
|
|
|
+ procedure firstcomplex(p : tnode);
|
|
|
+ var
|
|
|
+ hp : tnode;
|
|
|
+ begin
|
|
|
+ { always calculate boolean AND and OR from left to right }
|
|
|
+ if (p.treetype in [orn,andn]) and
|
|
|
+ (p.left^.resulttype^.deftype=orddef) and
|
|
|
+ (porddef(p.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
|
|
|
+ begin
|
|
|
+ { p.swaped:=false}
|
|
|
+ if p.swaped then
|
|
|
+ internalerror(234234);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ if (p.left^.registers32<p.right^.registers32) and
|
|
|
+ { 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 }
|
|
|
+ (p.right^.registers32<=4) then
|
|
|
+ begin
|
|
|
+ hp:=p.left;
|
|
|
+ p.left:=p.right;
|
|
|
+ p.right:=hp;
|
|
|
+ p.swaped:=not p.swaped;
|
|
|
+ end;
|
|
|
+ {else
|
|
|
+ p.swaped:=false; do not modify }
|
|
|
+ end;
|
|
|
+{$endif}
|
|
|
+
|
|
|
+end.
|
|
|
+{
|
|
|
+ $Log$
|
|
|
+ Revision 1.1 2000-10-01 19:58:40 peter
|
|
|
+ * new file
|
|
|
+
|
|
|
+}
|