{ $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) procedure pass_2;override; end; ti386notnode = class(tnotnode) procedure pass_2;override; end; implementation uses globtype,systems, cutils,verbose,globals, symconst,symdef,aasm,types, hcodegen,temp_gen,pass_2, ncon, cpubase, cgai386,tgcpu,n386util; {***************************************************************************** TI386MODDIVNODE *****************************************************************************} procedure ti386moddivnode.pass_2; var hreg1 : tregister; hreg2 : tregister; shrdiv, andmod, pushed,popeax,popedx : boolean; power : longint; hl : pasmlabel; hloc : tlocation; pushedreg : tpushed; typename,opname : string[6]; begin shrdiv := false; andmod := false; secondpass(left); pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype)); secondpass(right); if pushed then restore(left,is_64bitint(left.resulttype)); set_location(location,left.location); if is_64bitint(resulttype) then begin { save lcoation, because we change it now } set_location(hloc,location); release_qword_loc(location); release_qword_loc(right.location); location.registerlow:=getexplicitregister32(R_EAX); location.registerhigh:=getexplicitregister32(R_EDX); pushusedregisters(pushedreg,$ff and not($80 shr byte(location.registerlow)) and not($80 shr byte(location.registerhigh))); { the left operand is in hloc, because the location of left is location but location is already destroyed } emit_pushq_loc(hloc); clear_location(hloc); emit_pushq_loc(right.location); if porddef(resulttype)^.typ=u64bit then typename:='QWORD' else typename:='INT64'; if nodetype=divn then opname:='DIV_' else opname:='MOD_'; saveregvars($ff); emitcall('FPC_'+opname+typename); emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow); emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh); popusedregisters(pushedreg); location.loc:=LOC_REGISTER; end else begin { put numerator in register } if left.location.loc<>LOC_REGISTER then begin if left.location.loc=LOC_CREGISTER then begin hreg1:=getregister32; emit_reg_reg(A_MOV,S_L,left.location.register,hreg1); end else begin del_reference(left.location.reference); hreg1:=getregister32; 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) 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 if (nodetype=modn) and (right.nodetype=ordconstn) and ispowerof2(tordconstnode(right).value,power) and Not(is_signed(left.resulttype)) Then {is there a similar trick for MOD'ing signed numbers? (JM)} Begin emit_const_reg(A_AND,S_L,tordconstnode(right).value-1,hreg1); andmod := true; 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 porddef(left.resulttype)^.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 porddef(right.resulttype)^.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 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; if not popedx and (hreg1 <> R_EDX) then ungetregister(R_EDX); end else {if we did the mod by an "and", the result is in hreg1 and EDX certainly hasn't been pushed (JM)} if not(andmod) Then begin 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; if not popeax and (hreg1 <> R_EAX)then ungetregister(R_EAX); 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(andmod or shrdiv) then {andmod and 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 : tasmop; l1,l2,l3 : pasmlabel; begin popecx:=false; secondpass(left); pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype)); secondpass(right); if pushed then restore(left,is_64bitint(left.resulttype)); if is_64bitint(left.resulttype) then begin { load left operator in a register } if left.location.loc<>LOC_REGISTER then begin if left.location.loc=LOC_CREGISTER then begin hregisterlow:=getregister32; hregisterhigh:=getregister32; 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:=getregister32; hregisterhigh:=getregister32; 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); 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); 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; 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:=getregister32; emit_reg_reg(A_MOV,S_L,left.location.register, hregister1); end else begin del_reference(left.location.reference); hregister1:=getregister32; emit_ref_reg(A_MOV,S_L,newreference(left.location.reference), hregister1); end; end else hregister1:=left.location.register; { determine operator } if nodetype=shln then op:=A_SHL else op:=A_SHR; { 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 *****************************************************************************} 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) of mmxs8bit: op:=A_PSUBSB; mmxu8bit: op:=A_PSUBUSB; mmxs16bit,mmxfixed16: op:=A_PSUBSW; mmxu16bit: op:=A_PSUBUSW; end else case mmx_type(resulttype) 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) 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:=getregister32; location.registerhigh:=getregister32; 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:=getregister32; location.registerhigh:=getregister32; 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:=getregister32; 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^.deftype=floatdef) and (pfloatdef(left.resulttype)^.typ<>f32bit) then begin location.loc:=LOC_FPU; floatload(pfloatdef(left.resulttype)^.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) 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:=getregister32; 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 : pasmlabel; opsize : topsize; begin if is_boolean(resulttype) then begin opsize:=def_opsize(resulttype); { 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); hl:=truelabel; truelabel:=falselabel; falselabel:=hl; end; LOC_FLAGS : location.resflags:=flagsinvers[left.location.resflags]; LOC_REGISTER : begin {location.register:=left.location.register; emit_const_reg(A_XOR,opsize,1,location.register);} 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_CREGISTER : begin clear_location(location); location.loc:=LOC_REGISTER; location.register:=def_getreg(resulttype); emit_reg_reg(A_MOV,opsize,left.location.register,location.register); emit_reg_reg(A_TEST,opsize,location.register,location.register); ungetregister(location.register); location.loc:=LOC_FLAGS; location.resflags:=F_E; 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); 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) 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) 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:=getregister32; location.registerhigh:=getregister32; 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:=getregister32; location.registerhigh:=getregister32; 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); location.loc:=LOC_REGISTER; case left.location.loc of LOC_REGISTER : begin location.register:=left.location.register; emit_reg(A_NOT,S_L,location.register); end; LOC_CREGISTER : begin location.register:=getregister32; emit_reg_reg(A_MOV,S_L,left.location.register,location.register); emit_reg(A_NOT,S_L,location.register); end; LOC_REFERENCE,LOC_MEM : begin del_reference(left.location.reference); location.register:=getregister32; emit_ref_reg(A_MOV,S_L, newreference(left.location.reference),location.register); emit_reg(A_NOT,S_L,location.register); end; end; end; end; begin cmoddivnode:=ti386moddivnode; cshlshrnode:=ti386shlshrnode; cunaryminusnode:=ti386unaryminusnode; cnotnode:=ti386notnode; end. { $Log$ 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 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 }