{ $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 symtype,node; function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean; function maybe_pushfpu(needed : byte;p : tnode) : 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); {$ifdef TEMPS_NOT_PUSH} procedure restorefromtemp(p : tnode;isint64 : boolean); {$endif TEMPS_NOT_PUSH} procedure pushsetelement(p : tnode); procedure push_value_para(p:tnode;inlined,is_cdecl:boolean; para_offset:longint;alignment : longint); procedure loadshortstring(source,dest : tnode); procedure loadlongstring(p:tbinarynode); procedure loadansi2short(source,dest : tnode); procedure loadwide2short(source,dest : tnode); procedure loadinterfacecom(p: tbinarynode); procedure emitoverflowcheck(p:tnode); procedure firstcomplex(p : tbinarynode); implementation uses globtype,globals,systems,verbose, cutils, aasm,cpubase,cpuasm,cpuinfo, symconst,symbase,symdef,symsym,symtable, {$ifdef GDB} gdb, {$endif GDB} types, ncon,nld, pass_1,pass_2, cgbase,tgcpu,temp_gen, cga,regvars; {***************************************************************************** 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 p.location.loc = LOC_CREGISTER then begin maybe_push := true; exit; end; 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(Taicpu.Op_reg(A_MOV,S_L,p.location.registerhigh,href)); href.offset:=href.offset-4; {$else TEMPS_NOT_PUSH} exprasmList.concat(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,S_L,p.location.register,href)); {$else TEMPS_NOT_PUSH} exprasmList.concat(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href)); p.temp_offset:=href.offset; {$else TEMPS_NOT_PUSH} exprasmList.concat(Taicpu.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; function maybe_pushfpu(needed : byte;p : tnode) : boolean; begin if needed>=maxfpuregs then begin if p.location.loc = LOC_FPU then begin emit_to_mem(p.location,p.resulttype.def); maybe_pushfpu:=true; end else maybe_pushfpu:=false; end else maybe_pushfpu:=false; 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.def) then begin gettempofsizereference(href,8); p^.temp_offset:=href.offset; href.offset:=href.offset+4; exprasmList.concat(Taicpu.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(Taicpu.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(Taicpu.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 if p.location.loc = LOC_CREGISTER then begin load_regvar_reg(exprasmlist,p.location.register); exit; end; hregister:=getregisterint; {$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(Taicpu.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:=getregisterint; {$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(Taicpu.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; {$ifdef TEMPS_NOT_PUSH} procedure restorefromtemp(p : tnode;isint64 : boolean); var hregister : tregister; href : treference; begin hregister:=getregisterint; reset_reference(href); href.base:=procinfo^.frame_pointer; href.offset:=p.temp_offset; emit_ref_reg(A_MOV,S_L,href,hregister); if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then begin p.location.register:=hregister; if isint64 then begin p.location.registerhigh:=getregisterint; 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; end; end else begin reset_reference(p.location.reference); p.location.reference.base:=hregister; { Why is this done? We can never be sure about p^.left because otherwise secondload fails PM set_location(p^.left^.location,p^.location);} end; ungetiftemp(href); end; {$endif TEMPS_NOT_PUSH} 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 aktalignment.paraalign=4 then exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tordconstnode(p).value)) else exprasmList.concat(Taicpu.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 aktalignment.paraalign=4 then exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,hr32)) else exprasmList.concat(Taicpu.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 : tasmlabel; begin case p.location.loc of LOC_REGISTER, LOC_CREGISTER: begin if p.resulttype.def.size=8 then begin inc(pushedparasize,8); if inlined then begin r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize); exprasmlist.concat(taicpu.op_reg_ref(A_MOV,S_L,p.location.registerlow,r)); r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4); exprasmlist.concat(taicpu.op_reg_ref(A_MOV,S_L,p.location.registerhigh,r)); end else begin exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerhigh)); exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerlow)); end; ungetregister32(p.location.registerhigh); ungetregister32(p.location.registerlow); end else case p.location.register of R_EAX,R_EBX,R_ECX,R_EDX,R_ESI, R_EDI,R_ESP,R_EBP : begin inc(pushedparasize,4); if inlined then begin r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p.location.register,r)); end else exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.register)); ungetregister32(p.location.register); 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(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); end else exprasmList.concat(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); end else exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg)); ungetregister32(reg8toreg32(p.location.register)); end; else internalerror(1899); end; end; LOC_FPU: begin size:=align(tfloatdef(p.resulttype.def).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(Tai_force_line.Create); {$endif GDB} r:=new_reference(R_ESP,0); floatstoreops(tfloatdef(p.resulttype.def).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(Taicpu.Op_ref(op,opsize,r)); dec(fpuvaroffset); end; LOC_CFPUREGISTER: begin exprasmList.concat(Taicpu.Op_reg(A_FLD,S_NO, correct_fpuregister(p.location.register,fpuvaroffset))); size:=align(tfloatdef(p.resulttype.def).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(Tai_force_line.Create); {$endif GDB} r:=new_reference(R_ESP,0); floatstoreops(tfloatdef(p.resulttype.def).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(Taicpu.Op_ref(op,opsize,r)); end; LOC_REFERENCE,LOC_MEM: begin tempreference:=p.location.reference; del_reference(p.location.reference); case p.resulttype.def.deftype of enumdef, orddef : begin case p.resulttype.def.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(Taicpu.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(Taicpu.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(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); ungetregister32(R_EDI); end else emit_push_mem_size(tempreference,p.resulttype.def.size); end; else internalerror(234231); end; end; floatdef : begin case tfloatdef(p.resulttype.def).typ of 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(Taicpu.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(Taicpu.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(Taicpu.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(Taicpu.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(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); ungetregister32(R_EDI); end else exprasmList.concat(Taicpu.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(Taicpu.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.def) or is_ansistring(p.resulttype.def) or is_smallset(p.resulttype.def) or ((p.resulttype.def.deftype in [recorddef,arraydef]) and ( (p.resulttype.def.deftype<>arraydef) or not (tarraydef(p.resulttype.def).IsConstructor or tarraydef(p.resulttype.def).isArrayOfConst or is_open_array(p.resulttype.def)) ) and (p.resulttype.def.size<=4) ) or is_class(p.resulttype.def) or is_interface(p.resulttype.def) then begin if (p.resulttype.def.size>2) or ((alignment=4) and (p.resulttype.def.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.def.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(Taicpu.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.def.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); dispose(r); 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(Taicpu.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(Taicpu.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(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); end else exprasmList.concat(Taicpu.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(Tai_force_line.Create); {$endif GDB} if inlined then begin r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO, p.location.register,r)); end else begin r:=new_reference(R_ESP,0); exprasmList.concat(Taicpu.Op_reg_ref( A_MOVQ,S_NO,p.location.register,r)); end; end; {$endif SUPPORT_MMX} end; end; {***************************************************************************** Emit Functions *****************************************************************************} { produces if necessary overflowcode } procedure emitoverflowcheck(p:tnode); var hl : tasmlabel; begin if not(cs_check_overflow in aktlocalswitches) then exit; getlabel(hl); if not ((p.resulttype.def.deftype=pointerdef) or ((p.resulttype.def.deftype=orddef) and (torddef(p.resulttype.def).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; { DO NOT RELY on the fact that the tnode is not yet swaped because of inlining code PM } procedure firstcomplex(p : tbinarynode); var hp : tnode; begin { always calculate boolean AND and OR from left to right } if (p.nodetype in [orn,andn]) and (p.left.resulttype.def.deftype=orddef) and (torddef(p.left.resulttype.def).typ in [bool8bit,bool16bit,bool32bit]) then begin { p.swaped:=false} if nf_swaped in p.flags then internalerror(234234); end else if (((p.location.loc=LOC_FPU) and (p.right.registersfpu > p.left.registersfpu)) or ((((p.left.registersfpu = 0) and (p.right.registersfpu = 0)) or (p.location.loc<>LOC_FPU)) and (p.left.registers32