fpc/compiler/i386/n386add.pas
peter 4dcd96747e * moved entry and exitcode to ncgutil and cgobj
* foreach gets extra argument for passing local data to the
    iterator function
  * -CR checks also class typecasts at runtime by changing them
    into as
  * fixed compiler to cycle with the -CR option
  * fixed stabs with elf writer, finally the global variables can
    be watched
  * removed a lot of routines from cga unit and replaced them by
    calls to cgobj
  * u32bit-s32bit updates for and,or,xor nodes. When one element is
    u32bit then the other is typecasted also to u32bit without giving
    a rangecheck warning/error.
  * fixed pascal calling method with reversing also the high tree in
    the parast, detected by tcalcst3 test
2002-05-12 16:53:04 +00:00

1770 lines
64 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,cginfo;
type
ti386addnode = class(taddnode)
procedure pass_2;override;
protected
function first_addstring : tnode; override;
private
procedure pass_left_and_right(var pushedfpu:boolean);
function getresflags(unsigned : boolean) : tresflags;
procedure left_must_be_reg(opsize:TOpSize;noswap:boolean);
procedure emit_op_right_left(op:TAsmOp;opsize:TOpSize);
procedure emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
procedure set_result_location(cmpop,unsigned:boolean);
procedure second_addstring;
procedure second_addboolean;
procedure second_addfloat;
procedure second_addsmallset;
{$ifdef SUPPORT_MMX}
procedure second_addmmx;
{$endif SUPPORT_MMX}
procedure second_add64bit;
end;
implementation
uses
globtype,systems,
cutils,verbose,globals,
symconst,symdef,aasm,types,htypechk,
cgbase,pass_2,regvars,
cpuasm,
ncon,nset,
tainst,cga,ncgutil,n386util,tgobj,rgobj,rgcpu,cgobj,cg64f32;
{*****************************************************************************
Helpers
*****************************************************************************}
const
opsize_2_cgsize : array[S_B..S_L] of tcgsize = (OS_8,OS_16,OS_32);
procedure ti386addnode.pass_left_and_right(var pushedfpu:boolean);
var
pushed : boolean;
begin
{ calculate the operator which is more difficult }
firstcomplex(self);
{ in case of constant put it to the left }
if (left.nodetype=ordconstn) then
swapleftright;
secondpass(left);
{ are too few registers free? }
pushed:=maybe_push(right.registers32,left,is_64bitint(left.resulttype.def));
if location.loc=LOC_FPUREGISTER then
pushedfpu:=maybe_pushfpu(right.registersfpu,left)
else
pushedfpu:=false;
secondpass(right);
if pushed then
restore(left,is_64bitint(left.resulttype.def));
end;
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.left_must_be_reg(opsize:TOpSize;noswap:boolean);
begin
{ left location is not a register? }
if (left.location.loc<>LOC_REGISTER) then
begin
{ if right is register then we can swap the locations }
if (not noswap) and
(right.location.loc=LOC_REGISTER) then
begin
location_swap(left.location,right.location);
toggleflag(nf_swaped);
end
else
begin
{ maybe we can reuse a constant register when the
operation is a comparison that doesn't change the
value of the register }
location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],(nodetype in [ltn,lten,gtn,gten,equaln,unequaln]));
end;
end;
end;
procedure ti386addnode.emit_op_right_left(op:TAsmOp;opsize:TOpsize);
begin
{ left must be a register }
case right.location.loc of
LOC_REGISTER,
LOC_CREGISTER :
exprasmlist.concat(taicpu.op_reg_reg(op,opsize,right.location.register,left.location.register));
LOC_REFERENCE,
LOC_CREFERENCE :
exprasmlist.concat(taicpu.op_ref_reg(op,opsize,right.location.reference,left.location.register));
LOC_CONSTANT :
exprasmlist.concat(taicpu.op_const_reg(op,opsize,right.location.value,left.location.register));
else
internalerror(200203232);
end;
end;
procedure ti386addnode.set_result_location(cmpop,unsigned:boolean);
begin
if cmpop then
begin
location_reset(location,LOC_FLAGS,OS_NO);
location.resflags:=getresflags(unsigned);
end
else
location_copy(location,left.location);
end;
procedure ti386addnode.emit_generic_code(op:TAsmOp;opsize:TOpSize;unsigned,extra_not,mboverflow:boolean);
var
power : longint;
hl4 : tasmlabel;
begin
{ at this point, left.location.loc should be LOC_REGISTER }
if right.location.loc=LOC_REGISTER then
begin
{ right.location is a LOC_REGISTER }
{ 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,left.location.register);
emit_reg_reg(op,opsize,left.location.register,right.location.register);
{ newly swapped also set swapped flag }
location_swap(left.location,right.location);
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,left.location.register);
end;
end
else
begin
{ right.location is not a LOC_REGISTER }
if (nodetype=subn) and (nf_swaped in flags) then
begin
if extra_not then
emit_reg(A_NOT,opsize,left.location.register);
rg.getexplicitregisterint(exprasmlist,R_EDI);
cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
emit_reg_reg(op,opsize,left.location.register,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,left.location.register);
rg.ungetregisterint(exprasmlist,R_EDI);
end
else
begin
{ Optimizations when right.location is a constant value }
if (op=A_CMP) and
(nodetype in [equaln,unequaln]) and
(right.location.loc=LOC_CONSTANT) and
(right.location.value=0) then
begin
emit_reg_reg(A_TEST,opsize,left.location.register,left.location.register);
end
else
if (op=A_ADD) and
(right.location.loc=LOC_CONSTANT) and
(right.location.value=1) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_reg(A_INC,opsize,left.location.register);
end
else
if (op=A_SUB) and
(right.location.loc=LOC_CONSTANT) and
(right.location.value=1) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_reg(A_DEC,opsize,left.location.register);
end
else
if (op=A_IMUL) and
(right.location.loc=LOC_CONSTANT) and
(ispowerof2(right.location.value,power)) and
not(cs_check_overflow in aktlocalswitches) then
begin
emit_const_reg(A_SHL,opsize,power,left.location.register);
end
else
begin
if extra_not then
begin
rg.getexplicitregisterint(exprasmlist,R_EDI);
cg.a_load_loc_reg(exprasmlist,right.location,R_EDI);
emit_reg(A_NOT,S_L,R_EDI);
emit_reg_reg(A_AND,S_L,R_EDI,left.location.register);
rg.ungetregisterint(exprasmlist,R_EDI);
end
else
begin
emit_op_right_left(op,opsize);
end;
end;
end;
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);
cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
cg.a_label(exprasmlist,hl4);
end;
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_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def))
else
location_reset(location,LOC_FLAGS,OS_NO);
calcregisters(self,0,0,0);
result := nil;
exit;
end;
{ otherwise, use the generic code }
result := inherited first_addstring;
end;
procedure ti386addnode.second_addstring;
var
href : treference;
cmpop : boolean;
pushedregs : tpushedsaved;
regstopush : tregisterset;
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(tg.istemp(left.location.reference) and
(tg.getsizeoftemp(left.location.reference) = 256)) and
not(nf_use_strconcat in flags) then
begin
tg.gettempofsizereference(exprasmlist,256,href);
cg.g_copyshortstring(exprasmlist,left.location.reference,href,255,true,false);
{ location is released by copyshortstring }
location_freetemp(exprasmlist,left.location);
location_reset(left.location,LOC_CREFERENCE,def_cgsize(resulttype.def));
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 := all_registers;
remove_non_regvars_from_loc(right.location,regstopush);
rg.saveusedregisters(exprasmlist,pushedregs,regstopush);
{ push the maximum possible length of the result }
cg.a_paramaddr_ref(exprasmlist,left.location.reference,2);
{ 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") }
location_release(exprasmlist,right.location);
cg.a_paramaddr_ref(exprasmlist,right.location.reference,1);
rg.saveregvars(exprasmlist,regstopush);
cg.a_call_name(exprasmlist,'FPC_SHORTSTR_CONCAT');
tg.ungetiftemp(exprasmlist,right.location.reference);
cg.g_maybe_loadself(exprasmlist);
rg.restoreusedregisters(exprasmlist,pushedregs);
location_copy(location,left.location);
end;
ltn,lten,gtn,gten,equaln,unequaln :
begin
cmpop := true;
rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
secondpass(left);
location_release(exprasmlist,left.location);
cg.a_paramaddr_ref(exprasmlist,left.location.reference,2);
secondpass(right);
location_release(exprasmlist,right.location);
cg.a_paramaddr_ref(exprasmlist,right.location.reference,1);
rg.saveregvars(exprasmlist,all_registers);
cg.a_call_name(exprasmlist,'FPC_SHORTSTR_COMPARE');
cg.g_maybe_loadself(exprasmlist);
rg.restoreusedregisters(exprasmlist,pushedregs);
location_freetemp(exprasmlist,left.location);
location_freetemp(exprasmlist,right.location);
end;
end;
set_result_location(cmpop,true);
end;
else
{ rest should be handled in first pass (JM) }
internalerror(200108303);
end;
end;
{*****************************************************************************
AddBoolean
*****************************************************************************}
procedure ti386addnode.second_addboolean;
var
op : TAsmOp;
opsize : TOpsize;
cmpop,
pushed,
isjump : boolean;
otl,ofl : tasmlabel;
begin
{ calculate the operator which is more difficult }
firstcomplex(self);
cmpop:=false;
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;
isjump:=(left.location.loc=LOC_JUMP);
if isjump then
begin
otl:=truelabel;
getlabel(truelabel);
ofl:=falselabel;
getlabel(falselabel);
end;
secondpass(left);
if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
if isjump then
begin
truelabel:=otl;
falselabel:=ofl;
end;
pushed:=maybe_push(right.registers32,left,false);
isjump:=(right.location.loc=LOC_JUMP);
if isjump then
begin
otl:=truelabel;
getlabel(truelabel);
ofl:=falselabel;
getlabel(falselabel);
end;
secondpass(right);
if pushed then
restore(left,false);
if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
if isjump then
begin
truelabel:=otl;
falselabel:=ofl;
end;
{ left must be a register }
left_must_be_reg(opsize,false);
{ compare the }
case nodetype of
ltn,lten,gtn,gten,
equaln,unequaln :
begin
op:=A_CMP;
cmpop:=true;
end;
xorn :
op:=A_XOR;
orn :
op:=A_OR;
andn :
op:=A_AND;
else
internalerror(200203247);
end;
emit_op_right_left(op,opsize);
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
if cmpop then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
set_result_location(cmpop,true);
end
else
begin
case nodetype of
andn,
orn :
begin
location_reset(location,LOC_JUMP,OS_NO);
case nodetype of
andn :
begin
otl:=truelabel;
getlabel(truelabel);
secondpass(left);
maketojumpbool(exprasmlist,left,lr_load_regvars);
cg.a_label(exprasmlist,truelabel);
truelabel:=otl;
end;
orn :
begin
ofl:=falselabel;
getlabel(falselabel);
secondpass(left);
maketojumpbool(exprasmlist,left,lr_load_regvars);
cg.a_label(exprasmlist,falselabel);
falselabel:=ofl;
end;
else
CGMessage(type_e_mismatch);
end;
secondpass(right);
maketojumpbool(exprasmlist,right,lr_load_regvars);
end;
else
CGMessage(type_e_mismatch);
end;
end;
end;
{*****************************************************************************
AddFloat
*****************************************************************************}
procedure ti386addnode.second_addfloat;
var
op : TAsmOp;
resflags : tresflags;
pushedfpu,
cmpop : boolean;
begin
pass_left_and_right(pushedfpu);
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_FPUREGISTER) then
begin
cg.a_loadfpu_loc_reg(exprasmlist,
right.location,R_ST);
if (right.location.loc <> LOC_CFPUREGISTER) and
pushedfpu then
location_freetemp(exprasmlist,left.location);
if (left.location.loc<>LOC_FPUREGISTER) then
begin
cg.a_loadfpu_loc_reg(exprasmlist,left.location,R_ST);
if (left.location.loc <> LOC_CFPUREGISTER) and
pushedfpu then
location_freetemp(exprasmlist,left.location);
end
else
begin
{ left was on the stack => swap }
toggleflag(nf_swaped);
end;
{ releases the right reference }
location_release(exprasmlist,right.location);
end
{ the nominator in st0 }
else if (left.location.loc<>LOC_FPUREGISTER) then
begin
cg.a_loadfpu_loc_reg(exprasmlist,left.location,R_ST);
if (left.location.loc <> LOC_CFPUREGISTER) and
pushedfpu then
location_freetemp(exprasmlist,left.location);
end
else
begin
{ fpu operands are always in the wrong order on the stack }
toggleflag(nf_swaped);
end;
{ releases the left reference }
if (left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
location_release(exprasmlist,left.location);
{ 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
cg.a_call_name(exprasmlist,'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(trgcpu(rg).fpuvaroffset);
end
else
begin
emit_none(op,S_NO);
dec(trgcpu(rg).fpuvaroffset,2);
end;
{ on comparison load flags }
if cmpop then
begin
if not(R_EAX in rg.unusedregsint) then
begin
rg.getexplicitregisterint(exprasmlist,R_EDI);
emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
end;
emit_reg(A_FNSTSW,S_NO,R_AX);
emit_none(A_SAHF,S_NO);
if not(R_EAX in rg.unusedregsint) then
begin
emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
rg.ungetregisterint(exprasmlist,R_EDI);
end;
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;
location_reset(location,LOC_FLAGS,OS_NO);
location.resflags:=resflags;
end
else
begin
location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
location.register:=R_ST;
end;
end;
{*****************************************************************************
AddSmallSet
*****************************************************************************}
procedure ti386addnode.second_addsmallset;
var
opsize : TOpSize;
op : TAsmOp;
cmpop,
pushedfpu,
extra_not,
noswap : boolean;
begin
pass_left_and_right(pushedfpu);
{ when a setdef is passed, it has to be a smallset }
if ((left.resulttype.def.deftype=setdef) and
(tsetdef(left.resulttype.def).settype<>smallset)) or
((right.resulttype.def.deftype=setdef) and
(tsetdef(right.resulttype.def).settype<>smallset)) then
internalerror(200203301);
cmpop:=false;
noswap:=false;
extra_not:=false;
opsize:=S_L;
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!!!! }
{ 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 }
location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],true);
op:=A_BTS;
noswap:=true;
end
else
op:=A_OR;
end;
symdifn :
op:=A_XOR;
muln :
op:=A_AND;
subn :
begin
op:=A_AND;
if (not(nf_swaped in flags)) and
(right.location.loc=LOC_CONSTANT) then
right.location.value := not(right.location.value)
else if (nf_swaped in flags) and
(left.location.loc=LOC_CONSTANT) then
left.location.value := not(left.location.value)
else
extra_not:=true;
end;
equaln,
unequaln :
begin
op:=A_CMP;
cmpop:=true;
end;
lten,gten:
begin
If (not(nf_swaped in flags) and
(nodetype = lten)) or
((nf_swaped in flags) and
(nodetype = gten)) then
swapleftright;
location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],true);
emit_op_right_left(A_AND,opsize);
op:=A_CMP;
cmpop:=true;
{ warning: ugly hack, we need a JE so change the node to equaln }
nodetype:=equaln;
end;
xorn :
op:=A_XOR;
orn :
op:=A_OR;
andn :
op:=A_AND;
else
begin
{ no < or > support for sets }
CGMessage(type_e_mismatch);
end;
end;
{ left must be a register }
left_must_be_reg(opsize,noswap);
emit_generic_code(op,opsize,true,extra_not,false);
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
if cmpop then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
set_result_location(cmpop,true);
end;
{*****************************************************************************
Add64bit
*****************************************************************************}
procedure ti386addnode.second_add64bit;
var
op : TOpCG;
op1,op2 : TAsmOp;
opsize : TOpSize;
hregister,
hregister2 : tregister;
href : treference;
hl4 : tasmlabel;
pushedfpu,
mboverflow,
cmpop,
unsigned : boolean;
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);
cg.a_jmp_always(exprasmlist,falselabel);
end;
equaln:
begin
emitjmp(C_NE,falselabel);
cg.a_jmp_always(exprasmlist,truelabel);
end;
unequaln:
begin
emitjmp(C_NE,truelabel);
cg.a_jmp_always(exprasmlist,falselabel);
end;
end;
end;
begin
firstcomplex(self);
pass_left_and_right(pushedfpu);
op1:=A_NONE;
op2:=A_NONE;
mboverflow:=false;
cmpop:=false;
opsize:=S_L;
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
op:=OP_ADD;
mboverflow:=true;
end;
subn :
begin
op:=OP_SUB;
op1:=A_SUB;
op2:=A_SBB;
mboverflow:=true;
end;
ltn,lten,
gtn,gten,
equaln,unequaln:
begin
op:=OP_NONE;
cmpop:=true;
end;
xorn:
op:=OP_XOR;
orn:
op:=OP_OR;
andn:
op:=OP_AND;
muln:
begin
{ should be handled in pass_1 (JM) }
internalerror(200109051);
end;
else
CGMessage(type_e_mismatch);
end;
{ left and right no register? }
{ then one must be demanded }
if (left.location.loc<>LOC_REGISTER) then
begin
if (right.location.loc<>LOC_REGISTER) then
begin
{ we can reuse a CREGISTER for comparison }
if not((left.location.loc=LOC_CREGISTER) and cmpop) then
begin
if (left.location.loc<>LOC_CREGISTER) then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
hregister:=rg.getregisterint(exprasmlist);
hregister2:=rg.getregisterint(exprasmlist);
tcg64f32(cg).a_load64_loc_reg(exprasmlist,left.location,hregister,hregister2);
location_reset(left.location,LOC_REGISTER,OS_64);
left.location.registerlow:=hregister;
left.location.registerhigh:=hregister2;
end;
end
else
begin
location_swap(left.location,right.location);
toggleflag(nf_swaped);
end;
end;
{ at this point, left.location.loc should be LOC_REGISTER }
if right.location.loc=LOC_REGISTER then
begin
{ when swapped another result register }
if (nodetype=subn) and (nf_swaped in flags) then
begin
tcg64f32(cg).a_op64_reg_reg(exprasmlist,op,
left.location.registerlow,left.location.registerhigh,
right.location.registerlow,right.location.registerhigh);
location_swap(left.location,right.location);
toggleflag(nf_swaped);
end
else if cmpop then
begin
emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
secondjmp64bitcmp;
end
else
begin
tcg64f32(cg).a_op64_reg_reg(exprasmlist,op,
right.location.registerlow,right.location.registerhigh,
left.location.registerlow,left.location.registerhigh);
end;
location_release(exprasmlist,right.location);
end
else
begin
{ right.location<>LOC_REGISTER }
if (nodetype=subn) and (nf_swaped in flags) then
begin
rg.getexplicitregisterint(exprasmlist,R_EDI);
tcg64f32(cg).a_load64low_loc_reg(exprasmlist,right.location,R_EDI);
emit_reg_reg(op1,opsize,left.location.registerlow,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,left.location.registerlow);
tcg64f32(cg).a_load64high_loc_reg(exprasmlist,right.location,R_EDI);
{ the carry flag is still ok }
emit_reg_reg(op2,opsize,left.location.registerhigh,R_EDI);
emit_reg_reg(A_MOV,opsize,R_EDI,left.location.registerhigh);
rg.ungetregisterint(exprasmlist,R_EDI);
if right.location.loc<>LOC_CREGISTER then
begin
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
end;
end
else if cmpop then
begin
case right.location.loc of
LOC_CREGISTER :
begin
emit_reg_reg(A_CMP,S_L,right.location.registerhigh,left.location.registerhigh);
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_L,right.location.registerlow,left.location.registerlow);
secondjmp64bitcmp;
end;
LOC_CREFERENCE,
LOC_REFERENCE :
begin
href:=right.location.reference;
inc(href.offset,4);
emit_ref_reg(A_CMP,S_L,href,left.location.registerhigh);
firstjmp64bitcmp;
emit_ref_reg(A_CMP,S_L,right.location.reference,left.location.registerlow);
secondjmp64bitcmp;
cg.a_jmp_always(exprasmlist,falselabel);
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
end;
LOC_CONSTANT :
begin
exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,right.location.valuehigh,left.location.registerhigh));
firstjmp64bitcmp;
exprasmlist.concat(taicpu.op_const_reg(A_CMP,S_L,right.location.valuelow,left.location.registerlow));
secondjmp64bitcmp;
end;
else
internalerror(200203282);
end;
end
else
begin
tcg64f32(cg).a_op64_loc_reg(exprasmlist,op,right.location,
left.location.registerlow,left.location.registerhigh);
if (right.location.loc<>LOC_CREGISTER) then
begin
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
end;
end;
end;
if (left.location.loc<>LOC_CREGISTER) and cmpop then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
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);
cg.a_call_name(exprasmlist,'FPC_OVERFLOW');
cg.a_label(exprasmlist,hl4);
end;
end;
{ we have LOC_JUMP as result }
if cmpop then
location_reset(location,LOC_JUMP,OS_NO)
else
location_copy(location,left.location);
end;
{*****************************************************************************
AddMMX
*****************************************************************************}
{$ifdef SUPPORT_MMX}
procedure ti386addnode.second_addmmx;
var
op : TAsmOp;
pushedfpu,
cmpop : boolean;
mmxbase : tmmxtype;
hregister : tregister;
begin
pass_left_and_right(pushedfpu);
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;
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) then
begin
if (right.location.loc=LOC_MMXREGISTER) then
begin
location_swap(left.location,right.location);
toggleflag(nf_swaped);
end
else
begin
{ register variable ? }
if (left.location.loc=LOC_CMMXREGISTER) then
begin
hregister:=rg.getregistermm(exprasmlist);
emit_reg_reg(A_MOVQ,S_NO,left.location.register,hregister);
end
else
begin
if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
internalerror(200203245);
location_release(exprasmlist,left.location);
hregister:=rg.getregistermm(exprasmlist);
emit_ref_reg(A_MOVQ,S_NO,left.location.reference,hregister);
end;
location_reset(left.location,LOC_MMXREGISTER,OS_NO);
left.location.register:=hregister;
end;
end;
{ at this point, left.location.loc should be LOC_MMXREGISTER }
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,left.location.register,R_MM7);
emit_reg_reg(A_MOVQ,S_NO,R_MM7,left.location.register);
end
else
begin
if not(left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
internalerror(200203247);
emit_ref_reg(A_MOVQ,S_NO,right.location.reference,R_MM7);
emit_reg_reg(op,S_NO,left.location.register,R_MM7);
emit_reg_reg(A_MOVQ,S_NO,R_MM7,left.location.register);
location_release(exprasmlist,right.location);
end;
end
else
begin
if (right.location.loc=LOC_CMMXREGISTER) then
begin
emit_reg_reg(op,S_NO,right.location.register,left.location.register);
end
else
begin
if not(right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
internalerror(200203246);
emit_ref_reg(op,S_NO,right.location.reference,left.location.register);
location_release(exprasmlist,right.location);
end;
end;
end
else
begin
{ right.location=LOC_MMXREGISTER }
if (nodetype=subn) and (nf_swaped in flags) then
begin
emit_reg_reg(op,S_NO,left.location.register,right.location.register);
location_swap(left.location,right.location);
toggleflag(nf_swaped);
end
else
begin
emit_reg_reg(op,S_NO,right.location.register,left.location.register);
end;
end;
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
if cmpop then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
set_result_location(cmpop,true);
end;
{$endif SUPPORT_MMX}
{*****************************************************************************
pass_2
*****************************************************************************}
procedure ti386addnode.pass_2;
{ is also being used for xor, and "mul", "sub, or and comparative }
{ operators }
var
popeax,popedx,
pushedfpu,
mboverflow,cmpop : boolean;
op : tasmop;
power : longint;
opsize : topsize;
{ true, if unsigned types are compared }
unsigned : 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;
regstopush: tregisterset;
begin
{ to make it more readable, string and set (not smallset!) have their
own procedures }
case left.resulttype.def.deftype of
orddef :
begin
{ handling boolean expressions }
if is_boolean(left.resulttype.def) and
is_boolean(right.resulttype.def) then
begin
second_addboolean;
exit;
end
{ 64bit operations }
else if is_64bitint(left.resulttype.def) then
begin
second_add64bit;
exit;
end;
end;
stringdef :
begin
second_addstring;
exit;
end;
setdef :
begin
{ normalsets are already handled in pass1 }
if (tsetdef(left.resulttype.def).settype<>smallset) then
internalerror(200109041);
second_addsmallset;
exit;
end;
arraydef :
begin
{$ifdef SUPPORT_MMX}
if is_mmx_able_array(left.resulttype.def) then
begin
second_addmmx;
exit;
end;
{$endif SUPPORT_MMX}
end;
floatdef :
begin
second_addfloat;
exit;
end;
end;
{ defaults }
{is_in_dest:=false;}
extra_not:=false;
mboverflow:=false;
cmpop:=false;
unsigned:=not(is_signed(left.resulttype.def)) or
not(is_signed(right.resulttype.def));
opsize:=def_opsize(left.resulttype.def);
pass_left_and_right(pushedfpu);
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 in [s32bit,u32bit])) or
((right.resulttype.def.deftype=orddef) and
(torddef(right.resulttype.def).typ in [s32bit,u32bit])) then
begin
case nodetype of
addn :
begin
op:=A_ADD;
mboverflow:=true;
end;
muln :
begin
if unsigned then
op:=A_MUL
else
op:=A_IMUL;
mboverflow:=true;
end;
subn :
begin
op:=A_SUB;
mboverflow:=true;
end;
ltn,lten,
gtn,gten,
equaln,unequaln :
begin
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) }
{ the location.register will be filled in later (JM) }
location_reset(location,LOC_REGISTER,OS_INT);
{$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) }
location_release(exprasmlist,right.location);
location.register:=rg.getregisterint(exprasmlist);
cg.a_load_loc_reg(exprasmlist,right.location,location.register);
cg.a_op_const_reg(exprasmlist,OP_SHL,power,location.register);
End
Else
Begin
{$EndIf NoShlMul}
regstopush := all_registers;
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 rg.unusedregsint) and
(R_EAX in regstopush) then
begin
emit_reg(A_PUSH,S_L,R_EAX);
popeax:=true;
end;
if not(R_EDX in rg.unusedregsint) and
(R_EDX in regstopush) then
begin
emit_reg(A_PUSH,S_L,R_EDX);
popedx:=true;
end;
{ left.location can be R_EAX !!! }
rg.getexplicitregisterint(exprasmlist,R_EDI);
{ load the left value }
cg.a_load_loc_reg(exprasmlist,left.location,R_EDI);
location_release(exprasmlist,left.location);
{ allocate EAX }
if R_EAX in rg.unusedregsint then
exprasmList.concat(Tairegalloc.Alloc(R_EAX));
{ load he right value }
cg.a_load_loc_reg(exprasmlist,right.location,R_EAX);
location_release(exprasmlist,right.location);
{ allocate EAX if it isn't yet allocated (JM) }
if (R_EAX in rg.unusedregsint) then
exprasmList.concat(Tairegalloc.Alloc(R_EAX));
{ also allocate EDX, since it is also modified by }
{ a mul (JM) }
if R_EDX in rg.unusedregsint then
exprasmList.concat(Tairegalloc.Alloc(R_EDX));
emit_reg(A_MUL,S_L,R_EDI);
rg.ungetregisterint(exprasmlist,R_EDI);
if R_EDX in rg.unusedregsint then
exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
if R_EAX in rg.unusedregsint then
exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
location.register:=rg.getregisterint(exprasmlist);
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}
location_freetemp(exprasmlist,left.location);
location_freetemp(exprasmlist,right.location);
exit;
end;
{ Convert flags to register first }
if (left.location.loc=LOC_FLAGS) then
location_force_reg(exprasmlist,left.location,opsize_2_cgsize[opsize],false);
if (right.location.loc=LOC_FLAGS) then
location_force_reg(exprasmlist,right.location,opsize_2_cgsize[opsize],false);
left_must_be_reg(opsize,false);
emit_generic_code(op,opsize,unsigned,extra_not,mboverflow);
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
if cmpop and
(left.location.loc<>LOC_CREGISTER) then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
set_result_location(cmpop,unsigned);
end
{ 8/16 bit enum,char,wchar types }
else
if ((left.resulttype.def.deftype=orddef) and
(torddef(left.resulttype.def).typ in [uchar,uwidechar])) or
((left.resulttype.def.deftype=enumdef) and
((left.resulttype.def.size=1) or
(left.resulttype.def.size=2))) then
begin
case nodetype of
ltn,lten,gtn,gten,
equaln,unequaln :
cmpop:=true;
else
CGMessage(type_e_mismatch);
end;
left_must_be_reg(opsize,false);
emit_op_right_left(A_CMP,opsize);
location_freetemp(exprasmlist,right.location);
location_release(exprasmlist,right.location);
if left.location.loc<>LOC_CREGISTER then
begin
location_freetemp(exprasmlist,left.location);
location_release(exprasmlist,left.location);
end;
set_result_location(true,true);
end
else
CGMessage(type_e_mismatch);
end;
begin
caddnode:=ti386addnode;
end.
{
$Log$
Revision 1.35 2002-05-12 16:53:17 peter
* moved entry and exitcode to ncgutil and cgobj
* foreach gets extra argument for passing local data to the
iterator function
* -CR checks also class typecasts at runtime by changing them
into as
* fixed compiler to cycle with the -CR option
* fixed stabs with elf writer, finally the global variables can
be watched
* removed a lot of routines from cga unit and replaced them by
calls to cgobj
* u32bit-s32bit updates for and,or,xor nodes. When one element is
u32bit then the other is typecasted also to u32bit without giving
a rangecheck warning/error.
* fixed pascal calling method with reversing also the high tree in
the parast, detected by tcalcst3 test
Revision 1.34 2002/04/25 20:16:40 peter
* moved more routines from cga/n386util
Revision 1.33 2002/04/05 15:09:13 jonas
* fixed web bug 1915
Revision 1.32 2002/04/04 19:06:10 peter
* removed unused units
* use tlocation.size in cg.a_*loc*() routines
Revision 1.31 2002/04/02 17:11:35 peter
* tlocation,treference update
* LOC_CONSTANT added for better constant handling
* secondadd splitted in multiple routines
* location_force_reg added for loading a location to a register
of a specified size
* secondassignment parses now first the right and then the left node
(this is compatible with Kylix). This saves a lot of push/pop especially
with string operations
* adapted some routines to use the new cg methods
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 :=rg.getregisterint(exprasmlist);
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
}