{ $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,cpubase,cginfo; 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,cpuasm, symconst,symdef,symsym,symtable, {$ifdef GDB} gdb, {$endif GDB} types, ncgutil,ncon,nld, pass_1,pass_2, cgbase,tgobj, cga,regvars,cgobj,cg64f32,rgobj,rgcpu,cgcpu; {***************************************************************************** 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>rg.countunusedregsint then begin if (p.location.loc=LOC_REGISTER) then begin if isint64 then begin {$ifdef TEMPS_NOT_PUSH} tg.gettempofsizereference(exprasmlist,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} rg.ungetregisterint(exprasmlist,p.location.registerhigh); end {$ifdef TEMPS_NOT_PUSH} else begin tg.gettempofsizereference(exprasmlist,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} rg.ungetregisterint(exprasmlist,p.location.register); end else if (p.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) and ((p.location.reference.base<>R_NO) or (p.location.reference.index<>R_NO) ) then begin reference_release(exprasmlist,p.location.reference); rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_LEA,S_L,p.location.reference,R_EDI); {$ifdef TEMPS_NOT_PUSH} tg.gettempofsizereference(exprasmlist,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} rg.ungetregisterint(exprasmlist,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_FPUREGISTER then begin location_force_mem(p.location); 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>rg.unusedregsint then begin if (p^.location.loc=LOC_REGISTER) then begin if isint64(p^.resulttype.def) then begin tg.gettempofsizereference(exprasmlist,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; rg.ungetregisterint(exprasmlist,p^.location.registerhigh); end else begin tg.gettempofsizereference(exprasmlist,href,4); p^.temp_offset:=href.offset; end; pushed:=true; exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p^.location.register,href)); rg.ungetregisterint(exprasmlist,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 reference_release(p^.location.reference); rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_LEA,S_L,reference_copy(p^.location.reference), R_EDI); tg.gettempofsizereference(exprasmlist,href,4); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href)); rg.ungetregisterint(exprasmlist,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:=rg.getregisterint(exprasmlist); {$ifdef TEMPS_NOT_PUSH} reset_reference(href); href.base:=procinfo^.frame_pointer_reg; 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:=rg.getregisterint(exprasmlist); {$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 reference_reset(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} tg.ungetiftemp(exprasmlist,href); {$endif TEMPS_NOT_PUSH} end; {$ifdef TEMPS_NOT_PUSH} procedure restorefromtemp(p : tnode;isint64 : boolean); var hregister : tregister; href : treference; begin hregister:=rg.getregisterint(exprasmlist); reset_reference(href); href.base:=procinfo^.frame_pointer_reg; 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:=rg.getregisterint(exprasmlist); 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; tg.ungetiftemp(exprasmlist,href); end; {$endif TEMPS_NOT_PUSH} procedure pushsetelement(p : tnode); 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 if aktalignment.paraalign=4 then exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,rg.makeregsize(p.location.register,OS_16))) else exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,rg.makeregsize(p.location.register,OS_32))); rg.ungetregisterint(exprasmlist,p.location.register); 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); reference_release(exprasmlist,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 : treference; opsize : topsize; hreg : tregister; size : longint; hlabel : tasmlabel; cgsize : tcgsize; begin case p.location.loc of LOC_REGISTER, LOC_CREGISTER: begin cgsize:=def_cgsize(p.resulttype.def); if cgsize in [OS_64,OS_S64] then begin inc(pushedparasize,8); if inlined then begin reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); tcg64f32(cg).a_load64_loc_ref(exprasmlist,p.location,r); end else tcg64f32(cg).a_param64_loc(exprasmlist,p.location,-1); end else begin { save old register } hreg:=p.location.register; { update register to use to match alignment } case cgsize of OS_8,OS_S8 : begin if alignment=4 then cgsize:=OS_32 else cgsize:=OS_16; end; OS_16,OS_S16 : begin if alignment=4 then cgsize:=OS_32; end; end; p.location.register:=rg.makeregsize(p.location.register,cgsize); inc(pushedparasize,alignment); if inlined then begin reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); cg.a_load_loc_ref(exprasmlist,p.location,r); end else cg.a_param_loc(exprasmlist,p.location,-1); { restore old register } p.location.register:=hreg; end; location_release(exprasmlist,p.location); end; LOC_CONSTANT : begin cgsize:=def_cgsize(p.resulttype.def); if cgsize in [OS_64,OS_S64] then begin inc(pushedparasize,8); if inlined then begin reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); tcg64f32(cg).a_load64_loc_ref(exprasmlist,p.location,r); end else tcg64f32(cg).a_param64_loc(exprasmlist,p.location,-1); end else begin case cgsize of OS_8,OS_S8 : begin if alignment=4 then cgsize:=OS_32 else cgsize:=OS_16 end; OS_16,OS_S16 : begin if alignment=4 then cgsize:=OS_32; end; end; inc(pushedparasize,alignment); if inlined then begin reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); cg.a_load_loc_ref(exprasmlist,p.location,r); end else cg.a_param_loc(exprasmlist,p.location,-1); end; location_release(exprasmlist,p.location); end; LOC_FPUREGISTER, LOC_CFPUREGISTER: 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} { this is the easiest case for inlined !! } if inlined then reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize) else reference_reset_base(r,R_ESP,0); cg.a_loadfpu_reg_ref(exprasmlist, def_cgsize(p.resulttype.def),p.location.register,r); end; LOC_REFERENCE,LOC_CREFERENCE: begin tempreference:=p.location.reference; reference_release(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); inc(tempreference.offset,4); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize+4); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,opsize,tempreference,hreg); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); rg.ungetregisterint(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,R_EDI); end else emit_push_mem(tempreference); end; s64real, s64comp : begin inc(pushedparasize,4); inc(tempreference.offset,4); if inlined then begin rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,R_EDI); end else emit_push_mem(tempreference); inc(pushedparasize,4); dec(tempreference.offset,4); if inlined then begin rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,R_EDI); end else emit_push_mem(tempreference); dec(tempreference.offset,4); inc(pushedparasize,4); if inlined then begin rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,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 rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,opsize,tempreference,hreg); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r)); rg.ungetregisterint(exprasmlist,R_EDI); end else exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,tempreference)); end; end; end; pointerdef, procvardef, classrefdef: begin inc(pushedparasize,4); if inlined then begin rg.getexplicitregisterint(exprasmlist,R_EDI); emit_ref_reg(A_MOV,S_L,tempreference,R_EDI); reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r)); rg.ungetregisterint(exprasmlist,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 reference_reset_base(r,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 reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); concatcopy(tempreference,r,2,false,false); end else exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_W,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); reference_reset_base(r,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 reference_reset_base(r,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 reference_reset_base(r,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 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 not(R_EAX in rg.unusedregsint) then begin rg.getexplicitregisterint(exprasmlist,R_EDI); emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI); end; cg.g_flags2reg(exprasmlist,p.location.resflags,hreg); if inlined then begin reference_reset_base(r,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 rg.unusedregsint) then begin emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX); rg.ungetregisterint(exprasmlist,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 reference_reset_base(r,procinfo^.framepointer,para_offset-pushedparasize); exprasmList.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO, p.location.register,r)); end else begin reference_reset_base(r,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_FPUREGISTER) and (p.right.registersfpu > p.left.registersfpu)) or ((((p.left.registersfpu = 0) and (p.right.registersfpu = 0)) or (p.location.loc<>LOC_FPUREGISTER)) and (p.left.registers32