mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-11 15:28:31 +02:00
989 lines
30 KiB
ObjectPascal
989 lines
30 KiB
ObjectPascal
{
|
|
Copyright (c) 2000-2005 by Florian Klaempfl
|
|
|
|
Type checking and register allocation for math nodes
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
****************************************************************************
|
|
}
|
|
unit nmat;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
node;
|
|
|
|
type
|
|
tmoddivnode = class(tbinopnode)
|
|
function pass_1 : tnode;override;
|
|
function pass_typecheck:tnode;override;
|
|
function simplify : tnode;override;
|
|
protected
|
|
{$ifndef cpu64bit}
|
|
{ override the following if you want to implement }
|
|
{ parts explicitely in the code generator (JM) }
|
|
function first_moddiv64bitint: tnode; virtual;
|
|
{$endif cpu64bit}
|
|
function firstoptimize: tnode; virtual;
|
|
function first_moddivint: tnode; virtual;
|
|
end;
|
|
tmoddivnodeclass = class of tmoddivnode;
|
|
|
|
tshlshrnode = class(tbinopnode)
|
|
function pass_1 : tnode;override;
|
|
function pass_typecheck:tnode;override;
|
|
function simplify : tnode;override;
|
|
{$ifndef cpu64bit}
|
|
{ override the following if you want to implement }
|
|
{ parts explicitely in the code generator (CEC)
|
|
Should return nil, if everything will be handled
|
|
in the code generator
|
|
}
|
|
function first_shlshr64bitint: tnode; virtual;
|
|
{$endif cpu64bit}
|
|
end;
|
|
tshlshrnodeclass = class of tshlshrnode;
|
|
|
|
tunaryminusnode = class(tunarynode)
|
|
constructor create(expr : tnode);virtual;
|
|
function pass_1 : tnode;override;
|
|
function pass_typecheck:tnode;override;
|
|
function simplify : tnode;override;
|
|
end;
|
|
tunaryminusnodeclass = class of tunaryminusnode;
|
|
|
|
tnotnode = class(tunarynode)
|
|
constructor create(expr : tnode);virtual;
|
|
function pass_1 : tnode;override;
|
|
function pass_typecheck:tnode;override;
|
|
function simplify : tnode;override;
|
|
{$ifdef state_tracking}
|
|
function track_state_pass(exec_known:boolean):boolean;override;
|
|
{$endif}
|
|
end;
|
|
tnotnodeclass = class of tnotnode;
|
|
|
|
var
|
|
cmoddivnode : tmoddivnodeclass;
|
|
cshlshrnode : tshlshrnodeclass;
|
|
cunaryminusnode : tunaryminusnodeclass;
|
|
cnotnode : tnotnodeclass;
|
|
|
|
implementation
|
|
|
|
uses
|
|
systems,
|
|
verbose,globals,cutils,
|
|
globtype,
|
|
symconst,symtype,symdef,symtable,
|
|
defutil,
|
|
htypechk,pass_1,
|
|
cgbase,
|
|
ncon,ncnv,ncal,nadd,
|
|
nutils;
|
|
|
|
{****************************************************************************
|
|
TMODDIVNODE
|
|
****************************************************************************}
|
|
|
|
function tmoddivnode.simplify:tnode;
|
|
var
|
|
t : tnode;
|
|
rd,ld : torddef;
|
|
rv,lv : tconstexprint;
|
|
begin
|
|
result:=nil;
|
|
|
|
if is_constintnode(right) then
|
|
begin
|
|
if tordconstnode(right).value = 1 then
|
|
begin
|
|
case nodetype of
|
|
modn:
|
|
result := cordconstnode.create(0,left.resultdef,true);
|
|
divn:
|
|
result := left.getcopy;
|
|
end;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if is_constintnode(right) and is_constintnode(left) then
|
|
begin
|
|
rd:=torddef(right.resultdef);
|
|
ld:=torddef(left.resultdef);
|
|
|
|
rv:=tordconstnode(right).value;
|
|
lv:=tordconstnode(left).value;
|
|
|
|
case nodetype of
|
|
modn:
|
|
if (torddef(ld).ordtype <> u64bit) or
|
|
(torddef(rd).ordtype <> u64bit) then
|
|
t:=genintconstnode(lv mod rv)
|
|
else
|
|
t:=genintconstnode(int64(qword(lv) mod qword(rv)));
|
|
divn:
|
|
if (torddef(ld).ordtype <> u64bit) or
|
|
(torddef(rd).ordtype <> u64bit) then
|
|
t:=genintconstnode(lv div rv)
|
|
else
|
|
t:=genintconstnode(int64(qword(lv) div qword(rv)));
|
|
end;
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tmoddivnode.pass_typecheck:tnode;
|
|
var
|
|
hp,t : tnode;
|
|
rd,ld : torddef;
|
|
rv : tconstexprint;
|
|
begin
|
|
result:=nil;
|
|
typecheckpass(left);
|
|
typecheckpass(right);
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
set_varstate(right,vs_read,[vsf_must_be_valid]);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ tp procvar support }
|
|
maybe_call_procvar(left,true);
|
|
maybe_call_procvar(right,true);
|
|
|
|
result:=simplify;
|
|
if assigned(result) then
|
|
exit;
|
|
|
|
{ allow operator overloading }
|
|
t:=self;
|
|
if isbinaryoverloaded(t) then
|
|
begin
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
|
|
{ we need 2 orddefs always }
|
|
if (left.resultdef.typ<>orddef) then
|
|
inserttypeconv(right,sinttype);
|
|
if (right.resultdef.typ<>orddef) then
|
|
inserttypeconv(right,sinttype);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
rd:=torddef(right.resultdef);
|
|
ld:=torddef(left.resultdef);
|
|
|
|
{ check for division by zero }
|
|
if is_constintnode(right) then
|
|
begin
|
|
rv:=tordconstnode(right).value;
|
|
if (rv=0) then
|
|
begin
|
|
Message(parser_e_division_by_zero);
|
|
{ recover }
|
|
rv:=1;
|
|
end;
|
|
end;
|
|
|
|
{ if one operand is a cardinal and the other is a positive constant, convert the }
|
|
{ constant to a cardinal as well so we don't have to do a 64bit division (JM) }
|
|
{ Do the same for qwords and positive constants as well, otherwise things like }
|
|
{ "qword mod 10" are evaluated with int64 as result, which is wrong if the }
|
|
{ "qword" was > high(int64) (JM) }
|
|
if (rd.ordtype in [u32bit,u64bit]) and
|
|
is_constintnode(left) and
|
|
(tordconstnode(left).value >= 0) then
|
|
begin
|
|
inserttypeconv(left,right.resultdef);
|
|
ld:=torddef(left.resultdef);
|
|
end;
|
|
if (ld.ordtype in [u32bit,u64bit]) and
|
|
is_constintnode(right) and
|
|
(tordconstnode(right).value >= 0) then
|
|
begin
|
|
inserttypeconv(right,left.resultdef);
|
|
rd:=torddef(right.resultdef);
|
|
end;
|
|
|
|
{ when there is one currency value, everything is done
|
|
using currency }
|
|
if (ld.ordtype=scurrency) or
|
|
(rd.ordtype=scurrency) then
|
|
begin
|
|
if (ld.ordtype<>scurrency) then
|
|
inserttypeconv(left,s64currencytype);
|
|
if (rd.ordtype<>scurrency) then
|
|
inserttypeconv(right,s64currencytype);
|
|
resultdef:=left.resultdef;
|
|
end
|
|
else
|
|
{$ifndef cpu64bit}
|
|
{ when there is one 64bit value, everything is done
|
|
in 64bit }
|
|
if (is_64bitint(left.resultdef) or
|
|
is_64bitint(right.resultdef)) then
|
|
begin
|
|
if is_signed(rd) or is_signed(ld) then
|
|
begin
|
|
if (ld.ordtype<>s64bit) then
|
|
inserttypeconv(left,s64inttype);
|
|
if (rd.ordtype<>s64bit) then
|
|
inserttypeconv(right,s64inttype);
|
|
end
|
|
else
|
|
begin
|
|
if (ld.ordtype<>u64bit) then
|
|
inserttypeconv(left,u64inttype);
|
|
if (rd.ordtype<>u64bit) then
|
|
inserttypeconv(right,u64inttype);
|
|
end;
|
|
resultdef:=left.resultdef;
|
|
end
|
|
else
|
|
{ when mixing cardinals and signed numbers, convert everythign to 64bit (JM) }
|
|
if ((rd.ordtype = u32bit) and
|
|
is_signed(ld)) or
|
|
((ld.ordtype = u32bit) and
|
|
is_signed(rd)) then
|
|
begin
|
|
CGMessage(type_w_mixed_signed_unsigned);
|
|
if (ld.ordtype<>s64bit) then
|
|
inserttypeconv(left,s64inttype);
|
|
if (rd.ordtype<>s64bit) then
|
|
inserttypeconv(right,s64inttype);
|
|
resultdef:=left.resultdef;
|
|
end
|
|
else
|
|
{$endif cpu64bit}
|
|
begin
|
|
{ Make everything always default singed int }
|
|
if not(rd.ordtype in [torddef(sinttype).ordtype,torddef(uinttype).ordtype]) then
|
|
inserttypeconv(right,sinttype);
|
|
if not(ld.ordtype in [torddef(sinttype).ordtype,torddef(uinttype).ordtype]) then
|
|
inserttypeconv(left,sinttype);
|
|
resultdef:=right.resultdef;
|
|
end;
|
|
|
|
{ when the result is currency we need some extra code for
|
|
division. this should not be done when the divn node is
|
|
created internally }
|
|
if (nodetype=divn) and
|
|
not(nf_is_currency in flags) and
|
|
is_currency(resultdef) then
|
|
begin
|
|
hp:=caddnode.create(muln,getcopy,cordconstnode.create(10000,s64currencytype,false));
|
|
include(hp.flags,nf_is_currency);
|
|
result:=hp;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tmoddivnode.first_moddivint: tnode;
|
|
{$ifdef cpuneedsdiv32helper}
|
|
var
|
|
procname: string[31];
|
|
begin
|
|
result := nil;
|
|
|
|
{ otherwise create a call to a helper }
|
|
if nodetype = divn then
|
|
procname := 'fpc_div_'
|
|
else
|
|
procname := 'fpc_mod_';
|
|
{ only qword needs the unsigned code, the
|
|
signed code is also used for currency }
|
|
if is_signed(resultdef) then
|
|
procname := procname + 'longint'
|
|
else
|
|
procname := procname + 'dword';
|
|
|
|
result := ccallnode.createintern(procname,ccallparanode.create(left,
|
|
ccallparanode.create(right,nil)));
|
|
left := nil;
|
|
right := nil;
|
|
firstpass(result);
|
|
end;
|
|
{$else cpuneedsdiv32helper}
|
|
begin
|
|
result:=nil;
|
|
end;
|
|
{$endif cpuneedsdiv32helper}
|
|
|
|
|
|
{$ifndef cpu64bit}
|
|
function tmoddivnode.first_moddiv64bitint: tnode;
|
|
var
|
|
procname: string[31];
|
|
begin
|
|
result := nil;
|
|
|
|
{ when currency is used set the result of the
|
|
parameters to s64bit, so they are not converted }
|
|
if is_currency(resultdef) then
|
|
begin
|
|
left.resultdef:=s64inttype;
|
|
right.resultdef:=s64inttype;
|
|
end;
|
|
|
|
{ otherwise create a call to a helper }
|
|
if nodetype = divn then
|
|
procname := 'fpc_div_'
|
|
else
|
|
procname := 'fpc_mod_';
|
|
{ only qword needs the unsigned code, the
|
|
signed code is also used for currency }
|
|
if is_signed(resultdef) then
|
|
procname := procname + 'int64'
|
|
else
|
|
procname := procname + 'qword';
|
|
|
|
result := ccallnode.createintern(procname,ccallparanode.create(left,
|
|
ccallparanode.create(right,nil)));
|
|
left := nil;
|
|
right := nil;
|
|
firstpass(result);
|
|
end;
|
|
{$endif cpu64bit}
|
|
|
|
|
|
function tmoddivnode.firstoptimize: tnode;
|
|
var
|
|
power{,shiftval} : longint;
|
|
newtype: tnodetype;
|
|
begin
|
|
result := nil;
|
|
{ divide/mod a number by a constant which is a power of 2? }
|
|
if (cs_opt_peephole in current_settings.optimizerswitches) and
|
|
(right.nodetype = ordconstn) and
|
|
{ ((nodetype = divn) or
|
|
not is_signed(resultdef)) and}
|
|
(not is_signed(resultdef)) and
|
|
ispowerof2(tordconstnode(right).value,power) then
|
|
begin
|
|
if nodetype = divn then
|
|
begin
|
|
(*
|
|
if is_signed(resultdef) then
|
|
begin
|
|
if is_64bitint(left.resultdef) then
|
|
if not (cs_opt_size in current_settings.optimizerswitches) then
|
|
shiftval := 63
|
|
else
|
|
{ the shift code is a lot bigger than the call to }
|
|
{ the divide helper }
|
|
exit
|
|
else
|
|
shiftval := 31;
|
|
{ we reuse left twice, so create once a copy of it }
|
|
{ !!! if left is a call is -> call gets executed twice }
|
|
left := caddnode.create(addn,left,
|
|
caddnode.create(andn,
|
|
cshlshrnode.create(sarn,left.getcopy,
|
|
cordconstnode.create(shiftval,sinttype,false)),
|
|
cordconstnode.create(tordconstnode(right).value-1,
|
|
right.resultdef,false)));
|
|
newtype := sarn;
|
|
end
|
|
else
|
|
*)
|
|
newtype := shrn;
|
|
tordconstnode(right).value := power;
|
|
result := cshlshrnode.create(newtype,left,right)
|
|
end
|
|
else
|
|
begin
|
|
dec(tordconstnode(right).value);
|
|
result := caddnode.create(andn,left,right);
|
|
end;
|
|
{ left and right are reused }
|
|
left := nil;
|
|
right := nil;
|
|
firstpass(result);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tmoddivnode.pass_1 : tnode;
|
|
begin
|
|
result:=nil;
|
|
firstpass(left);
|
|
firstpass(right);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ Try to optimize mod/div }
|
|
result := firstoptimize;
|
|
if assigned(result) then
|
|
exit;
|
|
|
|
{$ifndef cpu64bit}
|
|
{ 64bit }
|
|
if (left.resultdef.typ=orddef) and
|
|
(right.resultdef.typ=orddef) and
|
|
(is_64bitint(left.resultdef) or is_64bitint(right.resultdef)) then
|
|
begin
|
|
result := first_moddiv64bitint;
|
|
if assigned(result) then
|
|
exit;
|
|
expectloc:=LOC_REGISTER;
|
|
calcregisters(self,2,0,0);
|
|
end
|
|
else
|
|
{$endif cpu64bit}
|
|
begin
|
|
result := first_moddivint;
|
|
if assigned(result) then
|
|
exit;
|
|
left_right_max;
|
|
if left.registersint<=right.registersint then
|
|
inc(registersint);
|
|
end;
|
|
expectloc:=LOC_REGISTER;
|
|
end;
|
|
|
|
|
|
|
|
{****************************************************************************
|
|
TSHLSHRNODE
|
|
****************************************************************************}
|
|
|
|
function tshlshrnode.simplify:tnode;
|
|
var
|
|
t : tnode;
|
|
begin
|
|
result:=nil;
|
|
{ constant folding }
|
|
if is_constintnode(left) and is_constintnode(right) then
|
|
begin
|
|
case nodetype of
|
|
shrn:
|
|
t:=genintconstnode(tordconstnode(left).value shr tordconstnode(right).value);
|
|
shln:
|
|
t:=genintconstnode(tordconstnode(left).value shl tordconstnode(right).value);
|
|
end;
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
function tshlshrnode.pass_typecheck:tnode;
|
|
var
|
|
t : tnode;
|
|
begin
|
|
result:=nil;
|
|
typecheckpass(left);
|
|
typecheckpass(right);
|
|
set_varstate(right,vs_read,[vsf_must_be_valid]);
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ tp procvar support }
|
|
maybe_call_procvar(left,true);
|
|
maybe_call_procvar(right,true);
|
|
|
|
result:=simplify;
|
|
if assigned(result) then
|
|
exit;
|
|
|
|
{ allow operator overloading }
|
|
t:=self;
|
|
if isbinaryoverloaded(t) then
|
|
begin
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
|
|
{ calculations for ordinals < 32 bit have to be done in
|
|
32 bit for backwards compatibility. That way 'shl 33' is
|
|
the same as 'shl 1'. It's ugly but compatible with delphi/tp/gcc }
|
|
if (not is_64bit(left.resultdef)) and
|
|
(torddef(left.resultdef).ordtype<>u32bit) then
|
|
inserttypeconv(left,s32inttype);
|
|
|
|
inserttypeconv(right,sinttype);
|
|
|
|
resultdef:=left.resultdef;
|
|
end;
|
|
|
|
|
|
{$ifndef cpu64bit}
|
|
function tshlshrnode.first_shlshr64bitint: tnode;
|
|
var
|
|
procname: string[31];
|
|
begin
|
|
result := nil;
|
|
{ otherwise create a call to a helper }
|
|
if nodetype = shln then
|
|
procname := 'fpc_shl_int64'
|
|
else
|
|
procname := 'fpc_shr_int64';
|
|
{ this order of parameters works at least for the arm,
|
|
however it should work for any calling conventions (FK) }
|
|
result := ccallnode.createintern(procname,ccallparanode.create(right,
|
|
ccallparanode.create(left,nil)));
|
|
left := nil;
|
|
right := nil;
|
|
firstpass(result);
|
|
end;
|
|
{$endif cpu64bit}
|
|
|
|
|
|
function tshlshrnode.pass_1 : tnode;
|
|
var
|
|
regs : longint;
|
|
begin
|
|
result:=nil;
|
|
firstpass(left);
|
|
firstpass(right);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{$ifndef cpu64bit}
|
|
{ 64 bit ints have their own shift handling }
|
|
if is_64bit(left.resultdef) then
|
|
begin
|
|
result := first_shlshr64bitint;
|
|
if assigned(result) then
|
|
exit;
|
|
regs:=2;
|
|
end
|
|
else
|
|
{$endif cpu64bit}
|
|
begin
|
|
regs:=1
|
|
end;
|
|
|
|
if (right.nodetype<>ordconstn) then
|
|
inc(regs);
|
|
expectloc:=LOC_REGISTER;
|
|
calcregisters(self,regs,0,0);
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
TUNARYMINUSNODE
|
|
****************************************************************************}
|
|
|
|
constructor tunaryminusnode.create(expr : tnode);
|
|
begin
|
|
inherited create(unaryminusn,expr);
|
|
end;
|
|
|
|
|
|
function tunaryminusnode.simplify:tnode;
|
|
begin
|
|
result:=nil;
|
|
{ constant folding }
|
|
if is_constintnode(left) then
|
|
begin
|
|
result:=genintconstnode(-tordconstnode(left).value);
|
|
exit;
|
|
end;
|
|
if is_constrealnode(left) then
|
|
begin
|
|
trealconstnode(left).value_real:=-trealconstnode(left).value_real;
|
|
trealconstnode(left).value_currency:=-trealconstnode(left).value_currency;
|
|
result:=left;
|
|
left:=nil;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tunaryminusnode.pass_typecheck : tnode;
|
|
var
|
|
t : tnode;
|
|
begin
|
|
result:=nil;
|
|
typecheckpass(left);
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
result:=simplify;
|
|
if assigned(result) then
|
|
exit;
|
|
|
|
resultdef:=left.resultdef;
|
|
if (left.resultdef.typ=floatdef) then
|
|
begin
|
|
end
|
|
{$ifdef SUPPORT_MMX}
|
|
else if (cs_mmx in current_settings.localswitches) and
|
|
is_mmx_able_array(left.resultdef) then
|
|
begin
|
|
{ if saturation is on, left.resultdef isn't
|
|
"mmx able" (FK)
|
|
if (cs_mmx_saturation in current_settings.localswitches^) and
|
|
(torddef(tarraydef(resultdef).definition).typ in
|
|
[s32bit,u32bit]) then
|
|
CGMessage(type_e_mismatch);
|
|
}
|
|
end
|
|
{$endif SUPPORT_MMX}
|
|
{$ifndef cpu64bit}
|
|
else if is_64bit(left.resultdef) then
|
|
begin
|
|
end
|
|
{$endif cpu64bit}
|
|
else if (left.resultdef.typ=orddef) then
|
|
begin
|
|
if (torddef(left.resultdef).ordtype <> scurrency) then begin
|
|
inserttypeconv(left,sinttype);
|
|
resultdef:=left.resultdef;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
{ allow operator overloading }
|
|
t:=self;
|
|
if isunaryoverloaded(t) then
|
|
begin
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
|
|
CGMessage(type_e_mismatch);
|
|
end;
|
|
end;
|
|
|
|
{ generic code }
|
|
{ overridden by: }
|
|
{ i386 }
|
|
function tunaryminusnode.pass_1 : tnode;
|
|
var
|
|
procname: string[31];
|
|
fdef : tdef;
|
|
begin
|
|
result:=nil;
|
|
firstpass(left);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
if (cs_fp_emulation in current_settings.moduleswitches) and (left.resultdef.typ=floatdef) then
|
|
begin
|
|
if not(target_info.system in system_wince) then
|
|
begin
|
|
case tfloatdef(resultdef).floattype of
|
|
s32real:
|
|
begin
|
|
procname:='float32_sub';
|
|
fdef:=search_system_type('FLOAT32REC').typedef;
|
|
end;
|
|
s64real:
|
|
begin
|
|
procname:='float64_sub';
|
|
fdef:=search_system_type('FLOAT64').typedef;
|
|
end;
|
|
{!!! not yet implemented
|
|
s128real:
|
|
}
|
|
else
|
|
internalerror(2005082801);
|
|
end;
|
|
result:=ctypeconvnode.create_internal(ccallnode.createintern(procname,ccallparanode.create(
|
|
ctypeconvnode.create_internal(crealconstnode.create(0,resultdef),fdef),
|
|
ccallparanode.create(ctypeconvnode.create_internal(left,fDef),nil))),resultdef);
|
|
end
|
|
else
|
|
begin
|
|
case tfloatdef(resultdef).floattype of
|
|
s32real:
|
|
procname:='NEGS';
|
|
s64real:
|
|
procname:='NEGD';
|
|
{!!! not yet implemented
|
|
s128real:
|
|
}
|
|
else
|
|
internalerror(2005082802);
|
|
end;
|
|
result:=ccallnode.createintern(procname,ccallparanode.create(left,nil));
|
|
end;
|
|
|
|
left:=nil;
|
|
end
|
|
else
|
|
begin
|
|
registersint:=left.registersint;
|
|
registersfpu:=left.registersfpu;
|
|
{$ifdef SUPPORT_MMX}
|
|
registersmmx:=left.registersmmx;
|
|
{$endif SUPPORT_MMX}
|
|
|
|
if (left.resultdef.typ=floatdef) then
|
|
begin
|
|
if (left.expectloc<>LOC_REGISTER) and
|
|
(registersfpu<1) then
|
|
registersfpu:=1;
|
|
expectloc:=LOC_FPUREGISTER;
|
|
end
|
|
{$ifdef SUPPORT_MMX}
|
|
else if (cs_mmx in current_settings.localswitches) and
|
|
is_mmx_able_array(left.resultdef) then
|
|
begin
|
|
if (left.expectloc<>LOC_MMXREGISTER) and
|
|
(registersmmx<1) then
|
|
registersmmx:=1;
|
|
end
|
|
{$endif SUPPORT_MMX}
|
|
{$ifndef cpu64bit}
|
|
else if is_64bit(left.resultdef) then
|
|
begin
|
|
if (left.expectloc<>LOC_REGISTER) and
|
|
(registersint<2) then
|
|
registersint:=2;
|
|
expectloc:=LOC_REGISTER;
|
|
end
|
|
{$endif cpu64bit}
|
|
else if (left.resultdef.typ=orddef) then
|
|
begin
|
|
if (left.expectloc<>LOC_REGISTER) and
|
|
(registersint<1) then
|
|
registersint:=1;
|
|
expectloc:=LOC_REGISTER;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
{****************************************************************************
|
|
TNOTNODE
|
|
****************************************************************************}
|
|
|
|
const
|
|
boolean_reverse:array[ltn..unequaln] of Tnodetype=(
|
|
gten,gtn,lten,ltn,unequaln,equaln
|
|
);
|
|
|
|
constructor tnotnode.create(expr : tnode);
|
|
begin
|
|
inherited create(notn,expr);
|
|
end;
|
|
|
|
|
|
function tnotnode.simplify:tnode;
|
|
var
|
|
v : tconstexprint;
|
|
t : tnode;
|
|
def : tdef;
|
|
begin
|
|
result:=nil;
|
|
{ Try optmimizing ourself away }
|
|
if left.nodetype=notn then
|
|
begin
|
|
{ Double not. Remove both }
|
|
result:=Tnotnode(left).left;
|
|
tnotnode(left).left:=nil;
|
|
exit;
|
|
end;
|
|
|
|
if (left.nodetype in [ltn,lten,equaln,unequaln,gtn,gten]) then
|
|
begin
|
|
{ Not of boolean expression. Turn around the operator and remove
|
|
the not. This is not allowed for sets with the gten/lten,
|
|
because there is no ltn/gtn support }
|
|
if (taddnode(left).left.resultdef.typ<>setdef) or
|
|
(left.nodetype in [equaln,unequaln]) then
|
|
begin
|
|
result:=left;
|
|
left.nodetype:=boolean_reverse[left.nodetype];
|
|
left:=nil;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
{ constant folding }
|
|
if (left.nodetype=ordconstn) then
|
|
begin
|
|
v:=tordconstnode(left).value;
|
|
def:=left.resultdef;
|
|
case torddef(left.resultdef).ordtype of
|
|
bool8bit,
|
|
bool16bit,
|
|
bool32bit,
|
|
bool64bit:
|
|
begin
|
|
{ here we do a boolean(byte(..)) type cast because }
|
|
{ boolean(<int64>) is buggy in 1.00 }
|
|
v:=byte(not(boolean(byte(v))));
|
|
end;
|
|
uchar,
|
|
uwidechar,
|
|
u8bit,
|
|
s8bit,
|
|
u16bit,
|
|
s16bit,
|
|
u32bit,
|
|
s32bit,
|
|
s64bit,
|
|
u64bit :
|
|
begin
|
|
v:=int64(not int64(v)); { maybe qword is required }
|
|
int_to_type(v,def);
|
|
end;
|
|
else
|
|
CGMessage(type_e_mismatch);
|
|
end;
|
|
t:=cordconstnode.create(v,def,true);
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
function tnotnode.pass_typecheck : tnode;
|
|
var
|
|
t : tnode;
|
|
begin
|
|
result:=nil;
|
|
typecheckpass(left);
|
|
set_varstate(left,vs_read,[vsf_must_be_valid]);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ tp procvar support }
|
|
maybe_call_procvar(left,true);
|
|
|
|
resultdef:=left.resultdef;
|
|
|
|
result:=simplify;
|
|
if assigned(result) then
|
|
exit;
|
|
|
|
if is_boolean(resultdef) then
|
|
begin
|
|
end
|
|
else
|
|
{$ifdef SUPPORT_MMX}
|
|
if (cs_mmx in current_settings.localswitches) and
|
|
is_mmx_able_array(left.resultdef) then
|
|
begin
|
|
end
|
|
else
|
|
{$endif SUPPORT_MMX}
|
|
{$ifndef cpu64bit}
|
|
if is_64bitint(left.resultdef) then
|
|
begin
|
|
end
|
|
else
|
|
{$endif cpu64bit}
|
|
if is_integer(left.resultdef) then
|
|
begin
|
|
end
|
|
else
|
|
begin
|
|
{ allow operator overloading }
|
|
t:=self;
|
|
if isunaryoverloaded(t) then
|
|
begin
|
|
result:=t;
|
|
exit;
|
|
end;
|
|
|
|
CGMessage(type_e_mismatch);
|
|
end;
|
|
end;
|
|
|
|
|
|
function tnotnode.pass_1 : tnode;
|
|
begin
|
|
result:=nil;
|
|
firstpass(left);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
expectloc:=left.expectloc;
|
|
registersint:=left.registersint;
|
|
{$ifdef SUPPORT_MMX}
|
|
registersmmx:=left.registersmmx;
|
|
{$endif SUPPORT_MMX}
|
|
if is_boolean(resultdef) then
|
|
begin
|
|
if (expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
|
|
begin
|
|
expectloc:=LOC_REGISTER;
|
|
if (registersint<1) then
|
|
registersint:=1;
|
|
end;
|
|
{ before loading it into flags we need to load it into
|
|
a register thus 1 register is need PM }
|
|
{$ifdef cpuflags}
|
|
if left.expectloc<>LOC_JUMP then
|
|
expectloc:=LOC_FLAGS;
|
|
{$endif def cpuflags}
|
|
end
|
|
else
|
|
{$ifdef SUPPORT_MMX}
|
|
if (cs_mmx in current_settings.localswitches) and
|
|
is_mmx_able_array(left.resultdef) then
|
|
begin
|
|
if (left.expectloc<>LOC_MMXREGISTER) and
|
|
(registersmmx<1) then
|
|
registersmmx:=1;
|
|
end
|
|
else
|
|
{$endif SUPPORT_MMX}
|
|
{$ifndef cpu64bit}
|
|
if is_64bit(left.resultdef) then
|
|
begin
|
|
if (expectloc in [LOC_REFERENCE,LOC_CREFERENCE,LOC_CREGISTER]) then
|
|
begin
|
|
expectloc:=LOC_REGISTER;
|
|
if (registersint<2) then
|
|
registersint:=2;
|
|
end;
|
|
end
|
|
else
|
|
{$endif cpu64bit}
|
|
if is_integer(left.resultdef) then
|
|
begin
|
|
if (left.expectloc<>LOC_REGISTER) and
|
|
(registersint<1) then
|
|
registersint:=1;
|
|
expectloc:=LOC_REGISTER;
|
|
end;
|
|
end;
|
|
|
|
{$ifdef state_tracking}
|
|
function Tnotnode.track_state_pass(exec_known:boolean):boolean;
|
|
begin
|
|
track_state_pass:=true;
|
|
if left.track_state_pass(exec_known) then
|
|
begin
|
|
left.resultdef:=nil;
|
|
do_typecheckpass(left);
|
|
end;
|
|
end;
|
|
{$endif}
|
|
|
|
begin
|
|
cmoddivnode:=tmoddivnode;
|
|
cshlshrnode:=tshlshrnode;
|
|
cunaryminusnode:=tunaryminusnode;
|
|
cnotnode:=tnotnode;
|
|
end.
|