{ $Id$ Copyright (c) 1998-2000 by Florian Klaempfl Generate i386 assembler for math nodes 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 n386mat; {$i defines.inc} interface uses node,nmat; type ti386moddivnode = class(tmoddivnode) procedure pass_2;override; end; ti386shlshrnode = class(tshlshrnode) procedure pass_2;override; end; ti386unaryminusnode = class(tunaryminusnode) function pass_1 : tnode;override; procedure pass_2;override; end; ti386notnode = class(tnotnode) procedure pass_2;override; end; implementation uses globtype,systems, cutils,verbose,globals, symconst,symdef,aasm,types, cgbase,temp_gen,pass_1,pass_2, ncon, cpubase, cga,tgcpu,n386util,ncgutil; {***************************************************************************** TI386MODDIVNODE *****************************************************************************} procedure ti386moddivnode.pass_2; var unusedregisters : tregisterset; usablecount, regstopush : byte; hreg1 : tregister; hreg2 : tregister; shrdiv, pushed,popeax,popedx : boolean; power : longint; hl : tasmlabel; hloc : tlocation; pushedreg : tpushed; typename,opname : string[6]; begin shrdiv := false; secondpass(left); pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype.def)); secondpass(right); if pushed then restore(left,is_64bitint(left.resulttype.def)); set_location(location,left.location); if is_64bitint(resulttype.def) then begin { should be handled in pass_1 (JM) } internalerror(200109052); end else begin { put numerator in register } if left.location.loc<>LOC_REGISTER then begin if left.location.loc=LOC_CREGISTER then begin hreg1:=getregisterint; emit_reg_reg(A_MOV,S_L,left.location.register,hreg1); end else begin del_reference(left.location.reference); hreg1:=getregisterint; emit_ref_reg(A_MOV,S_L,newreference(left.location.reference), hreg1); end; clear_location(left.location); left.location.loc:=LOC_REGISTER; left.location.register:=hreg1; end else hreg1:=left.location.register; if (nodetype=divn) and (right.nodetype=ordconstn) and ispowerof2(tordconstnode(right).value,power) then Begin shrdiv := true; {for signed numbers, the numerator must be adjusted before the shift instruction, but not wih unsigned numbers! Otherwise, "Cardinal($ffffffff) div 16" overflows! (JM)} If is_signed(left.resulttype.def) Then Begin If (aktOptProcessor <> class386) and not(CS_LittleSize in aktglobalswitches) then { use a sequence without jumps, saw this in comp.compilers (JM) } begin { no jumps, but more operations } if (hreg1 = R_EAX) and (R_EDX in unused) then begin hreg2 := getexplicitregister32(R_EDX); emit_none(A_CDQ,S_NO); end else begin getexplicitregister32(R_EDI); hreg2 := R_EDI; emit_reg_reg(A_MOV,S_L,hreg1,R_EDI); { if the left value is signed, R_EDI := $ffffffff, otherwise 0 } emit_const_reg(A_SAR,S_L,31,R_EDI); { if signed, R_EDI := right value-1, otherwise 0 } end; emit_const_reg(A_AND,S_L,tordconstnode(right).value-1,hreg2); { add to the left value } emit_reg_reg(A_ADD,S_L,hreg2,hreg1); { release EDX if we used it } { also releas EDI } ungetregister32(hreg2); { do the shift } emit_const_reg(A_SAR,S_L,power,hreg1); end else begin { a jump, but less operations } emit_reg_reg(A_TEST,S_L,hreg1,hreg1); getlabel(hl); emitjmp(C_NS,hl); if power=1 then emit_reg(A_INC,S_L,hreg1) else emit_const_reg(A_ADD,S_L,tordconstnode(right).value-1,hreg1); emitlab(hl); emit_const_reg(A_SAR,S_L,power,hreg1); end End Else emit_const_reg(A_SHR,S_L,power,hreg1); End else begin { bring denominator to EDI } { EDI is always free, it's } { only used for temporary } { purposes } getexplicitregister32(R_EDI); if (right.location.loc<>LOC_REGISTER) and (right.location.loc<>LOC_CREGISTER) then begin del_reference(right.location.reference); left.location.loc:=LOC_REGISTER; emit_ref_reg(A_MOV,S_L,newreference(right.location.reference),R_EDI); end else begin emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI); ungetregister32(right.location.register); end; popedx:=false; popeax:=false; if hreg1=R_EDX then begin if not(R_EAX in unused) then begin emit_reg(A_PUSH,S_L,R_EAX); popeax:=true; end else getexplicitregister32(R_EAX); emit_reg_reg(A_MOV,S_L,R_EDX,R_EAX); end else begin if not(R_EDX in unused) then begin emit_reg(A_PUSH,S_L,R_EDX); popedx:=true; end else getexplicitregister32(R_EDX); if hreg1<>R_EAX then begin if not(R_EAX in unused) then begin emit_reg(A_PUSH,S_L,R_EAX); popeax:=true; end else getexplicitregister32(R_EAX); emit_reg_reg(A_MOV,S_L,hreg1,R_EAX); end; end; { sign extension depends on the left type } if torddef(left.resulttype.def).typ=u32bit then emit_reg_reg(A_XOR,S_L,R_EDX,R_EDX) else emit_none(A_CDQ,S_NO); { division depends on the right type } if torddef(right.resulttype.def).typ=u32bit then emit_reg(A_DIV,S_L,R_EDI) else emit_reg(A_IDIV,S_L,R_EDI); ungetregister32(R_EDI); if nodetype=divn then begin if not popedx and (hreg1 <> R_EDX) then ungetregister(R_EDX); { if result register is busy then copy } if popeax then begin if hreg1=R_EAX then internalerror(112); emit_reg_reg(A_MOV,S_L,R_EAX,hreg1) end else if hreg1<>R_EAX then Begin ungetregister32(hreg1); { no need to allocate eax, that's already done before } { the div (JM) } hreg1 := R_EAX; end; end else begin if not popeax and (hreg1 <> R_EAX)then ungetregister(R_EAX); if popedx then {the mod was done by an (i)div (so the result is now in edx), but edx was occupied prior to the division, so move the result into a safe place (JM)} emit_reg_reg(A_MOV,S_L,R_EDX,hreg1) else Begin if hreg1 <> R_EDX then ungetregister32(hreg1); hreg1 := R_EDX End; end; if popeax then emit_reg(A_POP,S_L,R_EAX); if popedx then emit_reg(A_POP,S_L,R_EDX); end; If not(shrdiv) then { shrdiv only use hreg1 (which is already in usedinproc, } { since it was acquired with getregister), the others also } { use both EAX and EDX (JM) } Begin usedinproc:=usedinproc or ($80 shr byte(R_EAX)); usedinproc:=usedinproc or ($80 shr byte(R_EDX)); End; clear_location(location); location.loc:=LOC_REGISTER; location.register:=hreg1; end; end; {***************************************************************************** TI386SHLRSHRNODE *****************************************************************************} procedure ti386shlshrnode.pass_2; var hregister1,hregister2,hregister3, hregisterhigh,hregisterlow : tregister; pushed,popecx : boolean; op,opd : tasmop; l1,l2,l3 : tasmlabel; begin popecx:=false; secondpass(left); pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype.def)); secondpass(right); if pushed then restore(left,is_64bitint(left.resulttype.def)); { determine operator } case nodetype of shln: op:=A_SHL; shrn: op:=A_SHR; end; if is_64bitint(left.resulttype.def) then begin if nodetype = shln then opd:=A_SHLD else opd:=A_SHRD; { load left operator in a register } if left.location.loc<>LOC_REGISTER then begin if left.location.loc=LOC_CREGISTER then begin hregisterlow:=getregisterint; hregisterhigh:=getregisterint; emit_reg_reg(A_MOV,S_L,left.location.registerlow, hregisterlow); emit_reg_reg(A_MOV,S_L,left.location.registerhigh, hregisterlow); end else begin del_reference(left.location.reference); hregisterlow:=getregisterint; hregisterhigh:=getregisterint; emit_mov_ref_reg64(left.location.reference, hregisterlow, hregisterhigh); end; end else begin hregisterlow:=left.location.registerlow; hregisterhigh:=left.location.registerhigh; end; { shifting by a constant directly coded: } if (right.nodetype=ordconstn) then begin { shrd/shl works only for values <=31 !! } if tordconstnode(right).value>31 then begin if nodetype=shln then begin emit_reg_reg(A_XOR,S_L,hregisterhigh, hregisterhigh); if ((tordconstnode(right).value and 31) <> 0) then emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31, hregisterlow); end else begin emit_reg_reg(A_XOR,S_L,hregisterlow, hregisterlow); if ((tordconstnode(right).value and 31) <> 0) then emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31, hregisterhigh); end; location.registerhigh:=hregisterlow; location.registerlow:=hregisterhigh; end else begin if nodetype=shln then begin emit_const_reg_reg(A_SHLD,S_L,tordconstnode(right).value and 31, hregisterlow,hregisterhigh); emit_const_reg(A_SHL,S_L,tordconstnode(right).value and 31, hregisterlow); end else begin emit_const_reg_reg(A_SHRD,S_L,tordconstnode(right).value and 31, hregisterhigh,hregisterlow); emit_const_reg(A_SHR,S_L,tordconstnode(right).value and 31, hregisterhigh); end; location.registerlow:=hregisterlow; location.registerhigh:=hregisterhigh; end; location.loc:=LOC_REGISTER; end else begin { load right operators in a register } if right.location.loc<>LOC_REGISTER then begin if right.location.loc=LOC_CREGISTER then begin hregister2:=getexplicitregister32(R_ECX); emit_reg_reg(A_MOV,S_L,right.location.register, hregister2); end else begin del_reference(right.location.reference); hregister2:=getexplicitregister32(R_ECX); emit_ref_reg(A_MOV,S_L,newreference(right.location.reference), hregister2); end; end else hregister2:=right.location.register; { left operator is already in a register } { hence are both in a register } { is it in the case ECX ? } if (hregisterlow=R_ECX) then begin { then only swap } emit_reg_reg(A_XCHG,S_L,hregisterlow,hregister2); hregister3:=hregisterlow; hregisterlow:=hregister2; hregister2:=hregister3; end else if (hregisterhigh=R_ECX) then begin { then only swap } emit_reg_reg(A_XCHG,S_L,hregisterhigh,hregister2); hregister3:=hregisterhigh; hregisterhigh:=hregister2; hregister2:=hregister3; end { if second operator not in ECX ? } else if (hregister2<>R_ECX) then begin { ECX occupied then push it } if not (R_ECX in unused) then begin popecx:=true; emit_reg(A_PUSH,S_L,R_ECX); end else getexplicitregister32(R_ECX); emit_reg_reg(A_MOV,S_L,hregister2,R_ECX); end; if hregister2 <> R_ECX then ungetregister32(hregister2); { the damned shift instructions work only til a count of 32 } { so we've to do some tricks here } if nodetype=shln then begin getlabel(l1); getlabel(l2); getlabel(l3); emit_const_reg(A_CMP,S_L,64,R_ECX); emitjmp(C_L,l1); emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow); emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh); emitjmp(C_None,l3); emitlab(l1); emit_const_reg(A_CMP,S_L,32,R_ECX); emitjmp(C_L,l2); emit_const_reg(A_SUB,S_L,32,R_ECX); emit_reg_reg(A_SHL,S_L,R_CL, hregisterlow); emit_reg_reg(A_MOV,S_L,hregisterlow,hregisterhigh); emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow); emitjmp(C_None,l3); emitlab(l2); emit_reg_reg_reg(A_SHLD,S_L,R_CL, hregisterlow,hregisterhigh); emit_reg_reg(A_SHL,S_L,R_CL, hregisterlow); emitlab(l3); end else begin getlabel(l1); getlabel(l2); getlabel(l3); emit_const_reg(A_CMP,S_L,64,R_ECX); emitjmp(C_L,l1); emit_reg_reg(A_XOR,S_L,hregisterlow,hregisterlow); emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh); emitjmp(C_None,l3); emitlab(l1); emit_const_reg(A_CMP,S_L,32,R_ECX); emitjmp(C_L,l2); emit_const_reg(A_SUB,S_L,32,R_ECX); emit_reg_reg(A_SHR,S_L,R_CL, hregisterhigh); emit_reg_reg(A_MOV,S_L,hregisterhigh,hregisterlow); emit_reg_reg(A_XOR,S_L,hregisterhigh,hregisterhigh); emitjmp(C_None,l3); emitlab(l2); emit_reg_reg_reg(A_SHRD,S_L,R_CL, hregisterhigh,hregisterlow); emit_reg_reg(A_SHR,S_L,R_CL, hregisterhigh); emitlab(l3); end; { maybe put ECX back } if popecx then emit_reg(A_POP,S_L,R_ECX) else ungetregister32(R_ECX); location.registerlow:=hregisterlow; location.registerhigh:=hregisterhigh; end; end else begin { load left operators in a register } if left.location.loc<>LOC_REGISTER then begin if left.location.loc=LOC_CREGISTER then begin hregister1:=getregisterint; emit_reg_reg(A_MOV,S_L,left.location.register, hregister1); end else begin del_reference(left.location.reference); hregister1:=getregisterint; emit_ref_reg(A_MOV,S_L,newreference(left.location.reference), hregister1); end; end else hregister1:=left.location.register; { shifting by a constant directly coded: } if (right.nodetype=ordconstn) then begin { l shl 32 should 0 imho, but neither TP nor Delphi do it in this way (FK) if right.value<=31 then } emit_const_reg(op,S_L,tordconstnode(right).value and 31, hregister1); { else emit_reg_reg(A_XOR,S_L,hregister1, hregister1); } location.loc:=LOC_REGISTER; location.register:=hregister1; end else begin { load right operators in a register } if right.location.loc<>LOC_REGISTER then begin if right.location.loc=LOC_CREGISTER then begin hregister2:=getexplicitregister32(R_ECX); emit_reg_reg(A_MOV,S_L,right.location.register, hregister2); end else begin del_reference(right.location.reference); hregister2:=getexplicitregister32(R_ECX); emit_ref_reg(A_MOV,S_L,newreference(right.location.reference), hregister2); end; end else hregister2:=right.location.register; { left operator is already in a register } { hence are both in a register } { is it in the case ECX ? } if (hregister1=R_ECX) then begin { then only swap } emit_reg_reg(A_XCHG,S_L,hregister1,hregister2); hregister3:=hregister1; hregister1:=hregister2; hregister2:=hregister3; end { if second operator not in ECX ? } else if (hregister2<>R_ECX) then begin { ECX occupied then push it } if not (R_ECX in unused) then begin popecx:=true; emit_reg(A_PUSH,S_L,R_ECX); end else getexplicitregister32(R_ECX); emit_reg_reg(A_MOV,S_L,hregister2,R_ECX); end; ungetregister32(hregister2); { right operand is in ECX } emit_reg_reg(op,S_L,R_CL,hregister1); { maybe ECX back } if popecx then emit_reg(A_POP,S_L,R_ECX) else ungetregister32(R_ECX); location.register:=hregister1; end; end; end; {***************************************************************************** TI386UNARYMINUSNODE *****************************************************************************} function ti386unaryminusnode.pass_1 : tnode; begin result:=nil; firstpass(left); if codegenerror then exit; registers32:=left.registers32; registersfpu:=left.registersfpu; {$ifdef SUPPORT_MMX} registersmmx:=left.registersmmx; {$endif SUPPORT_MMX} if (left.resulttype.def.deftype=floatdef) then begin if (registersfpu < 1) then registersfpu := 1; location.loc:=LOC_FPU; end {$ifdef SUPPORT_MMX} else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then begin if (left.location.loc<>LOC_MMXREGISTER) and (registersmmx<1) then registersmmx:=1; end {$endif SUPPORT_MMX} else if is_64bitint(left.resulttype.def) then begin if (left.location.loc<>LOC_REGISTER) and (registers32<2) then registers32:=2; location.loc:=LOC_REGISTER; end else if (left.resulttype.def.deftype=orddef) then begin if (left.location.loc<>LOC_REGISTER) and (registers32<1) then registers32:=1; location.loc:=LOC_REGISTER; end; end; procedure ti386unaryminusnode.pass_2; {$ifdef SUPPORT_MMX} procedure do_mmx_neg; var op : tasmop; begin location.loc:=LOC_MMXREGISTER; if cs_mmx_saturation in aktlocalswitches then case mmx_type(resulttype.def) of mmxs8bit: op:=A_PSUBSB; mmxu8bit: op:=A_PSUBUSB; mmxs16bit,mmxfixed16: op:=A_PSUBSW; mmxu16bit: op:=A_PSUBUSW; end else case mmx_type(resulttype.def) of mmxs8bit,mmxu8bit: op:=A_PSUBB; mmxs16bit,mmxu16bit,mmxfixed16: op:=A_PSUBW; mmxs32bit,mmxu32bit: op:=A_PSUBD; end; emit_reg_reg(op,S_NO,location.register,R_MM7); emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register); end; {$endif} begin if is_64bitint(left.resulttype.def) then begin secondpass(left); clear_location(location); location.loc:=LOC_REGISTER; case left.location.loc of LOC_REGISTER : begin location.registerlow:=left.location.registerlow; location.registerhigh:=left.location.registerhigh; end; LOC_CREGISTER : begin location.registerlow:=getregisterint; location.registerhigh:=getregisterint; emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow); emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh); end; LOC_REFERENCE,LOC_MEM : begin del_reference(left.location.reference); location.registerlow:=getregisterint; location.registerhigh:=getregisterint; emit_mov_ref_reg64(left.location.reference, location.registerlow, location.registerhigh); end; end; { emit_reg(A_NEG,S_L,location.registerlow); emit_const_reg(A_ADC,S_L,0,location.registerhigh); emit_reg(A_NEG,S_L,location.registerhigh); } emit_reg(A_NOT,S_L,location.registerhigh); emit_reg(A_NEG,S_L,location.registerlow); emit_const_reg(A_SBB,S_L,-1,location.registerhigh); end else begin secondpass(left); location.loc:=LOC_REGISTER; case left.location.loc of LOC_REGISTER: begin location.register:=left.location.register; emit_reg(A_NEG,S_L,location.register); end; LOC_CREGISTER: begin location.register:=getregisterint; emit_reg_reg(A_MOV,S_L,location.register, location.register); emit_reg(A_NEG,S_L,location.register); end; {$ifdef SUPPORT_MMX} LOC_MMXREGISTER: begin set_location(location,left.location); emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7); do_mmx_neg; end; LOC_CMMXREGISTER: begin location.register:=getregistermmx; emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7); emit_reg_reg(A_MOVQ,S_NO,left.location.register, location.register); do_mmx_neg; end; {$endif SUPPORT_MMX} LOC_REFERENCE,LOC_MEM: begin del_reference(left.location.reference); if (left.resulttype.def.deftype=floatdef) then begin location.loc:=LOC_FPU; floatload(tfloatdef(left.resulttype.def).typ, left.location.reference); emit_none(A_FCHS,S_NO); end {$ifdef SUPPORT_MMX} else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then begin location.register:=getregistermmx; emit_reg_reg(A_PXOR,S_NO,R_MM7,R_MM7); emit_ref_reg(A_MOVQ,S_NO, newreference(left.location.reference), location.register); do_mmx_neg; end {$endif SUPPORT_MMX} else begin location.register:=getregisterint; emit_ref_reg(A_MOV,S_L, newreference(left.location.reference), location.register); emit_reg(A_NEG,S_L,location.register); end; end; LOC_FPU: begin location.loc:=LOC_FPU; emit_none(A_FCHS,S_NO); end; LOC_CFPUREGISTER: begin emit_reg(A_FLD,S_NO, correct_fpuregister(left.location.register,fpuvaroffset)); inc(fpuvaroffset); location.loc:=LOC_FPU; emit_none(A_FCHS,S_NO); end; end; end; { Here was a problem... } { Operand to be negated always } { seems to be converted to signed } { 32-bit before doing neg!! } { So this is useless... } { that's not true: -2^31 gives an overflow error if it is negaded (FK) } { emitoverflowcheck(p);} end; {***************************************************************************** TI386NOTNODE *****************************************************************************} procedure ti386notnode.pass_2; const flagsinvers : array[F_E..F_BE] of tresflags = (F_NE,F_E,F_LE,F_GE,F_L,F_G,F_NC,F_C, F_BE,F_B,F_AE,F_A); var hl : tasmlabel; opsize : topsize; begin if is_boolean(resulttype.def) then begin opsize:=def_opsize(resulttype.def); { the second pass could change the location of left } { if it is a register variable, so we've to do } { this before the case statement } if left.location.loc in [LOC_REFERENCE,LOC_MEM, LOC_FLAGS,LOC_REGISTER,LOC_CREGISTER] then secondpass(left); case left.location.loc of LOC_JUMP : begin hl:=truelabel; truelabel:=falselabel; falselabel:=hl; secondpass(left); maketojumpbool(left,lr_load_regvars); hl:=truelabel; truelabel:=falselabel; falselabel:=hl; end; LOC_FLAGS : location.resflags:=flagsinvers[left.location.resflags]; LOC_REGISTER, LOC_CREGISTER : begin location.loc:=LOC_FLAGS; location.resflags:=F_E; emit_reg_reg(A_TEST,opsize, left.location.register,left.location.register); ungetregister(left.location.register); end; LOC_REFERENCE, LOC_MEM : begin clear_location(location); location.loc:=LOC_REGISTER; del_reference(left.location.reference); { this was placed before del_ref => internaalerror(10) } location.register:=def_getreg(resulttype.def); emit_ref_reg(A_MOV,opsize, newreference(left.location.reference),location.register); emit_reg_reg(A_TEST,opsize,location.register,location.register); ungetregister(location.register); location.loc:=LOC_FLAGS; location.resflags:=F_E; end; end; end {$ifdef SUPPORT_MMX} else if (cs_mmx in aktlocalswitches) and is_mmx_able_array(left.resulttype.def) then begin secondpass(left); location.loc:=LOC_MMXREGISTER; { prepare EDI } getexplicitregister32(R_EDI); emit_const_reg(A_MOV,S_L,longint($ffffffff),R_EDI); { load operand } case left.location.loc of LOC_MMXREGISTER: set_location(location,left.location); LOC_CMMXREGISTER: begin location.register:=getregistermmx; emit_reg_reg(A_MOVQ,S_NO,left.location.register,location.register); end; LOC_REFERENCE,LOC_MEM: begin del_reference(left.location.reference); location.register:=getregistermmx; emit_ref_reg(A_MOVQ,S_NO, newreference(left.location.reference),location.register); end; end; { load mask } emit_reg_reg(A_MOVD,S_NO,R_EDI,R_MM7); ungetregister32(R_EDI); { lower 32 bit } emit_reg_reg(A_PXOR,S_D,R_MM7,location.register); { shift mask } emit_const_reg(A_PSLLQ,S_NO,32,R_MM7); { higher 32 bit } emit_reg_reg(A_PXOR,S_D,R_MM7,location.register); end {$endif SUPPORT_MMX} else if is_64bitint(left.resulttype.def) then begin secondpass(left); clear_location(location); location.loc:=LOC_REGISTER; case left.location.loc of LOC_REGISTER : begin location.registerlow:=left.location.registerlow; location.registerhigh:=left.location.registerhigh; emit_reg(A_NOT,S_L,location.registerlow); emit_reg(A_NOT,S_L,location.registerhigh); end; LOC_CREGISTER : begin location.registerlow:=getregisterint; location.registerhigh:=getregisterint; emit_reg_reg(A_MOV,S_L,left.location.registerlow,location.registerlow); emit_reg_reg(A_MOV,S_L,left.location.registerhigh,location.registerhigh); emit_reg(A_NOT,S_L,location.registerlow); emit_reg(A_NOT,S_L,location.registerhigh); end; LOC_REFERENCE,LOC_MEM : begin del_reference(left.location.reference); location.registerlow:=getregisterint; location.registerhigh:=getregisterint; emit_mov_ref_reg64(left.location.reference, location.registerlow, location.registerhigh); emit_reg(A_NOT,S_L,location.registerlow); emit_reg(A_NOT,S_L,location.registerhigh); end; end; end else begin secondpass(left); clear_location(location); opsize:=def_opsize(resulttype.def); location.loc:=LOC_REGISTER; case left.location.loc of LOC_REGISTER : begin location.register:=left.location.register; emit_reg(A_NOT,opsize,location.register); end; LOC_CREGISTER : begin location.register:=def_getreg(resulttype.def); emit_reg_reg(A_MOV,opsize,left.location.register,location.register); emit_reg(A_NOT,opsize,location.register); end; LOC_REFERENCE,LOC_MEM : begin del_reference(left.location.reference); location.register:=def_getreg(resulttype.def); emit_ref_reg(A_MOV,opsize, newreference(left.location.reference),location.register); emit_reg(A_NOT,opsize,location.register); end; end; end; end; begin cmoddivnode:=ti386moddivnode; cshlshrnode:=ti386shlshrnode; cunaryminusnode:=ti386unaryminusnode; cnotnode:=ti386notnode; end. { $Log$ Revision 1.22 2001-12-30 17:24:47 jonas * range checking is now processor independent (part in cgobj, part in cg64f32) and should work correctly again (it needed some changes after the changes of the low and high of tordef's to int64) * maketojumpbool() is now processor independent (in ncgutil) * getregister32 is now called getregisterint Revision 1.21 2001/12/29 15:27:24 jonas * made 'mod powerof2' -> 'and' optimization processor independent Revision 1.20 2001/12/27 15:33:58 jonas * fixed fpuregister counting errors ("merged") Revision 1.19 2001/12/07 13:03:49 jonas * fixed web bug 1716 Revision 1.18 2001/12/04 15:57:28 jonas * never generate any "shll/shrl $0,%reg" anymore Revision 1.17 2001/12/02 16:19:17 jonas * less unnecessary regvar loading with if-statements Revision 1.16 2001/09/05 15:22:10 jonas * made multiplying, dividing and mod'ing of int64 and qword processor independent with compilerprocs (+ small optimizations by using shift/and where possible) Revision 1.15 2001/08/29 12:03:23 jonas * fixed wrong regalloc info around FPC_MUL/DIV/MOD_INT64/QWORD calls * fixed partial result overwriting with the above calls too Revision 1.14 2001/08/26 13:37:00 florian * some cg reorganisation * some PPC updates Revision 1.13 2001/04/13 01:22:19 peter * symtable change to classes * range check generation and errors fixed, make cycle DEBUG=1 works * memory leaks fixed Revision 1.12 2001/04/04 22:37:06 peter * fix for not with no 32bit values Revision 1.11 2001/04/02 21:20:38 peter * resulttype rewrite Revision 1.10 2001/02/03 12:52:34 jonas * fixed web bug 1383 Revision 1.9 2000/12/07 17:19:46 jonas * new constant handling: from now on, hex constants >$7fffffff are parsed as unsigned constants (otherwise, $80000000 got sign extended and became $ffffffff80000000), all constants in the longint range become longints, all constants >$7fffffff and <=cardinal($ffffffff) are cardinals and the rest are int64's. * added lots of longint typecast to prevent range check errors in the compiler and rtl * type casts of symbolic ordinal constants are now preserved * fixed bug where the original resulttype.def wasn't restored correctly after doing a 64bit rangecheck Revision 1.8 2000/12/05 11:44:33 jonas + new integer regvar handling, should be much more efficient Revision 1.7 2000/11/29 00:30:48 florian * unused units removed from uses clause * some changes for widestrings Revision 1.6 2000/11/20 14:05:50 jonas * fixed bug in my changes to fix the regalloc info for div/mod ("merged") Revision 1.5 2000/10/31 22:02:56 peter * symtable splitted, no real code changes Revision 1.4 2000/10/19 16:26:52 jonas * fixed wrong regalloc info for secondmoddiv ("merged", also small correction made afterwards in fixes branch) Revision 1.3 2000/10/17 15:41:48 jonas * fixed stupid error in previous commit :/ Revision 1.1 2000/10/15 09:33:32 peter * moved n386*.pas to i386/ cpu_target dir Revision 1.4 2000/10/14 10:14:49 peter * moehrendorf oct 2000 rewrite Revision 1.3 2000/09/30 16:08:45 peter * more cg11 updates Revision 1.2 2000/09/24 15:06:18 peter * use defines.inc Revision 1.1 2000/09/22 22:24:37 florian * initial revision }