fpc/compiler/i386/n386add.pas
2002-03-04 19:10:11 +00:00

2017 lines
91 KiB
ObjectPascal

{
$Id$
Copyright (c) 2000 by Florian Klaempfl
Code generation for add nodes on the i386
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 n386add;
{$i defines.inc}
interface
uses
node,nadd,cpubase;
type
ti386addnode = class(taddnode)
procedure pass_2;override;
function getresflags(unsigned : boolean) : tresflags;
procedure SetResultLocation(cmpop,unsigned : boolean);
protected
function first_addstring : tnode; override;
private
procedure second_addstring;
end;
implementation
uses
globtype,systems,
cutils,verbose,globals,widestr,
symconst,symdef,aasm,types,htypechk,
cgbase,temp_gen,pass_2,regvars,
cpuasm,
ncon,nset,
tainst,cga,ncgutil,n386util,tgcpu;
function ti386addnode.getresflags(unsigned : boolean) : tresflags;
begin
case nodetype of
equaln : getresflags:=F_E;
unequaln : getresflags:=F_NE;
else
if not(unsigned) then
begin
if nf_swaped in flags then
case nodetype of
ltn : getresflags:=F_G;
lten : getresflags:=F_GE;
gtn : getresflags:=F_L;
gten : getresflags:=F_LE;
end
else
case nodetype of
ltn : getresflags:=F_L;
lten : getresflags:=F_LE;
gtn : getresflags:=F_G;
gten : getresflags:=F_GE;
end;
end
else
begin
if nf_swaped in flags then
case nodetype of
ltn : getresflags:=F_A;
lten : getresflags:=F_AE;
gtn : getresflags:=F_B;
gten : getresflags:=F_BE;
end
else
case nodetype of
ltn : getresflags:=F_B;
lten : getresflags:=F_BE;
gtn : getresflags:=F_A;
gten : getresflags:=F_AE;
end;
end;
end;
end;
procedure ti386addnode.SetResultLocation(cmpop,unsigned : boolean);
begin
{ remove temporary location if not a set or string }
{ that's a bad hack (FK) who did this ? }
if (left.resulttype.def.deftype<>stringdef) and
((left.resulttype.def.deftype<>setdef) or (tsetdef(left.resulttype.def).settype=smallset)) and
(left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
ungetiftemp(left.location.reference);
if (right.resulttype.def.deftype<>stringdef) and
((right.resulttype.def.deftype<>setdef) or (tsetdef(right.resulttype.def).settype=smallset)) and
(right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
ungetiftemp(right.location.reference);
{ in case of comparison operation the put result in the flags }
if cmpop then
begin
clear_location(location);
location.loc:=LOC_FLAGS;
location.resflags:=getresflags(unsigned);
end;
end;
{*****************************************************************************
Addstring
*****************************************************************************}
{ note: if you implemented an fpc_shortstr_concat similar to the }
{ one in i386.inc, you have to override first_addstring like in }
{ ti386addnode.first_string and implement the shortstring concat }
{ manually! The generic routine is different from the i386 one (JM) }
function ti386addnode.first_addstring : tnode;
begin
{ special cases for shortstrings, handled in pass_2 (JM) }
{ can't handle fpc_shortstr_compare with compilerproc either because it }
{ returns its results in the flags instead of in eax }
if (((nodetype = addn) and
is_shortstring(resulttype.def)) or
((nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
is_shortstring(left.resulttype.def))) then
begin
if nodetype = addn then
location.loc := LOC_MEM
else
location.loc := LOC_FLAGS;
calcregisters(self,0,0,0);
result := nil;
exit;
end;
{ otherwise, use the generic code }
result := inherited first_addstring;
end;
procedure ti386addnode.second_addstring;
var
pushedregs : tpushed;
href : treference;
cmpop : boolean;
regstopush : byte;
begin
{ string operations are not commutative }
if nf_swaped in flags then
swapleftright;
case tstringdef(left.resulttype.def).string_typ of
st_shortstring:
begin
case nodetype of
addn:
begin
cmpop:=false;
secondpass(left);
{ if str_concat is set in expr
s:=s+ ... no need to create a temp string (PM) }
{ the tempstring can also come from a typeconversion }
{ or a function result, so simply check for a }
{ temp of 256 bytes(JM) }
if not(istemp(left.location.reference) and
(getsizeoftemp(left.location.reference) = 256)) and
not(nf_use_strconcat in flags) then
begin
{ can only reference be }
{ string in register would be funny }
{ therefore produce a temporary string }
gettempofsizereference(256,href);
copyshortstring(href,left.location.reference,255,false,true);
{ release the registers }
{ done by copyshortstring now (JM) }
{ del_reference(left.location.reference); }
ungetiftemp(left.location.reference);
{ does not hurt: }
clear_location(left.location);
left.location.loc:=LOC_MEM;
left.location.reference:=href;
end;
secondpass(right);
{ on the right we do not need the register anymore too }
{ Instead of releasing them already, simply do not }
{ push them (so the release is in the right place, }
{ because emitpushreferenceaddr doesn't need extra }
{ registers) (JM) }
regstopush := $ff;
remove_non_regvars_from_loc(right.location,
regstopush);
pushusedregisters(pushedregs,regstopush);
{ push the maximum possible length of the result }
emitpushreferenceaddr(left.location.reference);
{ the optimizer can more easily put the }
{ deallocations in the right place if it happens }
{ too early than when it happens too late (if }
{ the pushref needs a "lea (..),edi; push edi") }
del_reference(right.location.reference);
emitpushreferenceaddr(right.location.reference);
saveregvars(regstopush);
emitcall('FPC_SHORTSTR_CONCAT');
ungetiftemp(right.location.reference);
maybe_loadself;
popusedregisters(pushedregs);
set_location(location,left.location);
end;
ltn,lten,gtn,gten,equaln,unequaln :
begin
cmpop := true;
pushusedregisters(pushedregs,$ff);
secondpass(left);
emitpushreferenceaddr(left.location.reference);
del_reference(left.location.reference);
secondpass(right);
emitpushreferenceaddr(right.location.reference);
del_reference(right.location.reference);
saveregvars($ff);
emitcall('FPC_SHORTSTR_COMPARE');
maybe_loadself;
popusedregisters(pushedregs);
ungetiftemp(left.location.reference);
ungetiftemp(right.location.reference);
end;
end;
SetResultLocation(cmpop,true);
end;
else
{ rest should be handled in first pass (JM) }
internalerror(200108303);
end;
end;
{*****************************************************************************
pass_2
*****************************************************************************}
procedure ti386addnode.pass_2;
{ is also being used for xor, and "mul", "sub, or and comparative }
{ operators }
label do_normal;
var
hregister,hregister2 : tregister;
noswap,popeax,popedx,
pushed,pushedfpu,
mboverflow,cmpop : boolean;
op,op2 : tasmop;
resflags : tresflags;
otl,ofl : tasmlabel;
power : longint;
opsize : topsize;
hl4: tasmlabel;
hr : preference;
{ true, if unsigned types are compared }
unsigned : boolean;
{ true, if a small set is handled with the longint code }
is_set : boolean;
{ is_in_dest if the result is put directly into }
{ the resulting refernce or varregister }
is_in_dest : boolean;
{ true, if for sets subtractions the extra not should generated }
extra_not : boolean;
{$ifdef SUPPORT_MMX}
mmxbase : tmmxtype;
{$endif SUPPORT_MMX}
regstopush: byte;
procedure firstjmp64bitcmp;
var
oldnodetype : tnodetype;
begin
load_all_regvars(exprasmlist);
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn:
begin
emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
{ cheat a little bit for the negative test }
toggleflag(nf_swaped);
emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
toggleflag(nf_swaped);
end;
lten,gten:
begin
oldnodetype:=nodetype;
if nodetype=lten then
nodetype:=ltn
else
nodetype:=gtn;
emitjmp(flags_to_cond(getresflags(unsigned)),truelabel);
{ cheat for the negative test }
if nodetype=ltn then
nodetype:=gtn
else
nodetype:=ltn;
emitjmp(flags_to_cond(getresflags(unsigned)),falselabel);
nodetype:=oldnodetype;
end;
equaln:
emitjmp(C_NE,falselabel);
unequaln:
emitjmp(C_NE,truelabel);
end;
end;
procedure secondjmp64bitcmp;
begin
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn,lten,gten:
begin
{ the comparisaion of the low dword have to be }
{ always unsigned! }
emitjmp(flags_to_cond(getresflags(true)),truelabel);
emitjmp(C_None,falselabel);
end;
equaln:
begin
emitjmp(C_NE,falselabel);
emitjmp(C_None,truelabel);
end;
unequaln:
begin
emitjmp(C_NE,truelabel);
emitjmp(C_None,falselabel);
end;
end;
end;
begin
{ to make it more readable, string and set (not smallset!) have their
own procedures }
case left.resulttype.def.deftype of
stringdef : begin
second_addstring;
exit;
end;
setdef : begin
{ normalsets are handled separate }
if not(tsetdef(left.resulttype.def).settype=smallset) then
begin
{ should be handled in pass 1 (JM) }
internalerror(200109041);
end;
end;
end;
{ defaults }
unsigned:=false;
is_in_dest:=false;
extra_not:=false;
noswap:=false;
opsize:=S_L;
{ are we a (small)set, must be set here because the side can be
swapped ! (PFV) }
is_set:=(left.resulttype.def.deftype=setdef);
{ calculate the operator which is more difficult }
firstcomplex(self);
{ handling boolean expressions extra: }
if is_boolean(left.resulttype.def) and
is_boolean(right.resulttype.def) then
begin
if (torddef(left.resulttype.def).typ=bool8bit) or
(torddef(right.resulttype.def).typ=bool8bit) then
opsize:=S_B
else
if (torddef(left.resulttype.def).typ=bool16bit) or
(torddef(right.resulttype.def).typ=bool16bit) then
opsize:=S_W
else
opsize:=S_L;
if (cs_full_boolean_eval in aktlocalswitches) or
(nodetype in
[unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
begin
if left.nodetype in [ordconstn,realconstn] then
swapleftright;
if left.location.loc=LOC_JUMP then
begin
otl:=truelabel;
getlabel(truelabel);
ofl:=falselabel;
getlabel(falselabel);
end;
secondpass(left);
{ if in flags then copy first to register, because the
flags can be destroyed }
case left.location.loc of
LOC_FLAGS:
locflags2reg(left.location,opsize);
LOC_JUMP:
locjump2reg(left.location,opsize, otl, ofl);
end;
set_location(location,left.location);
pushed:=maybe_push(right.registers32,self,false);
if right.location.loc=LOC_JUMP then
begin
otl:=truelabel;
getlabel(truelabel);
ofl:=falselabel;
getlabel(falselabel);
end;
secondpass(right);
if pushed then
begin
restore(self,false);
set_location(left.location,location);
end;
case right.location.loc of
LOC_FLAGS:
locflags2reg(right.location,opsize);
LOC_JUMP:
locjump2reg(right.location,opsize,otl,ofl);
end;
goto do_normal;
end;
case nodetype of
andn,
orn : begin
clear_location(location);
location.loc:=LOC_JUMP;
cmpop:=false;
case nodetype of
andn : begin
otl:=truelabel;
getlabel(truelabel);
secondpass(left);
maketojumpbool(left,lr_load_regvars);
emitlab(truelabel);
truelabel:=otl;
end;
orn : begin
ofl:=falselabel;
getlabel(falselabel);
secondpass(left);
maketojumpbool(left,lr_load_regvars);
emitlab(falselabel);
falselabel:=ofl;
end;
else
CGMessage(type_e_mismatch);
end;
secondpass(right);
maketojumpbool(right,lr_load_regvars);
end;
else
CGMessage(type_e_mismatch);
end
end
else
begin
{ in case of constant put it to the left }
if (left.nodetype=ordconstn) then
swapleftright;
secondpass(left);
{ this will be complicated as
a lot of code below assumes that
location and left.location are the same }
{$ifdef test_dest_loc}
if dest_loc_known and (dest_loc_tree=p) and
((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
begin
set_location(location,dest_loc);
in_dest_loc:=true;
is_in_dest:=true;
end
else
{$endif test_dest_loc}
set_location(location,left.location);
{ are too few registers free? }
pushed:=maybe_push(right.registers32,self,is_64bitint(left.resulttype.def));
if location.loc=LOC_FPU then
pushedfpu:=maybe_pushfpu(right.registersfpu,self)
else
pushedfpu:=false;
secondpass(right);
if pushed then
begin
restore(self,is_64bitint(left.resulttype.def));
set_location(left.location,location);
end;
if (left.resulttype.def.deftype=pointerdef) or
(right.resulttype.def.deftype=pointerdef) or
(is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
(left.resulttype.def.deftype=classrefdef) or
(left.resulttype.def.deftype=procvardef) or
((left.resulttype.def.deftype=enumdef) and
(left.resulttype.def.size=4)) or
((left.resulttype.def.deftype=orddef) and
(torddef(left.resulttype.def).typ=s32bit)) or
((right.resulttype.def.deftype=orddef) and
(torddef(right.resulttype.def).typ=s32bit)) or
((left.resulttype.def.deftype=orddef) and
(torddef(left.resulttype.def).typ=u32bit)) or
((right.resulttype.def.deftype=orddef) and
(torddef(right.resulttype.def).typ=u32bit)) or
{ as well as small sets }
is_set then
begin
do_normal:
mboverflow:=false;
cmpop:=false;
unsigned := not(is_signed(left.resulttype.def)) or
not(is_signed(right.resulttype.def));
case nodetype of
addn : begin
{ this is a really ugly hack!!!!!!!!!! }
{ this could be done later using EDI }
{ as it is done for subn }
{ instead of two registers!!!! }
if is_set then
begin
{ adding elements is not commutative }
if (nf_swaped in flags) and (left.nodetype=setelementn) then
swapleftright;
{ are we adding set elements ? }
if right.nodetype=setelementn then
begin
{ no range support for smallsets! }
if assigned(tsetelementnode(right).right) then
internalerror(43244);
{ bts requires both elements to be registers }
if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
begin
ungetiftemp(left.location.reference);
del_location(left.location);
{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
hregister:=getregisterint;
emit_ref_reg(A_MOV,opsize,
newreference(left.location.reference),hregister);
clear_location(left.location);
left.location.loc:=LOC_REGISTER;
left.location.register:=hregister;
set_location(location,left.location);
end;
if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
begin
ungetiftemp(right.location.reference);
del_location(right.location);
hregister:=getregisterint;
emit_ref_reg(A_MOV,opsize,
newreference(right.location.reference),hregister);
clear_location(right.location);
right.location.loc:=LOC_REGISTER;
right.location.register:=hregister;
end;
op:=A_BTS;
noswap:=true;
end
else
op:=A_OR;
mboverflow:=false;
unsigned:=false;
end
else
begin
op:=A_ADD;
mboverflow:=true;
end;
end;
symdifn : begin
{ the symetric diff is only for sets }
if is_set then
begin
op:=A_XOR;
mboverflow:=false;
unsigned:=false;
end
else
CGMessage(type_e_mismatch);
end;
muln : begin
if is_set then
begin
op:=A_AND;
mboverflow:=false;
unsigned:=false;
end
else
begin
if unsigned then
op:=A_MUL
else
op:=A_IMUL;
mboverflow:=true;
end;
end;
subn : begin
if is_set then
begin
op:=A_AND;
mboverflow:=false;
unsigned:=false;
If (not (nf_swaped in flags)) and
(right.nodetype = setconstn) then
right.location.reference.offset := not(right.location.reference.offset)
Else If (nf_swaped in flags) and
(left.nodetype = setconstn) then
left.location.reference.offset := not(left.location.reference.offset)
Else
extra_not:=true;
end
else
begin
op:=A_SUB;
mboverflow:=true;
end;
end;
ltn,lten,
gtn,gten,
equaln,unequaln : begin
If is_set Then
Case nodetype of
lten,gten:
Begin
If nodetype = lten then
swapleftright;
if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
begin
ungetiftemp(left.location.reference);
del_reference(left.location.reference);
hregister:=getregisterint;
emit_ref_reg(A_MOV,opsize,
newreference(left.location.reference),hregister);
clear_location(left.location);
left.location.loc:=LOC_REGISTER;
left.location.register:=hregister;
set_location(location,left.location);
end
else
if left.location.loc = LOC_CREGISTER Then
{save the register var in a temp register, because
its value is going to be modified}
begin
hregister := getregisterint;
emit_reg_reg(A_MOV,opsize,
left.location.register,hregister);
clear_location(left.location);
left.location.loc:=LOC_REGISTER;
left.location.register:=hregister;
set_location(location,left.location);
end;
{here, left.location should be LOC_REGISTER}
If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
emit_ref_reg(A_AND,opsize,
newreference(right.location.reference),left.location.register)
Else
emit_reg_reg(A_AND,opsize,
right.location.register,left.location.register);
{warning: ugly hack ahead: we need a "jne" after the cmp, so
change the nodetype from lten/gten to equaln}
nodetype := equaln
End;
{no < or > support for sets}
ltn,gtn: CGMessage(type_e_mismatch);
End;
op:=A_CMP;
cmpop:=true;
end;
xorn : op:=A_XOR;
orn : op:=A_OR;
andn : op:=A_AND;
else
CGMessage(type_e_mismatch);
end;
{ filter MUL, which requires special handling }
if op=A_MUL then
begin
popeax:=false;
popedx:=false;
{ here you need to free the symbol first }
{ left.location and right.location must }
{ only be freed when they are really released, }
{ because the optimizer NEEDS correct regalloc }
{ info!!! (JM) }
clear_location(location);
{ the location.register will be filled in later (JM) }
location.loc:=LOC_REGISTER;
{$IfNDef NoShlMul}
if right.nodetype=ordconstn then
swapleftright;
If (left.nodetype = ordconstn) and
ispowerof2(tordconstnode(left).value, power) and
not(cs_check_overflow in aktlocalswitches) then
Begin
{ This release will be moved after the next }
{ instruction by the optimizer. No need to }
{ release left.location, since it's a }
{ constant (JM) }
release_loc(right.location);
location.register := getregisterint;
emitloadord2reg(right.location,torddef(u32bittype.def),location.register,false);
emit_const_reg(A_SHL,S_L,power,location.register)
End
Else
Begin
{$EndIf NoShlMul}
regstopush := $ff;
remove_non_regvars_from_loc(right.location,regstopush);
remove_non_regvars_from_loc(left.location,regstopush);
{ now, regstopush does NOT contain EAX and/or EDX if they are }
{ used in either the left or the right location, excepts if }
{they are regvars. It DOES contain them if they are used in }
{ another location (JM) }
if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
begin
emit_reg(A_PUSH,S_L,R_EAX);
popeax:=true;
end;
if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
begin
emit_reg(A_PUSH,S_L,R_EDX);
popedx:=true;
end;
{ left.location can be R_EAX !!! }
getexplicitregister32(R_EDI);
{ load the left value }
emitloadord2reg(left.location,torddef(u32bittype.def),R_EDI,true);
release_loc(left.location);
{ allocate EAX }
if R_EAX in unused then
exprasmList.concat(Tairegalloc.Alloc(R_EAX));
{ load he right value }
emitloadord2reg(right.location,torddef(u32bittype.def),R_EAX,true);
release_loc(right.location);
{ allocate EAX if it isn't yet allocated (JM) }
if (R_EAX in unused) then
exprasmList.concat(Tairegalloc.Alloc(R_EAX));
{ also allocate EDX, since it is also modified by }
{ a mul (JM) }
if R_EDX in unused then
exprasmList.concat(Tairegalloc.Alloc(R_EDX));
emit_reg(A_MUL,S_L,R_EDI);
ungetregister32(R_EDI);
if R_EDX in unused then
exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
if R_EAX in unused then
exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
location.register := getregisterint;
emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
if popedx then
emit_reg(A_POP,S_L,R_EDX);
if popeax then
emit_reg(A_POP,S_L,R_EAX);
{$IfNDef NoShlMul}
End;
{$endif NoShlMul}
SetResultLocation(false,true);
exit;
end;
{ Convert flags to register first }
if (left.location.loc=LOC_FLAGS) then
locflags2reg(left.location,opsize);
if (right.location.loc=LOC_FLAGS) then
locflags2reg(right.location,opsize);
{ left and right no register? }
{ then one must be demanded }
if (left.location.loc<>LOC_REGISTER) and
(right.location.loc<>LOC_REGISTER) then
begin
{ register variable ? }
if (left.location.loc=LOC_CREGISTER) then
begin
{ it is OK if this is the destination }
if is_in_dest then
begin
hregister:=location.register;
emit_reg_reg(A_MOV,opsize,left.location.register,
hregister);
end
else
if cmpop then
begin
{ do not disturb the register }
hregister:=location.register;
end
else
begin
case opsize of
S_L : hregister:=getregisterint;
S_B : hregister:=reg32toreg8(getregisterint);
end;
emit_reg_reg(A_MOV,opsize,left.location.register,
hregister);
end
end
else
begin
ungetiftemp(left.location.reference);
del_reference(left.location.reference);
if is_in_dest then
begin
hregister:=location.register;
emit_ref_reg(A_MOV,opsize,
newreference(left.location.reference),hregister);
end
else
begin
{ first give free, then demand new register }
case opsize of
S_L : hregister:=getregisterint;
S_W : hregister:=reg32toreg16(getregisterint);
S_B : hregister:=reg32toreg8(getregisterint);
end;
emit_ref_reg(A_MOV,opsize,
newreference(left.location.reference),hregister);
end;
end;
clear_location(location);
location.loc:=LOC_REGISTER;
location.register:=hregister;
end
else
{ if on the right the register then swap }
if not(noswap) and (right.location.loc=LOC_REGISTER) then
begin
swap_location(location,right.location);
{ newly swapped also set swapped flag }
toggleflag(nf_swaped);
end;
{ at this point, location.loc should be LOC_REGISTER }
{ and location.register should be a valid register }
{ containing the left result }
if right.location.loc<>LOC_REGISTER then
begin
if (nodetype=subn) and (nf_swaped in flags) then
begin
if right.location.loc=LOC_CREGISTER then
begin
if extra_not then
emit_reg(A_NOT,opsize,location.register);
getexplicitregister32(R_EDI);
emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
emit_reg_reg(op,opsize,location.register,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
ungetregister32(R_EDI);
end
else
begin
if extra_not then
emit_reg(A_NOT,opsize,location.register);
getexplicitregister32(R_EDI);
emit_ref_reg(A_MOV,opsize,
newreference(right.location.reference),R_EDI);
emit_reg_reg(op,opsize,location.register,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
ungetregister32(R_EDI);
ungetiftemp(right.location.reference);
del_reference(right.location.reference);
end;
end
else
begin
if (right.nodetype=ordconstn) and
(op=A_CMP) and
(tordconstnode(right).value=0) then
begin
emit_reg_reg(A_TEST,opsize,location.register,
location.register);
end
else if (right.nodetype=ordconstn) and
(op=A_ADD) and
(tordconstnode(right).value=1) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_reg(A_INC,opsize,
location.register);
end
else if (right.nodetype=ordconstn) and
(op=A_SUB) and
(tordconstnode(right).value=1) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_reg(A_DEC,opsize,
location.register);
end
else if (right.nodetype=ordconstn) and
(op=A_IMUL) and
(ispowerof2(tordconstnode(right).value,power)) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_const_reg(A_SHL,opsize,power,
location.register);
end
else
begin
if (right.location.loc=LOC_CREGISTER) then
begin
if extra_not then
begin
getexplicitregister32(R_EDI);
emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
emit_reg(A_NOT,S_L,R_EDI);
emit_reg_reg(A_AND,S_L,R_EDI,
location.register);
ungetregister32(R_EDI);
end
else
begin
emit_reg_reg(op,opsize,right.location.register,
location.register);
end;
end
else
begin
if extra_not then
begin
getexplicitregister32(R_EDI);
emit_ref_reg(A_MOV,S_L,newreference(
right.location.reference),R_EDI);
emit_reg(A_NOT,S_L,R_EDI);
emit_reg_reg(A_AND,S_L,R_EDI,
location.register);
ungetregister32(R_EDI);
end
else
begin
emit_ref_reg(op,opsize,newreference(
right.location.reference),location.register);
end;
ungetiftemp(right.location.reference);
del_reference(right.location.reference);
end;
end;
end;
end
else
begin
{ when swapped another result register }
if (nodetype=subn) and (nf_swaped in flags) then
begin
if extra_not then
emit_reg(A_NOT,S_L,location.register);
emit_reg_reg(op,opsize,
location.register,right.location.register);
swap_location(location,right.location);
{ newly swapped also set swapped flag }
{ just to maintain ordering }
toggleflag(nf_swaped);
end
else
begin
if extra_not then
emit_reg(A_NOT,S_L,right.location.register);
emit_reg_reg(op,opsize,
right.location.register,
location.register);
end;
case opsize of
S_L : ungetregister32(right.location.register);
S_B : ungetregister32(reg8toreg32(right.location.register));
end;
end;
if cmpop then
case opsize of
S_L : ungetregister32(location.register);
S_B : ungetregister32(reg8toreg32(location.register));
end;
{ only in case of overflow operations }
{ produce overflow code }
{ we must put it here directly, because sign of operation }
{ is in unsigned VAR!! }
if mboverflow then
begin
if cs_check_overflow in aktlocalswitches then
begin
getlabel(hl4);
if unsigned then
emitjmp(C_NB,hl4)
else
emitjmp(C_NO,hl4);
emitcall('FPC_OVERFLOW');
emitlab(hl4);
end;
end;
end
else
{ Char type }
if ((left.resulttype.def.deftype=orddef) and
(torddef(left.resulttype.def).typ=uchar)) or
{ enumeration type 16 bit }
((left.resulttype.def.deftype=enumdef) and
(left.resulttype.def.size=1)) then
begin
case nodetype of
ltn,lten,gtn,gten,
equaln,unequaln :
cmpop:=true;
else CGMessage(type_e_mismatch);
end;
unsigned:=true;
{ left and right no register? }
{ the one must be demanded }
if (location.loc<>LOC_REGISTER) and
(right.location.loc<>LOC_REGISTER) then
begin
if location.loc=LOC_CREGISTER then
begin
if cmpop then
{ do not disturb register }
hregister:=location.register
else
begin
hregister:=reg32toreg8(getregisterint);
emit_reg_reg(A_MOV,S_B,location.register,
hregister);
end;
end
else
begin
del_reference(location.reference);
{ first give free then demand new register }
hregister:=reg32toreg8(getregisterint);
emit_ref_reg(A_MOV,S_B,newreference(location.reference),
hregister);
end;
clear_location(location);
location.loc:=LOC_REGISTER;
location.register:=hregister;
end;
{ now p always a register }
if (right.location.loc=LOC_REGISTER) and
(location.loc<>LOC_REGISTER) then
begin
swap_location(location,right.location);
{ newly swapped also set swapped flag }
toggleflag(nf_swaped);
end;
if right.location.loc<>LOC_REGISTER then
begin
if right.location.loc=LOC_CREGISTER then
begin
emit_reg_reg(A_CMP,S_B,
right.location.register,location.register);
end
else
begin
emit_ref_reg(A_CMP,S_B,newreference(
right.location.reference),location.register);
del_reference(right.location.reference);
end;
end
else
begin
emit_reg_reg(A_CMP,S_B,right.location.register,
location.register);
ungetregister32(reg8toreg32(right.location.register));
end;
ungetregister32(reg8toreg32(location.register));
end
else
{ 16 bit enumeration type }
if ((left.resulttype.def.deftype=enumdef) and
(left.resulttype.def.size=2)) then
begin
case nodetype of
ltn,lten,gtn,gten,
equaln,unequaln :
cmpop:=true;
else CGMessage(type_e_mismatch);
end;
unsigned:=true;
{ left and right no register? }
{ the one must be demanded }
if (location.loc<>LOC_REGISTER) and
(right.location.loc<>LOC_REGISTER) then
begin
if location.loc=LOC_CREGISTER then
begin
if cmpop then
{ do not disturb register }
hregister:=location.register
else
begin
hregister:=reg32toreg16(getregisterint);
emit_reg_reg(A_MOV,S_W,location.register,
hregister);
end;
end
else
begin
del_reference(location.reference);
{ first give free then demand new register }
hregister:=reg32toreg16(getregisterint);
emit_ref_reg(A_MOV,S_W,newreference(location.reference),
hregister);
end;
clear_location(location);
location.loc:=LOC_REGISTER;
location.register:=hregister;
end;
{ now p always a register }
if (right.location.loc=LOC_REGISTER) and
(location.loc<>LOC_REGISTER) then
begin
swap_location(location,right.location);
{ newly swapped also set swapped flag }
toggleflag(nf_swaped);
end;
if right.location.loc<>LOC_REGISTER then
begin
if right.location.loc=LOC_CREGISTER then
begin
emit_reg_reg(A_CMP,S_W,
right.location.register,location.register);
end
else
begin
emit_ref_reg(A_CMP,S_W,newreference(
right.location.reference),location.register);
del_reference(right.location.reference);
end;
end
else
begin
emit_reg_reg(A_CMP,S_W,right.location.register,
location.register);
ungetregister32(reg16toreg32(right.location.register));
end;
ungetregister32(reg16toreg32(location.register));
end
else
{ 64 bit types }
if is_64bitint(left.resulttype.def) then
begin
mboverflow:=false;
cmpop:=false;
unsigned:=((left.resulttype.def.deftype=orddef) and
(torddef(left.resulttype.def).typ=u64bit)) or
((right.resulttype.def.deftype=orddef) and
(torddef(right.resulttype.def).typ=u64bit));
case nodetype of
addn : begin
begin
op:=A_ADD;
op2:=A_ADC;
mboverflow:=true;
end;
end;
subn : begin
op:=A_SUB;
op2:=A_SBB;
mboverflow:=true;
end;
ltn,lten,
gtn,gten,
equaln,unequaln:
begin
op:=A_CMP;
op2:=A_CMP;
cmpop:=true;
end;
xorn:
begin
op:=A_XOR;
op2:=A_XOR;
end;
orn:
begin
op:=A_OR;
op2:=A_OR;
end;
andn:
begin
op:=A_AND;
op2:=A_AND;
end;
muln:
;
else
CGMessage(type_e_mismatch);
end;
if nodetype=muln then
begin
{ should be handled in pass_1 (JM) }
internalerror(200109051);
end
else
begin
{ left and right no register? }
{ then one must be demanded }
if (left.location.loc<>LOC_REGISTER) and
(right.location.loc<>LOC_REGISTER) then
begin
{ register variable ? }
if (left.location.loc=LOC_CREGISTER) then
begin
{ it is OK if this is the destination }
if is_in_dest then
begin
hregister:=location.registerlow;
hregister2:=location.registerhigh;
emit_reg_reg(A_MOV,S_L,left.location.registerlow,
hregister);
emit_reg_reg(A_MOV,S_L,left.location.registerlow,
hregister2);
end
else
if cmpop then
begin
{ do not disturb the register }
hregister:=location.registerlow;
hregister2:=location.registerhigh;
end
else
begin
hregister:=getregisterint;
hregister2:=getregisterint;
emit_reg_reg(A_MOV,S_L,left.location.registerlow,
hregister);
emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
hregister2);
end
end
else
begin
ungetiftemp(left.location.reference);
del_reference(left.location.reference);
if is_in_dest then
begin
hregister:=location.registerlow;
hregister2:=location.registerhigh;
emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
end
else
begin
hregister:=getregisterint;
hregister2:=getregisterint;
emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
end;
end;
clear_location(location);
location.loc:=LOC_REGISTER;
location.registerlow:=hregister;
location.registerhigh:=hregister2;
end
else
{ if on the right the register then swap }
if not(noswap) and (right.location.loc=LOC_REGISTER) then
begin
swap_location(location,right.location);
{ newly swapped also set swapped flag }
toggleflag(nf_swaped);
end;
{ at this point, location.loc should be LOC_REGISTER }
{ and location.register should be a valid register }
{ containing the left result }
if right.location.loc<>LOC_REGISTER then
begin
if (nodetype=subn) and (nf_swaped in flags) then
begin
if right.location.loc=LOC_CREGISTER then
begin
getexplicitregister32(R_EDI);
emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
emit_reg_reg(op,opsize,location.register,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
ungetregister32(R_EDI);
getexplicitregister32(R_EDI);
emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
{ the carry flag is still ok }
emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
ungetregister32(R_EDI);
end
else
begin
getexplicitregister32(R_EDI);
emit_ref_reg(A_MOV,opsize,
newreference(right.location.reference),R_EDI);
emit_reg_reg(op,opsize,location.registerlow,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
ungetregister32(R_EDI);
getexplicitregister32(R_EDI);
hr:=newreference(right.location.reference);
inc(hr^.offset,4);
emit_ref_reg(A_MOV,opsize,
hr,R_EDI);
{ here the carry flag is still preserved }
emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,
location.registerhigh);
ungetregister32(R_EDI);
ungetiftemp(right.location.reference);
del_reference(right.location.reference);
end;
end
else if cmpop then
begin
if (right.location.loc=LOC_CREGISTER) then
begin
emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
location.registerhigh);
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_L,right.location.registerlow,
location.registerlow);
secondjmp64bitcmp;
end
else
begin
hr:=newreference(right.location.reference);
inc(hr^.offset,4);
emit_ref_reg(A_CMP,S_L,
hr,location.registerhigh);
firstjmp64bitcmp;
emit_ref_reg(A_CMP,S_L,newreference(
right.location.reference),location.registerlow);
secondjmp64bitcmp;
emitjmp(C_None,falselabel);
ungetiftemp(right.location.reference);
del_reference(right.location.reference);
end;
end
else
begin
{
if (right.nodetype=ordconstn) and
(op=A_CMP) and
(right.value=0) then
begin
emit_reg_reg(A_TEST,opsize,location.register,
location.register);
end
else if (right.nodetype=ordconstn) and
(op=A_IMUL) and
(ispowerof2(right.value,power)) then
begin
emit_const_reg(A_SHL,opsize,power,
location.register);
end
else
}
begin
if (right.location.loc=LOC_CREGISTER) then
begin
emit_reg_reg(op,S_L,right.location.registerlow,
location.registerlow);
emit_reg_reg(op2,S_L,right.location.registerhigh,
location.registerhigh);
end
else
begin
emit_ref_reg(op,S_L,newreference(
right.location.reference),location.registerlow);
hr:=newreference(right.location.reference);
inc(hr^.offset,4);
emit_ref_reg(op2,S_L,
hr,location.registerhigh);
ungetiftemp(right.location.reference);
del_reference(right.location.reference);
end;
end;
end;
end
else
begin
{ when swapped another result register }
if (nodetype=subn) and (nf_swaped in flags) then
begin
emit_reg_reg(op,S_L,
location.registerlow,
right.location.registerlow);
emit_reg_reg(op2,S_L,
location.registerhigh,
right.location.registerhigh);
swap_location(location,right.location);
{ newly swapped also set swapped flag }
{ just to maintain ordering }
toggleflag(nf_swaped);
end
else if cmpop then
begin
emit_reg_reg(A_CMP,S_L,
right.location.registerhigh,
location.registerhigh);
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_L,
right.location.registerlow,
location.registerlow);
secondjmp64bitcmp;
end
else
begin
emit_reg_reg(op,S_L,
right.location.registerlow,
location.registerlow);
emit_reg_reg(op2,S_L,
right.location.registerhigh,
location.registerhigh);
end;
ungetregister32(right.location.registerlow);
ungetregister32(right.location.registerhigh);
end;
if cmpop then
begin
ungetregister32(location.registerlow);
ungetregister32(location.registerhigh);
end;
{ only in case of overflow operations }
{ produce overflow code }
{ we must put it here directly, because sign of operation }
{ is in unsigned VAR!! }
if mboverflow then
begin
if cs_check_overflow in aktlocalswitches then
begin
getlabel(hl4);
if unsigned then
emitjmp(C_NB,hl4)
else
emitjmp(C_NO,hl4);
emitcall('FPC_OVERFLOW');
emitlab(hl4);
end;
end;
{ we have LOC_JUMP as result }
if cmpop then
begin
clear_location(location);
location.loc:=LOC_JUMP;
cmpop:=false;
end;
end;
end
else
{ Floating point }
if (left.resulttype.def.deftype=floatdef) then
begin
{ real constants to the right, but only if it
isn't on the FPU stack, i.e. 1.0 or 0.0!
if (left.nodetype=realconstn) and
(left.location.loc<>LOC_FPU) then
swapleftright; obsolete, already swaped above PM }
cmpop:=false;
case nodetype of
addn : op:=A_FADDP;
muln : op:=A_FMULP;
subn : op:=A_FSUBP;
slashn : op:=A_FDIVP;
ltn,lten,gtn,gten,
equaln,unequaln : begin
op:=A_FCOMPP;
cmpop:=true;
end;
else CGMessage(type_e_mismatch);
end;
if (right.location.loc<>LOC_FPU) then
begin
if right.location.loc=LOC_CFPUREGISTER then
begin
emit_reg( A_FLD,S_NO,
correct_fpuregister(right.location.register,fpuvaroffset));
inc(fpuvaroffset);
end
else
begin
floatload(tfloatdef(right.resulttype.def).typ,right.location.reference);
if pushedfpu then
ungetiftemp(right.location.reference);
end;
if (left.location.loc<>LOC_FPU) then
begin
if left.location.loc=LOC_CFPUREGISTER then
begin
emit_reg( A_FLD,S_NO,
correct_fpuregister(left.location.register,fpuvaroffset));
inc(fpuvaroffset);
end
else
begin
floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
if pushedfpu then
ungetiftemp(left.location.reference);
end;
end
{ left was on the stack => swap }
else
toggleflag(nf_swaped);
{ releases the right reference }
del_reference(right.location.reference);
end
{ the nominator in st0 }
else if (left.location.loc<>LOC_FPU) then
begin
if left.location.loc=LOC_CFPUREGISTER then
begin
emit_reg( A_FLD,S_NO,
correct_fpuregister(left.location.register,fpuvaroffset));
inc(fpuvaroffset);
end
else
begin
floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
if pushedfpu then
ungetiftemp(left.location.reference);
end;
end
{ fpu operands are always in the wrong order on the stack }
else
toggleflag(nf_swaped);
{ releases the left reference }
if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
del_reference(left.location.reference);
{ if we swaped the tree nodes, then use the reverse operator }
if nf_swaped in flags then
begin
if (nodetype=slashn) then
op:=A_FDIVRP
else if (nodetype=subn) then
op:=A_FSUBRP;
end;
{ to avoid the pentium bug
if (op=FDIVP) and (opt_processors=pentium) then
emitcall('EMUL_FDIVP')
else
}
{ the Intel assemblers want operands }
if op<>A_FCOMPP then
begin
emit_reg_reg(op,S_NO,R_ST,R_ST1);
dec(fpuvaroffset);
end
else
begin
emit_none(op,S_NO);
dec(fpuvaroffset,2);
end;
{ on comparison load flags }
if cmpop then
begin
if not(R_EAX in unused) then
begin
getexplicitregister32(R_EDI);
emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
end;
emit_reg(A_FNSTSW,S_NO,R_AX);
emit_none(A_SAHF,S_NO);
if not(R_EAX in unused) then
begin
emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
ungetregister32(R_EDI);
end;
if nf_swaped in flags then
begin
case nodetype of
equaln : resflags:=F_E;
unequaln : resflags:=F_NE;
ltn : resflags:=F_A;
lten : resflags:=F_AE;
gtn : resflags:=F_B;
gten : resflags:=F_BE;
end;
end
else
begin
case nodetype of
equaln : resflags:=F_E;
unequaln : resflags:=F_NE;
ltn : resflags:=F_B;
lten : resflags:=F_BE;
gtn : resflags:=F_A;
gten : resflags:=F_AE;
end;
end;
clear_location(location);
location.loc:=LOC_FLAGS;
location.resflags:=resflags;
cmpop:=false;
end
else
begin
clear_location(location);
location.loc:=LOC_FPU;
end;
end
{$ifdef SUPPORT_MMX}
else
{ MMX Arrays }
if is_mmx_able_array(left.resulttype.def) then
begin
cmpop:=false;
mmxbase:=mmx_type(left.resulttype.def);
case nodetype of
addn : begin
if (cs_mmx_saturation in aktlocalswitches) then
begin
case mmxbase of
mmxs8bit:
op:=A_PADDSB;
mmxu8bit:
op:=A_PADDUSB;
mmxs16bit,mmxfixed16:
op:=A_PADDSB;
mmxu16bit:
op:=A_PADDUSW;
end;
end
else
begin
case mmxbase of
mmxs8bit,mmxu8bit:
op:=A_PADDB;
mmxs16bit,mmxu16bit,mmxfixed16:
op:=A_PADDW;
mmxs32bit,mmxu32bit:
op:=A_PADDD;
end;
end;
end;
muln : begin
case mmxbase of
mmxs16bit,mmxu16bit:
op:=A_PMULLW;
mmxfixed16:
op:=A_PMULHW;
end;
end;
subn : begin
if (cs_mmx_saturation in aktlocalswitches) then
begin
case mmxbase of
mmxs8bit:
op:=A_PSUBSB;
mmxu8bit:
op:=A_PSUBUSB;
mmxs16bit,mmxfixed16:
op:=A_PSUBSB;
mmxu16bit:
op:=A_PSUBUSW;
end;
end
else
begin
case mmxbase of
mmxs8bit,mmxu8bit:
op:=A_PSUBB;
mmxs16bit,mmxu16bit,mmxfixed16:
op:=A_PSUBW;
mmxs32bit,mmxu32bit:
op:=A_PSUBD;
end;
end;
end;
{
ltn,lten,gtn,gten,
equaln,unequaln :
begin
op:=A_CMP;
cmpop:=true;
end;
}
xorn:
op:=A_PXOR;
orn:
op:=A_POR;
andn:
op:=A_PAND;
else CGMessage(type_e_mismatch);
end;
{ left and right no register? }
{ then one must be demanded }
if (left.location.loc<>LOC_MMXREGISTER) and
(right.location.loc<>LOC_MMXREGISTER) then
begin
{ register variable ? }
if (left.location.loc=LOC_CMMXREGISTER) then
begin
{ it is OK if this is the destination }
if is_in_dest then
begin
hregister:=location.register;
emit_reg_reg(A_MOVQ,S_NO,left.location.register,
hregister);
end
else
begin
hregister:=getregistermmx;
emit_reg_reg(A_MOVQ,S_NO,left.location.register,
hregister);
end
end
else
begin
del_reference(left.location.reference);
if is_in_dest then
begin
hregister:=location.register;
emit_ref_reg(A_MOVQ,S_NO,
newreference(left.location.reference),hregister);
end
else
begin
hregister:=getregistermmx;
emit_ref_reg(A_MOVQ,S_NO,
newreference(left.location.reference),hregister);
end;
end;
clear_location(location);
location.loc:=LOC_MMXREGISTER;
location.register:=hregister;
end
else
{ if on the right the register then swap }
if (right.location.loc=LOC_MMXREGISTER) then
begin
swap_location(location,right.location);
{ newly swapped also set swapped flag }
toggleflag(nf_swaped);
end;
{ at this point, location.loc should be LOC_MMXREGISTER }
{ and location.register should be a valid register }
{ containing the left result }
if right.location.loc<>LOC_MMXREGISTER then
begin
if (nodetype=subn) and (nf_swaped in flags) then
begin
if right.location.loc=LOC_CMMXREGISTER then
begin
emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
emit_reg_reg(op,S_NO,location.register,R_MM0);
emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
end
else
begin
emit_ref_reg(A_MOVQ,S_NO,
newreference(right.location.reference),R_MM7);
emit_reg_reg(op,S_NO,location.register,
R_MM7);
emit_reg_reg(A_MOVQ,S_NO,
R_MM7,location.register);
del_reference(right.location.reference);
end;
end
else
begin
if (right.location.loc=LOC_CREGISTER) then
begin
emit_reg_reg(op,S_NO,right.location.register,
location.register);
end
else
begin
emit_ref_reg(op,S_NO,newreference(
right.location.reference),location.register);
del_reference(right.location.reference);
end;
end;
end
else
begin
{ when swapped another result register }
if (nodetype=subn) and (nf_swaped in flags) then
begin
emit_reg_reg(op,S_NO,
location.register,right.location.register);
swap_location(location,right.location);
{ newly swapped also set swapped flag }
{ just to maintain ordering }
toggleflag(nf_swaped);
end
else
begin
emit_reg_reg(op,S_NO,
right.location.register,
location.register);
end;
ungetregistermmx(right.location.register);
end;
end
{$endif SUPPORT_MMX}
else CGMessage(type_e_mismatch);
end;
SetResultLocation(cmpop,unsigned);
end;
begin
caddnode:=ti386addnode;
end.
{
$Log$
Revision 1.29 2002-03-04 19:10:13 peter
* removed compiler warnings
Revision 1.28 2001/12/30 17:24:46 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.27 2001/12/29 15:29:58 jonas
* powerpc/cgcpu.pas compiles :)
* several powerpc-related fixes
* cpuasm unit is now based on common tainst unit
+ nppcmat unit for powerpc (almost complete)
Revision 1.25 2001/10/12 13:51:51 jonas
* fixed internalerror(10) due to previous fpu overflow fixes ("merged")
* fixed bug in n386add (introduced after compilerproc changes for string
operations) where calcregisters wasn't called for shortstring addnodes
* NOTE: from now on, the location of a binary node must now always be set
before you call calcregisters() for it
Revision 1.24 2001/09/17 21:29:13 peter
* merged netbsd, fpu-overflow from fixes branch
Revision 1.23 2001/09/05 15:22:09 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.22 2001/09/04 11:38:55 jonas
+ searchsystype() and searchsystype() functions in symtable
* changed ninl and nadd to use these functions
* i386 set comparison functions now return their results in al instead
of in the flags so that they can be sued as compilerprocs
- removed all processor specific code from n386add.pas that has to do
with set handling, it's now all done in nadd.pas
* fixed fpc_set_contains_sets in genset.inc
* fpc_set_in_byte is now coded inline in n386set.pas and doesn't use a
helper anymore
* some small fixes in compproc.inc/set.inc regarding the declaration of
internal helper types (fpc_small_set and fpc_normal_set)
Revision 1.21 2001/09/03 13:27:42 jonas
* compilerproc implementation of set addition/substraction/...
* changed the declaration of some set helpers somewhat to accomodate the
above change
* i386 still uses the old code for comparisons of sets, because its
helpers return the results in the flags
* dummy tc_normal_2_small_set type conversion because I need the original
resulttype of the set add nodes
NOTE: you have to start a cycle with 1.0.5!
Revision 1.20 2001/08/30 15:43:14 jonas
* converted adding/comparing of strings to compileproc. Note that due
to the way the shortstring helpers for i386 are written, they are
still handled by the old code (reason: fpc_shortstr_compare returns
results in the flags instead of in eax and fpc_shortstr_concat
has wierd parameter conventions). The compilerproc stuff should work
fine with the generic implementations though.
* removed some nested comments warnings
Revision 1.19 2001/08/29 17:50:45 jonas
* removed unused var
Revision 1.18 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.17 2001/08/26 13:36:55 florian
* some cg reorganisation
* some PPC updates
Revision 1.16 2001/07/08 21:00:16 peter
* various widestring updates, it works now mostly without charset
mapping supported
Revision 1.15 2001/06/25 14:11:37 jonas
* fixed set bug discovered by Carl (merged)
Revision 1.14 2001/06/18 20:36:25 peter
* -Ur switch (merged)
* masm fixes (merged)
* quoted filenames for go32v2 and win32
Revision 1.13 2001/05/27 14:30:56 florian
+ some widestring stuff added
Revision 1.12 2001/05/06 17:12:14 jonas
* fixed an IE10 and another bug with [var1..var2] construct
Revision 1.11 2001/04/13 01:22:18 peter
* symtable change to classes
* range check generation and errors fixed, make cycle DEBUG=1 works
* memory leaks fixed
Revision 1.10 2001/04/02 21:20:36 peter
* resulttype rewrite
Revision 1.9 2000/12/31 11:14:11 jonas
+ implemented/fixed docompare() mathods for all nodes (not tested)
+ nopt.pas, nadd.pas, i386/n386opt.pas: optimized nodes for adding strings
and constant strings/chars together
* n386add.pas: don't copy temp strings (of size 256) to another temp string
when adding
Revision 1.8 2000/12/25 00:07:32 peter
+ new tlinkedlist class (merge of old tstringqueue,tcontainer and
tlinkedlist objects)
Revision 1.7 2000/12/16 15:56:18 jonas
- removed all ifdef cardinalmulfix code
Revision 1.6 2000/12/05 11:44:32 jonas
+ new integer regvar handling, should be much more efficient
Revision 1.5 2000/11/29 00:30:45 florian
* unused units removed from uses clause
* some changes for widestrings
Revision 1.4 2000/11/13 11:30:56 florian
* some bugs with interfaces and NIL fixed
Revision 1.3 2000/11/04 14:25:23 florian
+ merged Attila's changes for interfaces, not tested yet
Revision 1.2 2000/10/31 22:02:56 peter
* symtable splitted, no real code changes
Revision 1.1 2000/10/15 09:33:31 peter
* moved n386*.pas to i386/ cpu_target dir
Revision 1.6 2000/10/14 10:14:47 peter
* moehrendorf oct 2000 rewrite
Revision 1.5 2000/09/30 16:08:45 peter
* more cg11 updates
Revision 1.4 2000/09/24 15:06:18 peter
* use defines.inc
Revision 1.3 2000/09/22 22:42:52 florian
* more fixes
Revision 1.2 2000/09/21 12:24:22 jonas
* small fix to my changes for full boolean evaluation support (moved
opsize determination for boolean operations back in boolean
processing block)
+ full boolean evaluation support (from cg386add)
Revision 1.1 2000/09/20 21:23:32 florian
* initial revision
}