|
@@ -0,0 +1,493 @@
|
|
|
+{
|
|
|
+ $Id$
|
|
|
+ Copyright (c) 1998-2000 by Florian Klaempfl
|
|
|
+
|
|
|
+ Generate i386 assembler for constants
|
|
|
+
|
|
|
+ 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 n386con;
|
|
|
+
|
|
|
+{$i defines.inc}
|
|
|
+
|
|
|
+interface
|
|
|
+
|
|
|
+ uses
|
|
|
+ ncon;
|
|
|
+
|
|
|
+ type
|
|
|
+ ti386realconstnode = class(trealconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ti386fixconstnode = class(tfixconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ti386ordconstnode = class(tordconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ti386pointerconstnode = class(tpointerconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ti386stringconstnode = class(tstringconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+ ti386setconstnode = class(tsetconstnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ti386nilnode = class(tnilnode)
|
|
|
+ procedure pass_2;override;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+implementation
|
|
|
+
|
|
|
+ uses
|
|
|
+ globtype,systems,
|
|
|
+ cobjects,verbose,globals,
|
|
|
+ symconst,symtable,aasm,
|
|
|
+ hcodegen,temp_gen,pass_2,
|
|
|
+ cpubase,cpuasm,
|
|
|
+ cgai386,tgeni386;
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386REALCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386realconstnode.pass_2;
|
|
|
+ const
|
|
|
+ floattype2ait:array[tfloattype] of tait=
|
|
|
+ (ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_none,ait_none);
|
|
|
+
|
|
|
+ var
|
|
|
+ hp1 : pai;
|
|
|
+ lastlabel : pasmlabel;
|
|
|
+ realait : tait;
|
|
|
+
|
|
|
+ begin
|
|
|
+ if (value_real=1.0) then
|
|
|
+ begin
|
|
|
+ emit_none(A_FLD1,S_NO);
|
|
|
+ location.loc:=LOC_FPU;
|
|
|
+ inc(fpuvaroffset);
|
|
|
+ end
|
|
|
+ else if (value_real=0.0) then
|
|
|
+ begin
|
|
|
+ emit_none(A_FLDZ,S_NO);
|
|
|
+ location.loc:=LOC_FPU;
|
|
|
+ inc(fpuvaroffset);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ lastlabel:=nil;
|
|
|
+ realait:=floattype2ait[pfloatdef(resulttype)^.typ];
|
|
|
+ { const already used ? }
|
|
|
+ if not assigned(lab_real) then
|
|
|
+ begin
|
|
|
+ { tries to find an old entry }
|
|
|
+ hp1:=pai(consts^.first);
|
|
|
+ while assigned(hp1) do
|
|
|
+ begin
|
|
|
+ if hp1^.typ=ait_label then
|
|
|
+ lastlabel:=pai_label(hp1)^.l
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ if (hp1^.typ=realait) and (lastlabel<>nil) then
|
|
|
+ begin
|
|
|
+ if(
|
|
|
+ ((realait=ait_real_32bit) and (pai_real_32bit(hp1)^.value=value_real)) or
|
|
|
+ ((realait=ait_real_64bit) and (pai_real_64bit(hp1)^.value=value_real)) or
|
|
|
+ ((realait=ait_real_80bit) and (pai_real_80bit(hp1)^.value=value_real)) or
|
|
|
+ ((realait=ait_comp_64bit) and (pai_comp_64bit(hp1)^.value=value_real))
|
|
|
+ ) then
|
|
|
+ begin
|
|
|
+ { found! }
|
|
|
+ lab_real:=lastlabel;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ lastlabel:=nil;
|
|
|
+ end;
|
|
|
+ hp1:=pai(hp1^.next);
|
|
|
+ end;
|
|
|
+ { :-(, we must generate a new entry }
|
|
|
+ if not assigned(lab_real) then
|
|
|
+ begin
|
|
|
+ getdatalabel(lastlabel);
|
|
|
+ lab_real:=lastlabel;
|
|
|
+ if (cs_create_smart in aktmoduleswitches) then
|
|
|
+ consts^.concat(new(pai_cut,init));
|
|
|
+ consts^.concat(new(pai_label,init(lastlabel)));
|
|
|
+ case realait of
|
|
|
+ ait_real_32bit :
|
|
|
+ consts^.concat(new(pai_real_32bit,init(value_real)));
|
|
|
+ ait_real_64bit :
|
|
|
+ consts^.concat(new(pai_real_64bit,init(value_real)));
|
|
|
+ ait_real_80bit :
|
|
|
+ consts^.concat(new(pai_real_80bit,init(value_real)));
|
|
|
+ ait_comp_64bit :
|
|
|
+ consts^.concat(new(pai_comp_64bit,init(value_real)));
|
|
|
+ else
|
|
|
+ internalerror(10120);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ reset_reference(location.reference);
|
|
|
+ location.reference.symbol:=lab_real;
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386FIXCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386fixconstnode.pass_2;
|
|
|
+ begin
|
|
|
+ { an fix comma const. behaves as a memory reference }
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=value_fix;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386ORDCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386ordconstnode.pass_2;
|
|
|
+ var
|
|
|
+ l : pasmlabel;
|
|
|
+
|
|
|
+ begin
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ if is_64bitint(resulttype) then
|
|
|
+ begin
|
|
|
+ getdatalabel(l);
|
|
|
+ if (cs_create_smart in aktmoduleswitches) then
|
|
|
+ consts^.concat(new(pai_cut,init));
|
|
|
+ consts^.concat(new(pai_label,init(l)));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(lo(value))));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(hi(value))));
|
|
|
+ reset_reference(location.reference);
|
|
|
+ location.reference.symbol:=l;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { non int64 const. behaves as a memory reference }
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=value;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386POINTERCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386pointerconstnode.pass_2;
|
|
|
+ begin
|
|
|
+ { an integer const. behaves as a memory reference }
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=value;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ Ti386STRINGCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386stringconstnode.pass_2;
|
|
|
+ var
|
|
|
+ hp1 : pai;
|
|
|
+ l1,l2,
|
|
|
+ lastlabel : pasmlabel;
|
|
|
+ pc : pchar;
|
|
|
+ same_string : boolean;
|
|
|
+ l,j,
|
|
|
+ i,mylength : longint;
|
|
|
+ begin
|
|
|
+ { for empty ansistrings we could return a constant 0 }
|
|
|
+ if is_ansistring(resulttype) and
|
|
|
+ (length=0) then
|
|
|
+ begin
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=0;
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ { const already used ? }
|
|
|
+ lastlabel:=nil;
|
|
|
+ if not assigned(lab_str) then
|
|
|
+ begin
|
|
|
+ if is_shortstring(resulttype) then
|
|
|
+ mylength:=length+2
|
|
|
+ else
|
|
|
+ mylength:=length+1;
|
|
|
+ { tries to found an old entry }
|
|
|
+ hp1:=pai(consts^.first);
|
|
|
+ while assigned(hp1) do
|
|
|
+ begin
|
|
|
+ if hp1^.typ=ait_label then
|
|
|
+ lastlabel:=pai_label(hp1)^.l
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { when changing that code, be careful that }
|
|
|
+ { you don't use typed consts, which are }
|
|
|
+ { are also written to consts }
|
|
|
+ { currently, this is no problem, because }
|
|
|
+ { typed consts have no leading length or }
|
|
|
+ { they have no trailing zero }
|
|
|
+ if (hp1^.typ=ait_string) and (lastlabel<>nil) and
|
|
|
+ (pai_string(hp1)^.len=mylength) then
|
|
|
+ begin
|
|
|
+ same_string:=true;
|
|
|
+ { if shortstring then check the length byte first and
|
|
|
+ set the start index to 1 }
|
|
|
+ if is_shortstring(resulttype) then
|
|
|
+ begin
|
|
|
+ if length<>ord(pai_string(hp1)^.str[0]) then
|
|
|
+ same_string:=false;
|
|
|
+ j:=1;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ j:=0;
|
|
|
+ { don't check if the length byte was already wrong }
|
|
|
+ if same_string then
|
|
|
+ begin
|
|
|
+ for i:=0 to length do
|
|
|
+ begin
|
|
|
+ if pai_string(hp1)^.str[j]<>value_str[i] then
|
|
|
+ begin
|
|
|
+ same_string:=false;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
+ inc(j);
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ { found ? }
|
|
|
+ if same_string then
|
|
|
+ begin
|
|
|
+ lab_str:=lastlabel;
|
|
|
+ { create a new entry for ansistrings, but reuse the data }
|
|
|
+ if (stringtype in [st_ansistring,st_widestring]) then
|
|
|
+ begin
|
|
|
+ getdatalabel(l2);
|
|
|
+ consts^.concat(new(pai_label,init(l2)));
|
|
|
+ consts^.concat(new(pai_const_symbol,init(lab_str)));
|
|
|
+ { return the offset of the real string }
|
|
|
+ lab_str:=l2;
|
|
|
+ end;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ lastlabel:=nil;
|
|
|
+ end;
|
|
|
+ hp1:=pai(hp1^.next);
|
|
|
+ end;
|
|
|
+ { :-(, we must generate a new entry }
|
|
|
+ if not assigned(lab_str) then
|
|
|
+ begin
|
|
|
+ getdatalabel(lastlabel);
|
|
|
+ lab_str:=lastlabel;
|
|
|
+ if (cs_create_smart in aktmoduleswitches) then
|
|
|
+ consts^.concat(new(pai_cut,init));
|
|
|
+ consts^.concat(new(pai_label,init(lastlabel)));
|
|
|
+ { generate an ansi string ? }
|
|
|
+ case stringtype of
|
|
|
+ st_ansistring:
|
|
|
+ begin
|
|
|
+ { an empty ansi string is nil! }
|
|
|
+ if length=0 then
|
|
|
+ consts^.concat(new(pai_const,init_32bit(0)))
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ getdatalabel(l1);
|
|
|
+ getdatalabel(l2);
|
|
|
+ consts^.concat(new(pai_label,init(l2)));
|
|
|
+ consts^.concat(new(pai_const_symbol,init(l1)));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(length)));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(length)));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(-1)));
|
|
|
+ consts^.concat(new(pai_label,init(l1)));
|
|
|
+ getmem(pc,length+2);
|
|
|
+ move(value_str^,pc^,length);
|
|
|
+ pc[length]:=#0;
|
|
|
+ { to overcome this problem we set the length explicitly }
|
|
|
+ { with the ending null char }
|
|
|
+ consts^.concat(new(pai_string,init_length_pchar(pc,length+1)));
|
|
|
+ { return the offset of the real string }
|
|
|
+ lab_str:=l2;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ st_shortstring:
|
|
|
+ begin
|
|
|
+ { truncate strings larger than 255 chars }
|
|
|
+ if length>255 then
|
|
|
+ l:=255
|
|
|
+ else
|
|
|
+ l:=length;
|
|
|
+ { also length and terminating zero }
|
|
|
+ getmem(pc,l+3);
|
|
|
+ move(value_str^,pc[1],l+1);
|
|
|
+ pc[0]:=chr(l);
|
|
|
+ { to overcome this problem we set the length explicitly }
|
|
|
+ { with the ending null char }
|
|
|
+ pc[l+1]:=#0;
|
|
|
+ consts^.concat(new(pai_string,init_length_pchar(pc,l+2)));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ reset_reference(location.reference);
|
|
|
+ location.reference.symbol:=lab_str;
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386SETCONSTNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386setconstnode.pass_2;
|
|
|
+ var
|
|
|
+ hp1 : pai;
|
|
|
+ lastlabel : pasmlabel;
|
|
|
+ i : longint;
|
|
|
+ neededtyp : tait;
|
|
|
+ begin
|
|
|
+ { small sets are loaded as constants }
|
|
|
+ if psetdef(resulttype)^.settype=smallset then
|
|
|
+ begin
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=plongint(value_set)^;
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ if psetdef(resulttype)^.settype=smallset then
|
|
|
+ neededtyp:=ait_const_32bit
|
|
|
+ else
|
|
|
+ neededtyp:=ait_const_8bit;
|
|
|
+ lastlabel:=nil;
|
|
|
+ { const already used ? }
|
|
|
+ if not assigned(lab_set) then
|
|
|
+ begin
|
|
|
+ { tries to found an old entry }
|
|
|
+ hp1:=pai(consts^.first);
|
|
|
+ while assigned(hp1) do
|
|
|
+ begin
|
|
|
+ if hp1^.typ=ait_label then
|
|
|
+ lastlabel:=pai_label(hp1)^.l
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ if (lastlabel<>nil) and (hp1^.typ=neededtyp) then
|
|
|
+ begin
|
|
|
+ if (hp1^.typ=ait_const_8bit) then
|
|
|
+ begin
|
|
|
+ { compare normal set }
|
|
|
+ i:=0;
|
|
|
+ while assigned(hp1) and (i<32) do
|
|
|
+ begin
|
|
|
+ if pai_const(hp1)^.value<>value_set^[i] then
|
|
|
+ break;
|
|
|
+ inc(i);
|
|
|
+ hp1:=pai(hp1^.next);
|
|
|
+ end;
|
|
|
+ if i=32 then
|
|
|
+ begin
|
|
|
+ { found! }
|
|
|
+ lab_set:=lastlabel;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
+ { leave when the end of consts is reached, so no
|
|
|
+ hp1^.next is done }
|
|
|
+ if not assigned(hp1) then
|
|
|
+ break;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ { compare small set }
|
|
|
+ if plongint(value_set)^=pai_const(hp1)^.value then
|
|
|
+ begin
|
|
|
+ { found! }
|
|
|
+ lab_set:=lastlabel;
|
|
|
+ break;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ lastlabel:=nil;
|
|
|
+ end;
|
|
|
+ hp1:=pai(hp1^.next);
|
|
|
+ end;
|
|
|
+ { :-(, we must generate a new entry }
|
|
|
+ if not assigned(lab_set) then
|
|
|
+ begin
|
|
|
+ getdatalabel(lastlabel);
|
|
|
+ lab_set:=lastlabel;
|
|
|
+ if (cs_create_smart in aktmoduleswitches) then
|
|
|
+ consts^.concat(new(pai_cut,init));
|
|
|
+ consts^.concat(new(pai_label,init(lastlabel)));
|
|
|
+ if psetdef(resulttype)^.settype=smallset then
|
|
|
+ begin
|
|
|
+ move(value_set^,i,sizeof(longint));
|
|
|
+ consts^.concat(new(pai_const,init_32bit(i)));
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ for i:=0 to 31 do
|
|
|
+ consts^.concat(new(pai_const,init_8bit(value_set^[i])));
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ reset_reference(location.reference);
|
|
|
+ location.reference.symbol:=lab_set;
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+{*****************************************************************************
|
|
|
+ TI386NILNODE
|
|
|
+*****************************************************************************}
|
|
|
+
|
|
|
+ procedure ti386nilnode.pass_2;
|
|
|
+ begin
|
|
|
+ location.loc:=LOC_MEM;
|
|
|
+ location.reference.is_immediate:=true;
|
|
|
+ location.reference.offset:=0;
|
|
|
+ end;
|
|
|
+
|
|
|
+begin
|
|
|
+ crealconstnode:=ti386realconstnode;
|
|
|
+ cfixconstnode:=ti386fixconstnode;
|
|
|
+ cordconstnode:=ti386ordconstnode;
|
|
|
+ cpointerconstnode:=ti386pointerconstnode;
|
|
|
+ cstringconstnode:=ti386stringconstnode;
|
|
|
+ csetconstnode:=ti386setconstnode;
|
|
|
+ cnilnode:=ti386nilnode;
|
|
|
+end.
|
|
|
+{
|
|
|
+ $Log$
|
|
|
+ Revision 1.1 2000-09-28 20:48:52 florian
|
|
|
+ *** empty log message ***
|
|
|
+
|
|
|
+}
|