12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094 |
- {
- $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
- }
|