fpc/compiler/i8086/n8086add.pas
nickysn ddba821561 * GetNextReg(), used by 16-bit and 8-bit code generators (i8086 and avr) moved
from cpubase unit to a method in the tcg class. The reason for doing that is
  that this is now a standard part of the 16-bit and 8-bit code generators and
  moving to the tcg class allows doing extra checks (not done yet, but for
  example, in the future, we can keep track of whether there was an extra
  register allocated with getintregister and halt with an internalerror in case
  GetNextReg() is called for registers, which weren't allocated as a part of a
  sequence, therefore catching a certain class of 8-bit and 16-bit code
  generator bugs at compile time, instead of generating wrong code).
- removed GetLastReg() from avr's cpubase unit, because it isn't used for
  anything. It might be added to the tcg class, in case it's ever needed, but
  for now I've left it out.
* GetOffsetReg() and GetOffsetReg64() were also moved to the tcg unit.

git-svn-id: trunk@37180 -
2017-09-11 14:53:06 +00:00

1076 lines
41 KiB
ObjectPascal

{
Copyright (c) 2000-2002 by Florian Klaempfl
Code generation for add nodes on the i8086
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 n8086add;
{$i fpcdefs.inc}
interface
uses
node,nadd,cpubase,nx86add;
type
{ ti8086addnode }
ti8086addnode = class(tx86addnode)
function simplify(forinline: boolean) : tnode;override;
function use_generic_mul32to64: boolean; override;
function first_addpointer: tnode; override;
function first_addhugepointer: tnode;
function first_cmppointer: tnode; override;
function first_cmphugepointer: tnode;
function first_cmpfarpointer: tnode;
procedure second_addordinal; override;
procedure second_add64bit;override;
procedure second_addfarpointer;
procedure second_cmp64bit;override;
procedure second_cmp32bit;
procedure second_cmpfarpointer;
procedure second_cmpordinal;override;
procedure second_mul(unsigned: boolean);
end;
implementation
uses
globtype,systems,
cutils,verbose,globals,constexp,pass_1,
symconst,symdef,symtype,symcpu,paramgr,defutil,
aasmbase,aasmtai,aasmdata,aasmcpu,
cgbase,procinfo,
ncal,ncon,nset,cgutils,tgobj,
cga,ncgutil,cgobj,cg64f32,cgx86,
hlcgobj;
{*****************************************************************************
simplify
*****************************************************************************}
function ti8086addnode.simplify(forinline: boolean): tnode;
var
t : tnode;
lt,rt: tnodetype;
rd,ld: tdef;
rv,lv,v: tconstexprint;
begin
{ load easier access variables }
rd:=right.resultdef;
ld:=left.resultdef;
rt:=right.nodetype;
lt:=left.nodetype;
if (
(lt = pointerconstn) and is_farpointer(ld) and
is_constintnode(right) and
(nodetype in [addn,subn])
) or
(
(rt = pointerconstn) and is_farpointer(rd) and
is_constintnode(left) and
(nodetype=addn)
) or
(
(lt in [pointerconstn,niln]) and is_farpointer(ld) and
(rt in [pointerconstn,niln]) and is_farpointer(rd) and
(nodetype in [ltn,lten,gtn,gten,equaln,unequaln])
) then
begin
t:=nil;
{ load values }
case lt of
ordconstn:
lv:=tordconstnode(left).value;
pointerconstn:
lv:=tpointerconstnode(left).value;
niln:
lv:=0;
else
internalerror(2002080202);
end;
case rt of
ordconstn:
rv:=tordconstnode(right).value;
pointerconstn:
rv:=tpointerconstnode(right).value;
niln:
rv:=0;
else
internalerror(2002080203);
end;
case nodetype of
addn:
begin
v:=lv+rv;
if lt=pointerconstn then
t := cpointerconstnode.create((qword(lv) and $FFFF0000) or word(qword(v)),resultdef)
else if rt=pointerconstn then
t := cpointerconstnode.create((qword(rv) and $FFFF0000) or word(qword(v)),resultdef)
else
internalerror(2014040604);
end;
subn:
begin
v:=lv-rv;
if (lt=pointerconstn) then
{ pointer-pointer results in an integer }
if (rt=pointerconstn) then
begin
if not(nf_has_pointerdiv in flags) then
internalerror(2008030101);
{ todo: implement pointer-pointer as well }
internalerror(2014040607);
//t := cpointerconstnode.create(qword(v),resultdef);
end
else
t := cpointerconstnode.create((qword(lv) and $FFFF0000) or word(qword(v)),resultdef)
else
internalerror(2014040606);
end;
ltn:
t:=cordconstnode.create(ord(word(qword(lv))<word(qword(rv))),pasbool8type,true);
lten:
t:=cordconstnode.create(ord(word(qword(lv))<=word(qword(rv))),pasbool8type,true);
gtn:
t:=cordconstnode.create(ord(word(qword(lv))>word(qword(rv))),pasbool8type,true);
gten:
t:=cordconstnode.create(ord(word(qword(lv))>=word(qword(rv))),pasbool8type,true);
equaln:
t:=cordconstnode.create(ord(lv=rv),pasbool8type,true);
unequaln:
t:=cordconstnode.create(ord(lv<>rv),pasbool8type,true);
else
internalerror(2014040605);
end;
result:=t;
exit;
end
else
Result:=inherited simplify(forinline);
end;
{*****************************************************************************
use_generic_mul32to64
*****************************************************************************}
function ti8086addnode.use_generic_mul32to64: boolean;
begin
result := True;
end;
{ handles all multiplications }
procedure ti8086addnode.second_addordinal;
var
unsigned: boolean;
begin
unsigned:=not(is_signed(left.resultdef)) or
not(is_signed(right.resultdef));
if nodetype=muln then
second_mul(unsigned)
else if is_farpointer(left.resultdef) xor is_farpointer(right.resultdef) then
second_addfarpointer
else
inherited second_addordinal;
end;
{*****************************************************************************
Add64bit
*****************************************************************************}
procedure ti8086addnode.second_add64bit;
var
op : TOpCG;
op1,op2 : TAsmOp;
hregister,
hregister2 : tregister;
hl4 : tasmlabel;
mboverflow,
unsigned:boolean;
r:Tregister;
begin
pass_left_right;
op1:=A_NONE;
op2:=A_NONE;
mboverflow:=false;
unsigned:=((left.resultdef.typ=orddef) and
(torddef(left.resultdef).ordtype=u64bit)) or
((right.resultdef.typ=orddef) and
(torddef(right.resultdef).ordtype=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;
xorn:
op:=OP_XOR;
orn:
op:=OP_OR;
andn:
op:=OP_AND;
else
begin
{ everything should be handled in pass_1 (JM) }
internalerror(200109051);
end;
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
hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
location_reset(left.location,LOC_REGISTER,left.location.size);
left.location.register64.reglo:=hregister;
left.location.register64.reghi:=hregister2;
end
else
begin
location_swap(left.location,right.location);
toggleflag(nf_swapped);
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_swapped in flags) then
begin
cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
left.location.register64,
right.location.register64);
location_swap(left.location,right.location);
toggleflag(nf_swapped);
end
else
begin
cg64.a_op64_reg_reg(current_asmdata.CurrAsmList,op,location.size,
right.location.register64,
left.location.register64);
end;
end
else
begin
{ right.location<>LOC_REGISTER }
if (nodetype=subn) and (nf_swapped in flags) then
begin
r:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg64.a_load64low_loc_reg(current_asmdata.CurrAsmList,right.location,r);
emit_reg_reg(op1,S_W,left.location.register64.reglo,r);
emit_reg_reg(op2,S_W,cg.GetNextReg(left.location.register64.reglo),cg.GetNextReg(r));
emit_reg_reg(A_MOV,S_W,r,left.location.register64.reglo);
emit_reg_reg(A_MOV,S_W,cg.GetNextReg(r),cg.GetNextReg(left.location.register64.reglo));
cg64.a_load64high_loc_reg(current_asmdata.CurrAsmList,right.location,r);
{ the carry flag is still ok }
emit_reg_reg(op2,S_W,left.location.register64.reghi,r);
emit_reg_reg(op2,S_W,cg.GetNextReg(left.location.register64.reghi),cg.GetNextReg(r));
emit_reg_reg(A_MOV,S_W,r,left.location.register64.reghi);
emit_reg_reg(A_MOV,S_W,cg.GetNextReg(r),cg.GetNextReg(left.location.register64.reghi));
end
else
begin
cg64.a_op64_loc_reg(current_asmdata.CurrAsmList,op,location.size,right.location,
left.location.register64);
end;
location_freetemp(current_asmdata.CurrAsmList,right.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 current_settings.localswitches then
begin
current_asmdata.getjumplabel(hl4);
if unsigned then
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4)
else
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NO,hl4);
cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
cg.a_label(current_asmdata.CurrAsmList,hl4);
end;
end;
location_copy(location,left.location);
end;
function ti8086addnode.first_addpointer: tnode;
begin
if is_hugepointer(left.resultdef) or is_hugepointer(right.resultdef) then
result:=first_addhugepointer
else
result:=inherited;
end;
function ti8086addnode.first_addhugepointer: tnode;
var
procname:string;
begin
result:=nil;
if (nodetype=subn) and is_hugepointer(left.resultdef) and is_hugepointer(right.resultdef) then
procname:='fpc_hugeptr_sub_hugeptr'
else
begin
case nodetype of
addn:
procname:='fpc_hugeptr_add_longint';
subn:
procname:='fpc_hugeptr_sub_longint';
else
internalerror(2014070301);
end;
if cs_hugeptr_arithmetic_normalization in current_settings.localswitches then
procname:=procname+'_normalized';
end;
if is_hugepointer(left.resultdef) then
result := ccallnode.createintern(procname,
ccallparanode.create(right,
ccallparanode.create(left,nil)))
else
result := ccallnode.createintern(procname,
ccallparanode.create(left,
ccallparanode.create(right,nil)));
left := nil;
right := nil;
firstpass(result);
end;
function ti8086addnode.first_cmppointer: tnode;
begin
if is_hugepointer(left.resultdef) or is_hugepointer(right.resultdef) then
result:=first_cmphugepointer
else if is_farpointer(left.resultdef) or is_farpointer(right.resultdef) then
result:=first_cmpfarpointer
else
result:=inherited;
end;
function ti8086addnode.first_cmphugepointer: tnode;
var
procname:string;
begin
result:=nil;
if not (cs_hugeptr_comparison_normalization in current_settings.localswitches) then
begin
expectloc:=LOC_JUMP;
exit;
end;
case nodetype of
equaln:
procname:='fpc_hugeptr_cmp_normalized_e';
unequaln:
procname:='fpc_hugeptr_cmp_normalized_ne';
ltn:
procname:='fpc_hugeptr_cmp_normalized_b';
lten:
procname:='fpc_hugeptr_cmp_normalized_be';
gtn:
procname:='fpc_hugeptr_cmp_normalized_a';
gten:
procname:='fpc_hugeptr_cmp_normalized_ae';
else
internalerror(2014070401);
end;
result := ccallnode.createintern(procname,
ccallparanode.create(right,
ccallparanode.create(left,nil)));
left := nil;
right := nil;
firstpass(result);
end;
function ti8086addnode.first_cmpfarpointer: tnode;
begin
{ = and <> are handled as a 32-bit comparison }
if nodetype in [equaln,unequaln] then
begin
result:=nil;
expectloc:=LOC_JUMP;
end
else
begin
result:=nil;
expectloc:=LOC_FLAGS;
end;
end;
procedure ti8086addnode.second_addfarpointer;
var
tmpreg : tregister;
pointernode: tnode;
begin
pass_left_right;
force_reg_left_right(false,true);
set_result_location_reg;
if (left.resultdef.typ=pointerdef) and (right.resultdef.typ<>pointerdef) then
pointernode:=left
else if (left.resultdef.typ<>pointerdef) and (right.resultdef.typ=pointerdef) then
pointernode:=right
else
internalerror(2014040601);
if not (nodetype in [addn,subn]) then
internalerror(2014040602);
if nodetype=addn then
begin
if (right.location.loc<>LOC_CONSTANT) then
begin
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
left.location.register,right.location.register,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(pointernode.location.register),cg.GetNextReg(location.register));
end
else
begin
if pointernode=left then
begin
{ farptr_reg + int_const }
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
right.location.value,left.location.register,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
end
else
begin
{ int_reg + farptr_const }
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,
right.location.value,tmpreg);
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_16,
left.location.register,tmpreg,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(tmpreg),cg.GetNextReg(location.register));
end;
end;
end
else { subtract is a special case since its not commutative }
begin
if (nf_swapped in flags) then
swapleftright;
{ left can only be a pointer in this case, since (int-pointer) is not supported }
if pointernode<>left then
internalerror(2014040603);
if left.location.loc<>LOC_CONSTANT then
begin
if right.location.loc<>LOC_CONSTANT then
begin
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
right.location.register,left.location.register,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(pointernode.location.register),cg.GetNextReg(location.register));
end
else
begin
{ farptr_reg - int_const }
cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
right.location.value,left.location.register,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(left.location.register),cg.GetNextReg(location.register));
end;
end
else
begin
{ farptr_const - int_reg }
tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,
left.location.value,tmpreg);
cg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_16,
right.location.register,tmpreg,location.register);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,
cg.GetNextReg(tmpreg),cg.GetNextReg(location.register));
end;
end;
end;
procedure ti8086addnode.second_cmp64bit;
var
truelabel,
falselabel : tasmlabel;
hregister,
hregister2 : tregister;
href : treference;
unsigned : boolean;
procedure firstjmp64bitcmp;
var
oldnodetype : tnodetype;
begin
{$ifdef OLDREGVARS}
load_all_regvars(current_asmdata.CurrAsmList);
{$endif OLDREGVARS}
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel);
{ cheat a little bit for the negative test }
toggleflag(nf_swapped);
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel);
toggleflag(nf_swapped);
end;
lten,gten:
begin
oldnodetype:=nodetype;
if nodetype=lten then
nodetype:=ltn
else
nodetype:=gtn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel);
{ cheat for the negative test }
if nodetype=ltn then
nodetype:=gtn
else
nodetype:=ltn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel);
nodetype:=oldnodetype;
end;
equaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel);
unequaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel);
end;
end;
procedure middlejmp64bitcmp;
var
oldnodetype : tnodetype;
begin
{$ifdef OLDREGVARS}
load_all_regvars(current_asmdata.CurrAsmList);
{$endif OLDREGVARS}
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn:
begin
{ the comparisaion of the low word have to be }
{ always unsigned! }
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.truelabel);
{ cheat a little bit for the negative test }
toggleflag(nf_swapped);
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.falselabel);
toggleflag(nf_swapped);
end;
lten,gten:
begin
oldnodetype:=nodetype;
if nodetype=lten then
nodetype:=ltn
else
nodetype:=gtn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.truelabel);
{ cheat for the negative test }
if nodetype=ltn then
nodetype:=gtn
else
nodetype:=ltn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.falselabel);
nodetype:=oldnodetype;
end;
equaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel);
unequaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel);
end;
end;
procedure lastjmp64bitcmp;
begin
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn,lten,gten:
begin
{ the comparisaion of the low word have to be }
{ always unsigned! }
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
equaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
end;
unequaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
end;
end;
begin
truelabel:=nil;
falselabel:=nil;
pass_left_right;
unsigned:=((left.resultdef.typ=orddef) and
(torddef(left.resultdef).ordtype=u64bit)) or
((right.resultdef.typ=orddef) and
(torddef(right.resultdef).ordtype=u64bit));
{ we have LOC_JUMP as result }
current_asmdata.getjumplabel(truelabel);
current_asmdata.getjumplabel(falselabel);
location_reset_jump(location,truelabel,falselabel);
{ 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 (left.location.loc<>LOC_CREGISTER) then
begin
hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
hregister2:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg64.a_load64_loc_reg(current_asmdata.CurrAsmList,left.location,joinreg64(hregister,hregister2));
location_freetemp(current_asmdata.CurrAsmList,left.location);
location_reset(left.location,LOC_REGISTER,left.location.size);
left.location.register64.reglo:=hregister;
left.location.register64.reghi:=hregister2;
end;
end
else
begin
location_swap(left.location,right.location);
toggleflag(nf_swapped);
end;
end;
{ at this point, left.location.loc should be LOC_REGISTER }
if right.location.loc=LOC_REGISTER then
begin
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register64.reghi),cg.GetNextReg(left.location.register64.reghi));
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register64.reghi,left.location.register64.reghi);
middlejmp64bitcmp;
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register64.reglo),cg.GetNextReg(left.location.register64.reglo));
middlejmp64bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register64.reglo,left.location.register64.reglo);
lastjmp64bitcmp;
end
else
begin
case right.location.loc of
LOC_CREGISTER :
begin
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register64.reghi),cg.GetNextReg(left.location.register64.reghi));
firstjmp64bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register64.reghi,left.location.register64.reghi);
middlejmp64bitcmp;
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register64.reglo),cg.GetNextReg(left.location.register64.reglo));
middlejmp64bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register64.reglo,left.location.register64.reglo);
lastjmp64bitcmp;
end;
LOC_CREFERENCE,
LOC_REFERENCE :
begin
tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,right.location.reference);
href:=right.location.reference;
inc(href.offset,6);
emit_ref_reg(A_CMP,S_W,href,cg.GetNextReg(left.location.register64.reghi));
firstjmp64bitcmp;
dec(href.offset,2);
emit_ref_reg(A_CMP,S_W,href,left.location.register64.reghi);
middlejmp64bitcmp;
dec(href.offset,2);
emit_ref_reg(A_CMP,S_W,href,cg.GetNextReg(left.location.register64.reglo));
middlejmp64bitcmp;
emit_ref_reg(A_CMP,S_W,right.location.reference,left.location.register64.reglo);
lastjmp64bitcmp;
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
location_freetemp(current_asmdata.CurrAsmList,right.location);
end;
LOC_CONSTANT :
begin
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 48) and $FFFF),cg.GetNextReg(left.location.register64.reghi)));
firstjmp64bitcmp;
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 32) and $FFFF),left.location.register64.reghi));
middlejmp64bitcmp;
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value64 shr 16) and $FFFF),cg.GetNextReg(left.location.register64.reglo)));
middlejmp64bitcmp;
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint(right.location.value64 and $FFFF),left.location.register64.reglo));
lastjmp64bitcmp;
end;
else
internalerror(200203282);
end;
end;
end;
procedure ti8086addnode.second_cmp32bit;
var
truelabel,
falselabel: tasmlabel;
hregister : tregister;
href : treference;
unsigned : boolean;
procedure firstjmp32bitcmp;
var
oldnodetype : tnodetype;
begin
{$ifdef OLDREGVARS}
load_all_regvars(current_asmdata.CurrAsmList);
{$endif OLDREGVARS}
{ the jump the sequence is a little bit hairy }
case nodetype of
ltn,gtn:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel);
{ cheat a little bit for the negative test }
toggleflag(nf_swapped);
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel);
toggleflag(nf_swapped);
end;
lten,gten:
begin
oldnodetype:=nodetype;
if nodetype=lten then
nodetype:=ltn
else
nodetype:=gtn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.truelabel);
{ cheat for the negative test }
if nodetype=ltn then
nodetype:=gtn
else
nodetype:=ltn;
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(unsigned),location.falselabel);
nodetype:=oldnodetype;
end;
equaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel);
unequaln:
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel);
end;
end;
procedure secondjmp32bitcmp;
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! }
cg.a_jmp_flags(current_asmdata.CurrAsmList,getresflags(true),location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
equaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.falselabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
end;
unequaln:
begin
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_NE,location.truelabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
end;
end;
end;
begin
truelabel:=nil;
falselabel:=nil;
pass_left_right;
unsigned:=((left.resultdef.typ=orddef) and
(torddef(left.resultdef).ordtype=u32bit)) or
((right.resultdef.typ=orddef) and
(torddef(right.resultdef).ordtype=u32bit)) or
is_hugepointer(left.resultdef);
{ we have LOC_JUMP as result }
current_asmdata.getjumplabel(truelabel);
current_asmdata.getjumplabel(falselabel);
location_reset_jump(location,truelabel,falselabel);
{ 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 (left.location.loc<>LOC_CREGISTER) then
begin
hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_32,left.location,hregister);
location_freetemp(current_asmdata.CurrAsmList,left.location);
location_reset(left.location,LOC_REGISTER,left.location.size);
left.location.register:=hregister;
end;
end
else
begin
location_swap(left.location,right.location);
toggleflag(nf_swapped);
end;
end;
{ at this point, left.location.loc should be LOC_REGISTER }
if right.location.loc=LOC_REGISTER then
begin
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register),cg.GetNextReg(left.location.register));
firstjmp32bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register,left.location.register);
secondjmp32bitcmp;
end
else
begin
case right.location.loc of
LOC_CREGISTER :
begin
emit_reg_reg(A_CMP,S_W,cg.GetNextReg(right.location.register),cg.GetNextReg(left.location.register));
firstjmp32bitcmp;
emit_reg_reg(A_CMP,S_W,right.location.register,left.location.register);
secondjmp32bitcmp;
end;
LOC_CREFERENCE,
LOC_REFERENCE :
begin
tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,right.location.reference);
href:=right.location.reference;
inc(href.offset,2);
emit_ref_reg(A_CMP,S_W,href,cg.GetNextReg(left.location.register));
firstjmp32bitcmp;
dec(href.offset,2);
emit_ref_reg(A_CMP,S_W,href,left.location.register);
secondjmp32bitcmp;
cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
location_freetemp(current_asmdata.CurrAsmList,right.location);
end;
LOC_CONSTANT :
begin
if (right.location.value=0) and (nodetype in [equaln,unequaln]) and (left.location.loc=LOC_REGISTER) then
begin
current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_OR,S_W,cg.GetNextReg(left.location.register),left.location.register));
secondjmp32bitcmp;
end
else
begin
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint((right.location.value shr 16) and $FFFF),cg.GetNextReg(left.location.register)));
firstjmp32bitcmp;
current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_CMP,S_W,aint(right.location.value and $FFFF),left.location.register));
secondjmp32bitcmp;
end;
end;
else
internalerror(200203282);
end;
end;
end;
procedure ti8086addnode.second_cmpfarpointer;
begin
{ handle = and <> as a 32-bit comparison }
if nodetype in [equaln,unequaln] then
begin
second_cmp32bit;
exit;
end;
pass_left_right;
{ <, >, <= and >= compare the 16-bit offset only }
if (right.location.loc=LOC_CONSTANT) and
(left.location.loc in [LOC_REFERENCE, LOC_CREFERENCE])
then
begin
emit_const_ref(A_CMP, S_W, word(right.location.value), left.location.reference);
location_freetemp(current_asmdata.CurrAsmList,left.location);
end
else
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 right.location.loc=LOC_REGISTER then
begin
location_swap(left.location,right.location);
toggleflag(nf_swapped);
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 }
hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,u16inttype,true);
end;
end;
emit_generic_code(A_CMP,OS_16,true,false,false);
location_freetemp(current_asmdata.CurrAsmList,right.location);
location_freetemp(current_asmdata.CurrAsmList,left.location);
end;
location_reset(location,LOC_FLAGS,OS_NO);
location.resflags:=getresflags(true);
end;
procedure ti8086addnode.second_cmpordinal;
begin
if is_farpointer(left.resultdef) then
second_cmpfarpointer
else if is_32bit(left.resultdef) or is_hugepointer(left.resultdef) or is_farprocvar(left.resultdef) then
second_cmp32bit
else
inherited second_cmpordinal;
end;
{*****************************************************************************
x86 MUL
*****************************************************************************}
procedure ti8086addnode.second_mul(unsigned: boolean);
var reg:Tregister;
ref:Treference;
use_ref:boolean;
hl4 : tasmlabel;
const
asmops: array[boolean] of tasmop = (A_IMUL, A_MUL);
begin
reg:=NR_NO;
reference_reset(ref,sizeof(pint),[]);
pass_left_right;
{ MUL is faster than IMUL on the 8086 & 8088 (and equal in speed on 286+),
but it's only safe to use in place of IMUL when overflow checking is off
and we're doing a 16-bit>16-bit multiplication }
if not (cs_check_overflow in current_settings.localswitches) and
(not is_32bitint(resultdef)) then
unsigned:=true;
{The location.register will be filled in later (JM)}
location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
{ Mul supports registers and references, so if not register/reference,
load the location into a register. }
use_ref:=false;
if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
reg:=left.location.register
else if left.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
begin
tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,left.location.reference);
ref:=left.location.reference;
use_ref:=true;
end
else
begin
{LOC_CONSTANT for example.}
reg:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,left.resultdef,osuinttype,left.location,reg);
end;
{Allocate AX.}
cg.getcpuregister(current_asmdata.CurrAsmList,NR_AX);
{Load the right value.}
hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,osuinttype,right.location,NR_AX);
{Also allocate DX, since it is also modified by a mul (JM).}
cg.getcpuregister(current_asmdata.CurrAsmList,NR_DX);
if use_ref then
emit_ref(asmops[unsigned],S_W,ref)
else
emit_reg(asmops[unsigned],S_W,reg);
if (cs_check_overflow in current_settings.localswitches) and
{ 16->32 bit cannot overflow }
(not is_32bitint(resultdef)) then
begin
current_asmdata.getjumplabel(hl4);
cg.a_jmp_flags(current_asmdata.CurrAsmList,F_AE,hl4);
cg.a_call_name(current_asmdata.CurrAsmList,'FPC_OVERFLOW',false);
cg.a_label(current_asmdata.CurrAsmList,hl4);
end;
{Free AX,DX}
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_DX);
if is_32bitint(resultdef) then
begin
{Allocate an imaginary 32-bit register, which consists of a pair of
16-bit registers and store DX:AX into it}
location.register := cg.getintregister(current_asmdata.CurrAsmList,OS_32);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_DX,cg.GetNextReg(location.register));
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_AX);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_AX,location.register);
end
else
begin
{Allocate a new register and store the result in AX in it.}
location.register:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_AX);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_AX,location.register);
end;
location_freetemp(current_asmdata.CurrAsmList,left.location);
location_freetemp(current_asmdata.CurrAsmList,right.location);
end;
begin
caddnode:=ti8086addnode;
end.