* add pinline unit that inserts compiler supported functions using

one or more statements
  * moved finalize and setlength from ninl to pinline
This commit is contained in:
peter 2002-04-23 19:16:34 +00:00
parent 451532aaed
commit 67ede1276b
11 changed files with 685 additions and 554 deletions

View File

@ -59,16 +59,11 @@ implementation
addsubop:array[in_inc_x..in_dec_x] of TOpCG=(OP_ADD,OP_SUB);
var
asmop : tasmop;
pushed : tpushedsaved;
{inc/dec}
addconstant : boolean;
addvalue : longint;
hp : tnode;
var
href,href2 : treference;
href : treference;
hp2 : tstringconstnode;
dummycoll : tparaitem;
l : longint;
ispushed : boolean;
hregisterhi,
@ -76,7 +71,6 @@ implementation
lengthlab,
otlabel,oflabel{,l1} : tasmlabel;
oldpushedparasize : longint;
def : tdef;
cgop : TOpCG;
cgsize : TCGSize;
begin
@ -276,36 +270,6 @@ implementation
emit_ref_reg(A_LEA,S_L,href,location.register);
end;
in_finalize_x:
begin
rg.saveusedregisters(exprasmlist,pushed,all_registers);
{ if a count is passed, push size, typeinfo and count }
if assigned(tcallparanode(left).right) then
begin
secondpass(tcallparanode(tcallparanode(left).right).left);
push_int(tcallparanode(left).left.resulttype.def.size);
if codegenerror then
exit;
cg.a_param_loc(exprasmlist,tcallparanode(tcallparanode(left).right).left.location,1);
end;
{ generate a reference }
reference_reset_symbol(href,tstoreddef(ttypenode(tcallparanode(left).left).resulttype.def).get_rtti_label(initrtti),0);
emitpushreferenceaddr(href);
{ data to finalize }
secondpass(tcallparanode(left).left);
if codegenerror then
exit;
emitpushreferenceaddr(tcallparanode(left).left.location.reference);
rg.saveregvars(exprasmlist,all_registers);
if assigned(tcallparanode(left).right) then
emitcall('FPC_FINALIZEARRAY')
else
emitcall('FPC_FINALIZE');
rg.restoreusedregisters(exprasmlist,pushed);
end;
in_assigned_x :
begin
secondpass(tcallparanode(left).left);
@ -323,93 +287,6 @@ implementation
location_reset(location,LOC_FLAGS,OS_NO);
location.resflags:=F_NE;
end;
in_setlength_x:
begin
rg.saveusedregisters(exprasmlist,pushed,all_registers);
l:=0;
{ push dimensions }
hp:=left;
while assigned(tcallparanode(hp).right) do
begin
inc(l);
hp:=tcallparanode(hp).right;
end;
def:=tcallparanode(hp).left.resulttype.def;
hp:=left;
if is_dynamic_array(def) then
begin
{ get temp. space }
tg.gettempofsizereference(exprasmlist,l*4,href);
{ keep data start }
href2:=href;
{ copy dimensions }
hp:=left;
while assigned(tcallparanode(hp).right) do
begin
secondpass(tcallparanode(hp).left);
location_release(exprasmlist,tcallparanode(hp).left.location);
cg.a_load_loc_ref(exprasmlist,tcallparanode(hp).left.location,href);
inc(href.offset,4);
hp:=tcallparanode(hp).right;
end;
end
else
begin
secondpass(tcallparanode(hp).left);
cg.a_param_loc(exprasmlist,tcallparanode(hp).left.location,1);
hp:=tcallparanode(hp).right;
end;
{ handle shortstrings separately since the hightree must be }
{ pushed too (JM) }
if not(is_dynamic_array(def)) and
(tstringdef(def).string_typ = st_shortstring) then
begin
dummycoll:=TParaItem.Create;
dummycoll.paratyp:=vs_var;
dummycoll.paratype:=openshortstringtype;
tcallparanode(hp).secondcallparan(dummycoll,false,false,false,0,0);
dummycoll.free;
if codegenerror then
exit;
end
else secondpass(tcallparanode(hp).left);
if is_dynamic_array(def) then
begin
emitpushreferenceaddr(href2);
push_int(l);
reference_reset_symbol(href2,tstoreddef(def).get_rtti_label(initrtti),0);
emitpushreferenceaddr(href2);
emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
rg.saveregvars(exprasmlist,all_registers);
emitcall('FPC_DYNARR_SETLENGTH');
tg.ungetiftemp(exprasmlist,href);
end
else
{ must be string }
begin
case tstringdef(def).string_typ of
st_widestring:
begin
emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
rg.saveregvars(exprasmlist,all_registers);
emitcall('FPC_WIDESTR_SETLENGTH');
end;
st_ansistring:
begin
emitpushreferenceaddr(tcallparanode(hp).left.location.reference);
rg.saveregvars(exprasmlist,all_registers);
emitcall('FPC_ANSISTR_SETLENGTH');
end;
st_shortstring:
begin
rg.saveregvars(exprasmlist,all_registers);
emitcall('FPC_SHORTSTR_SETLENGTH');
end;
end;
end;
rg.restoreusedregisters(exprasmlist,pushed);
maybe_loadself;
end;
in_include_x_y,
in_exclude_x_y:
begin
@ -591,7 +468,12 @@ begin
end.
{
$Log$
Revision 1.38 2002-04-21 15:35:54 carl
Revision 1.39 2002-04-23 19:16:35 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.38 2002/04/21 15:35:54 carl
* changeregsize -> rg.makeregsize
Revision 1.37 2002/04/19 15:39:35 peter

View File

@ -1052,7 +1052,7 @@ implementation
{ create the call to the concat routine both strings as arguments }
result := ccallnode.createintern('fpc_'+
lower(tstringdef(resulttype.def).stringtypname)+'_concat',
tstringdef(resulttype.def).stringtypname+'_concat',
ccallparanode.create(right,ccallparanode.create(left,nil)));
{ we reused the arguments }
left := nil;
@ -1097,7 +1097,7 @@ implementation
end;
{ no string constant -> call compare routine }
result := ccallnode.createintern('fpc_'+
lower(tstringdef(left.resulttype.def).stringtypname)+'_compare',
tstringdef(left.resulttype.def).stringtypname+'_compare',
ccallparanode.create(right,ccallparanode.create(left,nil)));
{ and compare its result with 0 according to the original operator }
result := caddnode.create(nodetype,result,
@ -1601,7 +1601,12 @@ begin
end.
{
$Log$
Revision 1.45 2002-04-04 19:05:56 peter
Revision 1.46 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.45 2002/04/04 19:05:56 peter
* removed unused units
* use tlocation.size in cg.a_*loc*() routines

View File

@ -109,12 +109,14 @@ interface
{ a node which is a reference to a certain temp }
ttemprefnode = class(tnode)
constructor create(const temp: ttempcreatenode); virtual;
constructor create_offset(const temp: ttempcreatenode;aoffset:longint);
function getcopy: tnode; override;
function pass_1 : tnode; override;
function det_resulttype : tnode; override;
function docompare(p: tnode): boolean; override;
protected
tempinfo: ptempinfo;
offset : longint;
end;
ttemprefnodeclass = class of ttemprefnode;
@ -543,6 +545,13 @@ implementation
begin
inherited create(temprefn);
tempinfo := temp.tempinfo;
offset:=0;
end;
constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
begin
self.create(temp);
offset := aoffset;
end;
function ttemprefnode.getcopy: tnode;
@ -570,6 +579,7 @@ implementation
function ttemprefnode.pass_1 : tnode;
begin
location.loc:=LOC_REFERENCE;
result := nil;
end;
@ -665,7 +675,12 @@ begin
end.
{
$Log$
Revision 1.21 2002-04-21 19:02:03 peter
Revision 1.22 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.21 2002/04/21 19:02:03 peter
* removed newn and disposen nodes, the code is now directly
inlined from pexpr
* -an option that will write the secondpass nodes to the .s file, this

View File

@ -263,6 +263,7 @@ interface
{ set the temp's location }
location_reset(location,LOC_REFERENCE,def_cgsize(tempinfo^.restype.def));
location.reference := tempinfo^.ref;
inc(location.reference.offset,offset);
end;
{*****************************************************************************
@ -289,7 +290,12 @@ begin
end.
{
$Log$
Revision 1.13 2002-04-21 19:02:03 peter
Revision 1.14 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.13 2002/04/21 19:02:03 peter
* removed newn and disposen nodes, the code is now directly
inlined from pexpr
* -an option that will write the secondpass nodes to the .s file, this

View File

@ -36,6 +36,7 @@ interface
totype : ttype;
convtype : tconverttype;
constructor create(node : tnode;const t : ttype);virtual;
constructor create_explicit(node : tnode;const t : ttype);
function getcopy : tnode;override;
function pass_1 : tnode;override;
function det_resulttype:tnode;override;
@ -410,6 +411,14 @@ implementation
end;
constructor ttypeconvnode.create_explicit(node : tnode;const t:ttype);
begin
self.create(node,t);
toggleflag(nf_explizit);
end;
function ttypeconvnode.getcopy : tnode;
var
@ -458,7 +467,7 @@ implementation
begin
result := ccallnode.createinternres(
'fpc_chararray_to_'+lower(tstringdef(resulttype.def).stringtypname),
'fpc_chararray_to_'+tstringdef(resulttype.def).stringtypname,
ccallparanode.create(left,nil),resulttype);
left := nil;
end;
@ -485,7 +494,7 @@ implementation
exit;
end;
result := ccallnode.createinternres(
'fpc_'+lower(tstringdef(left.resulttype.def).stringtypname)+
'fpc_'+tstringdef(left.resulttype.def).stringtypname+
'_to_chararray',ccallparanode.create(left,ccallparanode.create(
cordconstnode.create(arrsize,s32bittype),nil)),resulttype);
left := nil;
@ -532,9 +541,8 @@ implementation
else
begin
{ get the correct procedure name }
procname := 'fpc_'+
lower(tstringdef(left.resulttype.def).stringtypname+
'_to_'+tstringdef(resulttype.def).stringtypname);
procname := 'fpc_'+tstringdef(left.resulttype.def).stringtypname+
'_to_'+tstringdef(resulttype.def).stringtypname;
{ create parameter (and remove left node from typeconvnode }
{ since it's reused as parameter) }
@ -585,8 +593,7 @@ implementation
left := nil;
{ and the procname }
procname := 'fpc_char_to_' +
lower(tstringdef(resulttype.def).stringtypname);
procname := 'fpc_char_to_' +tstringdef(resulttype.def).stringtypname;
{ and finally the call }
result := ccallnode.createinternres(procname,para,resulttype);
@ -734,7 +741,7 @@ implementation
begin
result := ccallnode.createinternres(
'fpc_pchar_to_'+lower(tstringdef(resulttype.def).stringtypname),
'fpc_pchar_to_'+tstringdef(resulttype.def).stringtypname,
ccallparanode.create(left,nil),resulttype);
left := nil;
end;
@ -1705,7 +1712,12 @@ begin
end.
{
$Log$
Revision 1.52 2002-04-21 19:02:03 peter
Revision 1.53 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.52 2002/04/21 19:02:03 peter
* removed newn and disposen nodes, the code is now directly
inlined from pexpr
* -an option that will write the secondpass nodes to the .s file, this

View File

@ -201,7 +201,7 @@ implementation
left := nil;
{ create procedure name }
procname := 'fpc_' + lower(tstringdef(dest.resulttype.def).stringtypname)+'_';
procname := 'fpc_' + tstringdef(dest.resulttype.def).stringtypname+'_';
if is_real then
procname := procname + 'float'
else
@ -543,7 +543,7 @@ implementation
case para.left.resulttype.def.deftype of
stringdef :
begin
name := procprefix+lower(tstringdef(para.left.resulttype.def).stringtypname);
name := procprefix+tstringdef(para.left.resulttype.def).stringtypname;
end;
pointerdef :
begin
@ -941,7 +941,7 @@ implementation
{ play a trick to have tcallnode handle invalid source parameters: }
{ the shortstring-longint val routine by default }
if (sourcepara.resulttype.def.deftype = stringdef) then
procname := procname + lower(tstringdef(sourcepara.resulttype.def).stringtypname)
procname := procname + tstringdef(sourcepara.resulttype.def).stringtypname
else procname := procname + 'shortstr';
{ set up the correct parameters for the call: the code para... }
@ -1070,14 +1070,10 @@ implementation
end;
var
counter : longint;
ppn : tcallparanode;
dummycoll : tparaitem;
vl,vl2 : longint;
vr : bestreal;
hp : tnode;
srsym : tsym;
def : tdef;
isreal : boolean;
label
myexit;
@ -1573,81 +1569,11 @@ implementation
end;
end;
in_finalize_x,
in_setlength_x:
begin
resulttype:=voidtype;
if assigned(left) then
begin
ppn:=tcallparanode(left);
counter:=0;
{ check type }
while assigned(ppn.right) do
begin
set_varstate(ppn.left,true);
inserttypeconv(ppn.left,s32bittype);
inc(counter);
ppn:=tcallparanode(ppn.right);
end;
{ last param must be var }
valid_for_var(ppn.left);
set_varstate(ppn.left,false);
{ first param must be a string or dynamic array ...}
if not((ppn.left.resulttype.def.deftype=stringdef) or
(is_dynamic_array(ppn.left.resulttype.def))) then
CGMessage(type_e_mismatch);
{ only dynamic arrays accept more dimensions }
if (counter>1) then
if (not(is_dynamic_array(ppn.left.resulttype.def))) then
CGMessage(type_e_mismatch)
else
{ check if the amount of dimensions is valid }
begin
def := tarraydef(ppn.left.resulttype.def).elementtype.def;
while counter > 1 do
begin
if not(is_dynamic_array(def)) then
begin
CGMessage(parser_e_wrong_parameter_size);
break;
end;
dec(counter);
def := tarraydef(def).elementtype.def;
end;
end;
{ convert shortstrings to openstring parameters }
{ (generate the hightree) (JM) }
if (ppn.left.resulttype.def.deftype = stringdef) and
(tstringdef(ppn.left.resulttype.def).string_typ =
st_shortstring) then
begin
dummycoll:=tparaitem.create;
dummycoll.paratyp:=vs_var;
dummycoll.paratype:=openshortstringtype;
tcallparanode(ppn).insert_typeconv(dummycoll,false);
dummycoll.destroy;
end;
end
else
CGMessage(type_e_mismatch);
end;
in_finalize_x:
begin
resulttype:=voidtype;
if assigned(left) and assigned(tcallparanode(left).left) then
begin
{ first param must be var }
valid_for_var(tcallparanode(left).left);
set_varstate(tcallparanode(left).left,true);
{ two parameters?, the last parameter must be a longint }
if assigned(tcallparanode(left).right) then
inserttypeconv(tcallparanode(tcallparanode(left).right).left,s32bittype);
end
else
CGMessage(type_e_mismatch);
{ inlined from pinline }
internalerror(200204231);
end;
in_inc_x,
@ -2341,7 +2267,12 @@ begin
end.
{
$Log$
Revision 1.71 2002-04-02 17:11:29 peter
Revision 1.72 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.71 2002/04/02 17:11:29 peter
* tlocation,treference update
* LOC_CONSTANT added for better constant handling
* secondadd splitted in multiple routines

View File

@ -421,7 +421,7 @@ implementation
function tassignmentnode.det_resulttype:tnode;
var
hp,hp2 : tnode;
hp : tnode;
begin
result:=nil;
resulttype:=voidtype;
@ -450,12 +450,11 @@ implementation
if is_dynamic_array(left.resulttype.def) and
(right.nodetype=niln) then
begin
hp := ctypeconvnode.create(left,voidpointertype);
hp.toggleflag(nf_explizit);
hp2 := crttinode.create(tstoreddef(left.resulttype.def),initrtti);
hp := ccallparanode.create(hp2,ccallparanode.create(hp,nil));
left:=nil;
hp:=ccallparanode.create(caddrnode.create
(crttinode.create(tstoreddef(left.resulttype.def),initrtti)),
ccallparanode.create(ctypeconvnode.create_explicit(left,voidpointertype),nil));
result := ccallnode.createintern('fpc_dynarray_clear',hp);
left:=nil;
exit;
end;
@ -925,7 +924,12 @@ begin
end.
{
$Log$
Revision 1.36 2002-04-22 16:30:06 peter
Revision 1.37 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.36 2002/04/22 16:30:06 peter
* fixed @methodpointer
Revision 1.35 2002/04/21 19:02:04 peter

View File

@ -43,6 +43,8 @@ interface
procedure string_dec(var t: ttype);
function parse_paras(__colon,in_prop_paras : boolean) : tnode;
{ the ID token has to be consumed before calling this function }
procedure do_member_read(getaddr : boolean;sym : tsym;var p1 : tnode;var again : boolean);
@ -72,7 +74,7 @@ implementation
nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,nbas,
{ parser }
scanner,
pbase,
pbase,pinline,
{ codegen }
cgbase
;
@ -218,313 +220,6 @@ implementation
end;
function new_dispose_statement(is_new:boolean) : tnode;
var
newstatement : tstatementnode;
temp : ttempcreatenode;
para : tcallparanode;
p,p2 : tnode;
again : boolean; { dummy for do_proc_call }
destructorname : stringid;
sym : tsym;
classh : tobjectdef;
destructorpos,
storepos : tfileposinfo;
begin
consume(_LKLAMMER);
p:=comp_expr(true);
{ calc return type }
{ rg.cleartempgen; }
set_varstate(p,(not is_new));
{ constructor,destructor specified }
if try_to_consume(_COMMA) then
begin
{ extended syntax of new and dispose }
{ function styled new is handled in factor }
{ destructors have no parameters }
destructorname:=pattern;
destructorpos:=akttokenpos;
consume(_ID);
if (p.resulttype.def.deftype<>pointerdef) then
begin
Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
p.free;
p:=factor(false);
p.free;
consume(_RKLAMMER);
new_dispose_statement:=cerrornode.create;
exit;
end;
{ first parameter must be an object or class }
if tpointerdef(p.resulttype.def).pointertype.def.deftype<>objectdef then
begin
Message(parser_e_pointer_to_class_expected);
p.free;
new_dispose_statement:=factor(false);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
exit;
end;
{ check, if the first parameter is a pointer to a _class_ }
classh:=tobjectdef(tpointerdef(p.resulttype.def).pointertype.def);
if is_class(classh) then
begin
Message(parser_e_no_new_or_dispose_for_classes);
new_dispose_statement:=factor(false);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
exit;
end;
{ search cons-/destructor, also in parent classes }
storepos:=akttokenpos;
akttokenpos:=destructorpos;
sym:=search_class_member(classh,destructorname);
akttokenpos:=storepos;
{ the second parameter of new/dispose must be a call }
{ to a cons-/destructor }
if (not assigned(sym)) or (sym.typ<>procsym) then
begin
if is_new then
Message(parser_e_expr_have_to_be_constructor_call)
else
Message(parser_e_expr_have_to_be_destructor_call);
p.free;
new_dispose_statement:=cerrornode.create;
end
else
begin
if is_new then
p2:=chnewnode.create(tpointerdef(p.resulttype.def).pointertype)
else
p2:=chdisposenode.create(p);
do_resulttypepass(p2);
if is_new then
do_member_read(false,sym,p2,again)
else
begin
if not(m_fpc in aktmodeswitches) then
do_member_read(false,sym,p2,again)
else
begin
p2:=ccallnode.create(nil,tprocsym(sym),sym.owner,p2);
{ support dispose(p,done()); }
if try_to_consume(_LKLAMMER) then
begin
if not try_to_consume(_RKLAMMER) then
begin
Message(parser_e_no_paras_for_destructor);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
end;
end;
end;
end;
{ we need the real called method }
{ rg.cleartempgen;}
do_resulttypepass(p2);
if not codegenerror then
begin
if is_new then
begin
if (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor) then
Message(parser_e_expr_have_to_be_constructor_call);
p2.resulttype:=p.resulttype;
p2:=cassignmentnode.create(p,p2);
end
else
begin
if (tcallnode(p2).procdefinition.proctypeoption<>potype_destructor) then
Message(parser_e_expr_have_to_be_destructor_call);
end;
end;
new_dispose_statement:=p2;
end;
end
else
begin
if (p.resulttype.def.deftype<>pointerdef) then
Begin
Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
new_dispose_statement:=cerrornode.create;
end
else
begin
if (tpointerdef(p.resulttype.def).pointertype.def.deftype=objectdef) and
(oo_has_vmt in tobjectdef(tpointerdef(p.resulttype.def).pointertype.def).objectoptions) then
Message(parser_w_use_extended_syntax_for_objects);
if (tpointerdef(p.resulttype.def).pointertype.def.deftype=orddef) and
(torddef(tpointerdef(p.resulttype.def).pointertype.def).typ=uvoid) then
begin
if (m_tp7 in aktmodeswitches) or
(m_delphi in aktmodeswitches) then
Message(parser_w_no_new_dispose_on_void_pointers)
else
Message(parser_e_no_new_dispose_on_void_pointers);
end;
{ create statements with call to getmem+initialize or
finalize+freemem }
new_dispose_statement:=internalstatements(newstatement);
if is_new then
begin
{ create temp for result }
temp := ctempcreatenode.create(p.resulttype,p.resulttype.def.size,true);
addstatement(newstatement,temp);
{ create call to fpc_getmem }
para := ccallparanode.create(cordconstnode.create
(tpointerdef(p.resulttype.def).pointertype.def.size,s32bittype),nil);
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create(temp),
ccallnode.createintern('fpc_getmem',para)));
{ create call to fpc_initialize }
if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
begin
para := ccallparanode.create(caddrnode.create(crttinode.create(
tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(ctemprefnode.create
(temp),nil));
addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
end;
{ copy the temp to the destination }
addstatement(newstatement,cassignmentnode.create(
p,
ctemprefnode.create(temp)));
{ release temp }
addstatement(newstatement,ctempdeletenode.create(temp));
end
else
begin
{ create call to fpc_finalize }
if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
begin
{ we need to use a copy of p here }
para := ccallparanode.create(caddrnode.create(crttinode.create
(tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(p.getcopy,nil));
addstatement(newstatement,ccallnode.createintern('fpc_finalize',para));
end;
{ create call to fpc_freemem }
para := ccallparanode.create(p,nil);
addstatement(newstatement,ccallnode.createintern('fpc_freemem',para));
end;
end;
end;
consume(_RKLAMMER);
end;
function new_function : tnode;
var
newstatement : tstatementnode;
newblock : tblocknode;
temp : ttempcreatenode;
para : tcallparanode;
p1,p2 : tnode;
classh : tobjectdef;
sym : tsym;
again : boolean; { dummy for do_proc_call }
begin
consume(_LKLAMMER);
p1:=factor(false);
if p1.nodetype<>typen then
begin
Message(type_e_type_id_expected);
p1.destroy;
p1:=cerrornode.create;
do_resulttypepass(p1);
end;
if (p1.resulttype.def.deftype<>pointerdef) then
Message1(type_e_pointer_type_expected,p1.resulttype.def.typename)
else
if token=_RKLAMMER then
begin
if (tpointerdef(p1.resulttype.def).pointertype.def.deftype=objectdef) and
(oo_has_vmt in tobjectdef(tpointerdef(p1.resulttype.def).pointertype.def).objectoptions) then
Message(parser_w_use_extended_syntax_for_objects);
{ create statements with call to getmem+initialize }
newblock:=internalstatements(newstatement);
{ create temp for result }
temp := ctempcreatenode.create(p1.resulttype,p1.resulttype.def.size,true);
addstatement(newstatement,temp);
{ create call to fpc_getmem }
para := ccallparanode.create(cordconstnode.create
(tpointerdef(p1.resulttype.def).pointertype.def.size,s32bittype),nil);
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create(temp),
ccallnode.createintern('fpc_getmem',para)));
{ create call to fpc_initialize }
if tpointerdef(p1.resulttype.def).pointertype.def.needs_inittable then
begin
para := ccallparanode.create(caddrnode.create(crttinode.create
(tstoreddef(tpointerdef(p1.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(ctemprefnode.create
(temp),nil));
addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
end;
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
addstatement(newstatement,ctemprefnode.create(temp));
p1.destroy;
p1:=newblock;
consume(_RKLAMMER);
end
else
begin
p2:=chnewnode.create(tpointerdef(p1.resulttype.def).pointertype);
do_resulttypepass(p2);
consume(_COMMA);
afterassignment:=false;
{ determines the current object defintion }
classh:=tobjectdef(p2.resulttype.def);
if classh.deftype=objectdef then
begin
{ check for an abstract class }
if (oo_has_abstract in classh.objectoptions) then
Message(sym_e_no_instance_of_abstract_object);
{ search the constructor also in the symbol tables of
the parents }
sym:=searchsym_in_class(classh,pattern);
consume(_ID);
do_member_read(false,sym,p2,again);
{ we need to know which procedure is called }
do_resulttypepass(p2);
if (p2.nodetype<>calln) or
(assigned(tcallnode(p2).procdefinition) and
(tcallnode(p2).procdefinition.proctypeoption<>potype_constructor)) then
Message(parser_e_expr_have_to_be_constructor_call);
end
else
Message(parser_e_pointer_to_class_expected);
{ constructors return boolean, update resulttype to return
the pointer to the object }
p2.resulttype:=p1.resulttype;
p1.destroy;
p1:=p2;
consume(_RKLAMMER);
end;
new_function:=p1;
end;
function statement_syssym(l : longint) : tnode;
var
p1,p2,paras : tnode;
@ -724,7 +419,7 @@ implementation
in_finalize_x:
begin
consume(_LKLAMMER);
{ consume(_LKLAMMER);
in_args:=true;
p1:=comp_expr(true);
if token=_COMMA then
@ -737,6 +432,8 @@ implementation
p2:=ccallparanode.create(p1,p2);
statement_syssym:=geninlinenode(in_finalize_x,false,p2);
consume(_RKLAMMER);
}
statement_syssym:=inline_finalize;
end;
in_concat_x :
@ -783,17 +480,7 @@ implementation
in_setlength_x:
begin
if token=_LKLAMMER then
begin
consume(_LKLAMMER);
in_args:=true;
paras:=parse_paras(false,false);
consume(_RKLAMMER);
end
else
paras:=nil;
p1:=geninlinenode(l,false,paras);
statement_syssym := p1;
statement_syssym := inline_setlength;
end;
in_length_x:
@ -2537,7 +2224,12 @@ implementation
end.
{
$Log$
Revision 1.63 2002-04-21 19:02:05 peter
Revision 1.64 2002-04-23 19:16:34 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.63 2002/04/21 19:02:05 peter
* removed newn and disposen nodes, the code is now directly
inlined from pexpr
* -an option that will write the secondpass nodes to the .s file, this

573
compiler/pinline.pas Normal file
View File

@ -0,0 +1,573 @@
{
$Id$
Copyright (c) 1998-2001 by Florian Klaempfl
Generates nodes for routines that need compiler support
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 pinline;
{$i defines.inc}
interface
uses
symtype,
node,
globals,
cpuinfo;
function new_dispose_statement(is_new:boolean) : tnode;
function new_function : tnode;
function inline_setlength : tnode;
function inline_finalize : tnode;
implementation
uses
{$ifdef delphi}
SysUtils,
{$endif}
{ common }
cutils,
{ global }
globtype,tokens,verbose,
systems,widestr,
{ symtable }
symconst,symbase,symdef,symsym,symtable,types,
{ pass 1 }
pass_1,htypechk,
nmat,nadd,ncal,nmem,nset,ncnv,ninl,ncon,nld,nflw,nbas,
{ parser }
scanner,
pbase,pexpr,
{ codegen }
cgbase
;
function new_dispose_statement(is_new:boolean) : tnode;
var
newstatement : tstatementnode;
temp : ttempcreatenode;
para : tcallparanode;
p,p2 : tnode;
again : boolean; { dummy for do_proc_call }
destructorname : stringid;
sym : tsym;
classh : tobjectdef;
destructorpos,
storepos : tfileposinfo;
begin
consume(_LKLAMMER);
p:=comp_expr(true);
{ calc return type }
set_varstate(p,(not is_new));
{ constructor,destructor specified }
if try_to_consume(_COMMA) then
begin
{ extended syntax of new and dispose }
{ function styled new is handled in factor }
{ destructors have no parameters }
destructorname:=pattern;
destructorpos:=akttokenpos;
consume(_ID);
if (p.resulttype.def.deftype<>pointerdef) then
begin
Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
p.free;
p:=factor(false);
p.free;
consume(_RKLAMMER);
new_dispose_statement:=cerrornode.create;
exit;
end;
{ first parameter must be an object or class }
if tpointerdef(p.resulttype.def).pointertype.def.deftype<>objectdef then
begin
Message(parser_e_pointer_to_class_expected);
p.free;
new_dispose_statement:=factor(false);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
exit;
end;
{ check, if the first parameter is a pointer to a _class_ }
classh:=tobjectdef(tpointerdef(p.resulttype.def).pointertype.def);
if is_class(classh) then
begin
Message(parser_e_no_new_or_dispose_for_classes);
new_dispose_statement:=factor(false);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
exit;
end;
{ search cons-/destructor, also in parent classes }
storepos:=akttokenpos;
akttokenpos:=destructorpos;
sym:=search_class_member(classh,destructorname);
akttokenpos:=storepos;
{ the second parameter of new/dispose must be a call }
{ to a cons-/destructor }
if (not assigned(sym)) or (sym.typ<>procsym) then
begin
if is_new then
Message(parser_e_expr_have_to_be_constructor_call)
else
Message(parser_e_expr_have_to_be_destructor_call);
p.free;
new_dispose_statement:=cerrornode.create;
end
else
begin
if is_new then
p2:=chnewnode.create(tpointerdef(p.resulttype.def).pointertype)
else
p2:=chdisposenode.create(p);
do_resulttypepass(p2);
if is_new then
do_member_read(false,sym,p2,again)
else
begin
if not(m_fpc in aktmodeswitches) then
do_member_read(false,sym,p2,again)
else
begin
p2:=ccallnode.create(nil,tprocsym(sym),sym.owner,p2);
{ support dispose(p,done()); }
if try_to_consume(_LKLAMMER) then
begin
if not try_to_consume(_RKLAMMER) then
begin
Message(parser_e_no_paras_for_destructor);
consume_all_until(_RKLAMMER);
consume(_RKLAMMER);
end;
end;
end;
end;
{ we need the real called method }
{ rg.cleartempgen;}
do_resulttypepass(p2);
if not codegenerror then
begin
if is_new then
begin
if (tcallnode(p2).procdefinition.proctypeoption<>potype_constructor) then
Message(parser_e_expr_have_to_be_constructor_call);
p2.resulttype:=p.resulttype;
p2:=cassignmentnode.create(p,p2);
end
else
begin
if (tcallnode(p2).procdefinition.proctypeoption<>potype_destructor) then
Message(parser_e_expr_have_to_be_destructor_call);
end;
end;
new_dispose_statement:=p2;
end;
end
else
begin
if (p.resulttype.def.deftype<>pointerdef) then
Begin
Message1(type_e_pointer_type_expected,p.resulttype.def.typename);
new_dispose_statement:=cerrornode.create;
end
else
begin
if (tpointerdef(p.resulttype.def).pointertype.def.deftype=objectdef) and
(oo_has_vmt in tobjectdef(tpointerdef(p.resulttype.def).pointertype.def).objectoptions) then
Message(parser_w_use_extended_syntax_for_objects);
if (tpointerdef(p.resulttype.def).pointertype.def.deftype=orddef) and
(torddef(tpointerdef(p.resulttype.def).pointertype.def).typ=uvoid) then
begin
if (m_tp7 in aktmodeswitches) or
(m_delphi in aktmodeswitches) then
Message(parser_w_no_new_dispose_on_void_pointers)
else
Message(parser_e_no_new_dispose_on_void_pointers);
end;
{ create statements with call to getmem+initialize or
finalize+freemem }
new_dispose_statement:=internalstatements(newstatement);
if is_new then
begin
{ create temp for result }
temp := ctempcreatenode.create(p.resulttype,p.resulttype.def.size,true);
addstatement(newstatement,temp);
{ create call to fpc_getmem }
para := ccallparanode.create(cordconstnode.create
(tpointerdef(p.resulttype.def).pointertype.def.size,s32bittype),nil);
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create(temp),
ccallnode.createintern('fpc_getmem',para)));
{ create call to fpc_initialize }
if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
begin
para := ccallparanode.create(caddrnode.create(crttinode.create(
tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(ctemprefnode.create
(temp),nil));
addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
end;
{ copy the temp to the destination }
addstatement(newstatement,cassignmentnode.create(
p,
ctemprefnode.create(temp)));
{ release temp }
addstatement(newstatement,ctempdeletenode.create(temp));
end
else
begin
{ create call to fpc_finalize }
if tpointerdef(p.resulttype.def).pointertype.def.needs_inittable then
begin
{ we need to use a copy of p here }
para := ccallparanode.create(caddrnode.create(crttinode.create
(tstoreddef(tpointerdef(p.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(p.getcopy,nil));
addstatement(newstatement,ccallnode.createintern('fpc_finalize',para));
end;
{ create call to fpc_freemem }
para := ccallparanode.create(p,nil);
addstatement(newstatement,ccallnode.createintern('fpc_freemem',para));
end;
end;
end;
consume(_RKLAMMER);
end;
function new_function : tnode;
var
newstatement : tstatementnode;
newblock : tblocknode;
temp : ttempcreatenode;
para : tcallparanode;
p1,p2 : tnode;
classh : tobjectdef;
sym : tsym;
again : boolean; { dummy for do_proc_call }
begin
consume(_LKLAMMER);
p1:=factor(false);
if p1.nodetype<>typen then
begin
Message(type_e_type_id_expected);
p1.destroy;
p1:=cerrornode.create;
do_resulttypepass(p1);
end;
if (p1.resulttype.def.deftype<>pointerdef) then
Message1(type_e_pointer_type_expected,p1.resulttype.def.typename)
else
if token=_RKLAMMER then
begin
if (tpointerdef(p1.resulttype.def).pointertype.def.deftype=objectdef) and
(oo_has_vmt in tobjectdef(tpointerdef(p1.resulttype.def).pointertype.def).objectoptions) then
Message(parser_w_use_extended_syntax_for_objects);
{ create statements with call to getmem+initialize }
newblock:=internalstatements(newstatement);
{ create temp for result }
temp := ctempcreatenode.create(p1.resulttype,p1.resulttype.def.size,true);
addstatement(newstatement,temp);
{ create call to fpc_getmem }
para := ccallparanode.create(cordconstnode.create
(tpointerdef(p1.resulttype.def).pointertype.def.size,s32bittype),nil);
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create(temp),
ccallnode.createintern('fpc_getmem',para)));
{ create call to fpc_initialize }
if tpointerdef(p1.resulttype.def).pointertype.def.needs_inittable then
begin
para := ccallparanode.create(caddrnode.create(crttinode.create
(tstoreddef(tpointerdef(p1.resulttype.def).pointertype.def),initrtti)),
ccallparanode.create(ctemprefnode.create
(temp),nil));
addstatement(newstatement,ccallnode.createintern('fpc_initialize',para));
end;
{ the last statement should return the value as
location and type, this is done be referencing the
temp and converting it first from a persistent temp to
normal temp }
addstatement(newstatement,ctempdeletenode.create_normal_temp(temp));
addstatement(newstatement,ctemprefnode.create(temp));
p1.destroy;
p1:=newblock;
consume(_RKLAMMER);
end
else
begin
p2:=chnewnode.create(tpointerdef(p1.resulttype.def).pointertype);
do_resulttypepass(p2);
consume(_COMMA);
afterassignment:=false;
{ determines the current object defintion }
classh:=tobjectdef(p2.resulttype.def);
if classh.deftype=objectdef then
begin
{ check for an abstract class }
if (oo_has_abstract in classh.objectoptions) then
Message(sym_e_no_instance_of_abstract_object);
{ search the constructor also in the symbol tables of
the parents }
sym:=searchsym_in_class(classh,pattern);
consume(_ID);
do_member_read(false,sym,p2,again);
{ we need to know which procedure is called }
do_resulttypepass(p2);
if (p2.nodetype<>calln) or
(assigned(tcallnode(p2).procdefinition) and
(tcallnode(p2).procdefinition.proctypeoption<>potype_constructor)) then
Message(parser_e_expr_have_to_be_constructor_call);
end
else
Message(parser_e_pointer_to_class_expected);
{ constructors return boolean, update resulttype to return
the pointer to the object }
p2.resulttype:=p1.resulttype;
p1.destroy;
p1:=p2;
consume(_RKLAMMER);
end;
new_function:=p1;
end;
function inline_setlength : tnode;
var
paras : tnode;
npara,
ppn : tcallparanode;
counter : integer;
isarray : boolean;
def : tdef;
destppn : tnode;
newstatement : tstatementnode;
temp : ttempcreatenode;
newblock : tnode;
begin
{ for easy exiting if something goes wrong }
result := cerrornode.create;
consume(_LKLAMMER);
paras:=parse_paras(false,false);
consume(_RKLAMMER);
if not assigned(paras) then
begin
CGMessage(parser_e_wrong_parameter_size);
exit;
end;
counter:=0;
if assigned(paras) then
begin
{ check type of lengths }
ppn:=tcallparanode(paras);
while assigned(ppn.right) do
begin
set_varstate(ppn.left,true);
inserttypeconv(ppn.left,s32bittype);
inc(counter);
ppn:=tcallparanode(ppn.right);
end;
end;
if counter=0 then
begin
CGMessage(parser_e_wrong_parameter_size);
paras.free;
exit;
end;
{ last param must be var }
destppn:=ppn.left;
inc(parsing_para_level);
valid_for_var(destppn);
set_varstate(destppn,false);
dec(parsing_para_level);
{ first param must be a string or dynamic array ...}
isarray:=is_dynamic_array(destppn.resulttype.def);
if not((destppn.resulttype.def.deftype=stringdef) or
isarray) then
begin
CGMessage(type_e_mismatch);
paras.free;
exit;
end;
{ only dynamic arrays accept more dimensions }
if (counter>1) then
begin
if (not isarray) then
CGMessage(type_e_mismatch)
else
begin
{ check if the amount of dimensions is valid }
def := tarraydef(destppn.resulttype.def).elementtype.def;
while counter > 1 do
begin
if not(is_dynamic_array(def)) then
begin
CGMessage(parser_e_wrong_parameter_size);
break;
end;
dec(counter);
def := tarraydef(def).elementtype.def;
end;
end;
end;
if isarray then
begin
{ create statements with call initialize the arguments and
call fpc_dynarr_setlength }
newblock:=internalstatements(newstatement);
{ get temp for array of lengths }
temp := ctempcreatenode.create(s32bittype,counter*s32bittype.def.size,true);
addstatement(newstatement,temp);
{ load array of lengths }
ppn:=tcallparanode(paras);
counter:=0;
while assigned(ppn.right) do
begin
addstatement(newstatement,cassignmentnode.create(
ctemprefnode.create_offset(temp,counter*s32bittype.def.size),
ppn.left));
ppn.left:=nil;
inc(counter);
ppn:=tcallparanode(ppn.right);
end;
{ destppn is also reused }
ppn.left:=nil;
{ create call to fpc_dynarr_setlength }
npara:=ccallparanode.create(caddrnode.create
(ctemprefnode.create(temp)),
ccallparanode.create(cordconstnode.create
(counter,s32bittype),
ccallparanode.create(caddrnode.create
(crttinode.create(tstoreddef(destppn.resulttype.def),initrtti)),
ccallparanode.create(ctypeconvnode.create_explicit(destppn,voidpointertype),nil))));
addstatement(newstatement,ccallnode.createintern('fpc_dynarray_setlength',npara));
addstatement(newstatement,ctempdeletenode.create(temp));
{ we don't need original the callparanodes tree }
paras.free;
end
else
begin
{ we can reuse the supplied parameters }
newblock:=ccallnode.createintern(
'fpc_'+tstringdef(destppn.resulttype.def).stringtypname+'_setlength',paras);
end;
result.free;
result:=newblock;
end;
function inline_finalize : tnode;
var
newblock,
paras : tnode;
npara,
destppn,
ppn : tcallparanode;
begin
{ for easy exiting if something goes wrong }
result := cerrornode.create;
consume(_LKLAMMER);
paras:=parse_paras(false,false);
consume(_RKLAMMER);
if not assigned(paras) then
begin
CGMessage(parser_e_wrong_parameter_size);
exit;
end;
ppn:=tcallparanode(paras);
{ 2 arguments? }
if assigned(ppn.right) then
begin
destppn:=tcallparanode(ppn.right);
{ 3 arguments is invalid }
if assigned(destppn.right) then
begin
CGMessage(parser_e_wrong_parameter_size);
paras.free;
exit;
end;
{ create call to fpc_finalize_array }
npara:=ccallparanode.create(cordconstnode.create
(destppn.left.resulttype.def.size,s32bittype),
ccallparanode.create(ctypeconvnode.create
(ppn.left,s32bittype),
ccallparanode.create(caddrnode.create
(crttinode.create(tstoreddef(destppn.left.resulttype.def),initrtti)),
ccallparanode.create(caddrnode.create
(destppn.left),nil))));
newblock:=ccallnode.createintern('fpc_finalize_array',npara);
destppn.left:=nil;
ppn.left:=nil;
end
else
begin
{ create call to fpc_finalize }
npara:=ccallparanode.create(caddrnode.create
(crttinode.create(tstoreddef(ppn.left.resulttype.def),initrtti)),
ccallparanode.create(caddrnode.create
(ppn.left),nil));
newblock:=ccallnode.createintern('fpc_finalize',npara);
ppn.left:=nil;
end;
paras.free;
result.free;
result:=newblock;
end;
end.
{
$Log$
Revision 1.1 2002-04-23 19:16:35 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
}

View File

@ -774,15 +774,16 @@ implementation
Message1(sym_e_illegal_field,s);
error := true;
end;
if not assigned(srsym) or
(s <> srsym.name) then
if (not error) and
(not assigned(srsym) or
(s <> srsym.name)) then
{ possible variant record (JM) }
begin
{ All parts of a variant start at the same offset }
{ Also allow jumping from one variant part to another, }
{ as long as the offsets match }
if (assigned(srsym) and
(tvarsym(recsym).address = tvarsym(srsym).address)) or
(tvarsym(recsym).address = tvarsym(srsym).address)) or
{ srsym is not assigned after parsing w2 in the }
{ typed const in the next example: }
{ type tr = record case byte of }
@ -970,7 +971,12 @@ implementation
end.
{
$Log$
Revision 1.44 2002-04-20 21:32:24 carl
Revision 1.45 2002-04-23 19:16:35 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.44 2002/04/20 21:32:24 carl
+ generic FPC_CHECKPOINTER
+ first parameter offset in stack now portable
* rename some constants

View File

@ -1252,7 +1252,7 @@ implementation
function tstringdef.stringtypname:string;
const
typname:array[tstringtype] of string[8]=('',
'SHORTSTR','LONGSTR','ANSISTR','WIDESTR'
'shortstr','longstr','ansistr','widestr'
);
begin
stringtypname:=typname[string_typ];
@ -5470,7 +5470,12 @@ implementation
end.
{
$Log$
Revision 1.73 2002-04-21 19:02:05 peter
Revision 1.74 2002-04-23 19:16:35 peter
* add pinline unit that inserts compiler supported functions using
one or more statements
* moved finalize and setlength from ninl to pinline
Revision 1.73 2002/04/21 19:02:05 peter
* removed newn and disposen nodes, the code is now directly
inlined from pexpr
* -an option that will write the secondpass nodes to the .s file, this