2
$Id: tcmem.pas,v 1.1.2.3 2000/12/05 15:12:21 jonas Exp $
3
Copyright (c) 1998-2000 by Florian Klaempfl
5
Type checking and register allocation for memory related nodes
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
****************************************************************************
29
procedure firstloadvmt(var p : ptree);
30
procedure firsthnew(var p : ptree);
31
procedure firstnew(var p : ptree);
32
procedure firsthdispose(var p : ptree);
33
procedure firstsimplenewdispose(var p : ptree);
34
procedure firstaddr(var p : ptree);
35
procedure firstdoubleaddr(var p : ptree);
36
procedure firstderef(var p : ptree);
37
procedure firstsubscript(var p : ptree);
38
procedure firstvec(var p : ptree);
39
procedure firstself(var p : ptree);
40
procedure firstwith(var p : ptree);
47
cobjects,verbose,globals,
48
symconst,symtable,aasm,types,
49
htypechk,pass_1,cpubase
56
{*****************************************************************************
58
*****************************************************************************}
60
procedure firstloadvmt(var p : ptree);
63
p^.location.loc:=LOC_REGISTER;
67
{*****************************************************************************
69
*****************************************************************************}
71
procedure firsthnew(var p : ptree);
76
{*****************************************************************************
78
*****************************************************************************}
80
procedure firstnew(var p : ptree);
82
{ Standardeinleitung }
83
if assigned(p^.left) then
88
if assigned(p^.left) then
90
p^.registers32:=p^.left^.registers32;
91
p^.registersfpu:=p^.left^.registersfpu;
93
p^.registersmmx:=p^.left^.registersmmx;
96
{ result type is already set }
97
procinfo^.flags:=procinfo^.flags or pi_do_call;
98
if assigned(p^.left) then
99
p^.location.loc:=LOC_REGISTER
101
p^.location.loc:=LOC_REFERENCE;
105
{*****************************************************************************
107
*****************************************************************************}
109
procedure firsthdispose(var p : ptree);
116
p^.registers32:=p^.left^.registers32;
117
p^.registersfpu:=p^.left^.registersfpu;
119
p^.registersmmx:=p^.left^.registersmmx;
121
if p^.registers32<1 then
124
if p^.left^.location.loc<>LOC_REFERENCE then
125
CGMessage(cg_e_illegal_expression);
127
if p^.left^.location.loc=LOC_CREGISTER then
129
p^.location.loc:=LOC_REFERENCE;
130
p^.resulttype:=ppointerdef(p^.left^.resulttype)^.pointertype.def;
134
{*****************************************************************************
135
FirstSimpleNewDispose
136
*****************************************************************************}
138
procedure firstsimplenewdispose(var p : ptree);
140
{ this cannot be in a register !! }
141
make_not_regable(p^.left);
148
if p^.left^.resulttype=nil then
149
p^.left^.resulttype:=generrordef;
150
if (p^.left^.resulttype^.deftype<>pointerdef) then
151
CGMessage1(type_e_pointer_type_expected,p^.left^.resulttype^.typename);
153
if (p^.left^.location.loc<>LOC_REFERENCE) {and
154
(p^.left^.location.loc<>LOC_CREGISTER)} then
155
CGMessage(cg_e_illegal_expression);
157
p^.registers32:=p^.left^.registers32;
158
p^.registersfpu:=p^.left^.registersfpu;
160
p^.registersmmx:=p^.left^.registersmmx;
162
p^.resulttype:=voiddef;
163
procinfo^.flags:=procinfo^.flags or pi_do_call;
167
{*****************************************************************************
169
*****************************************************************************}
171
procedure firstaddr(var p : ptree);
175
hp3 : pabstractprocdef;
177
make_not_regable(p^.left);
178
if not(assigned(p^.resulttype)) then
180
{ tp @procvar support (type of @procvar is a void pointer)
181
Note: we need to leave the addrn in the tree,
182
else we can't see the difference between @procvar and procvar.
183
we set the procvarload flag so a secondpass does nothing for
185
if (m_tp_procvar in aktmodeswitches) then
195
{ remove calln node }
197
{ first do firstpass, then assignment in case hp }
198
{ gets changed by firstpass (JM) }
201
p^.procvarload:=true;
211
{ in case hp gets changed by firstpass (JM) }
215
if hp^.resulttype^.deftype=procvardef then
217
p^.procvarload:=true;
222
if p^.procvarload then
224
p^.registers32:=p^.left^.registers32;
225
p^.registersfpu:=p^.left^.registersfpu;
227
p^.registersmmx:=p^.left^.registersmmx;
229
if p^.registers32<1 then
231
p^.location.loc:=p^.left^.location.loc;
232
p^.resulttype:=voidpointerdef;
237
if p^.left^.treetype=calln then
239
{ generate a methodcallnode or proccallnode }
240
{ we shouldn't convert things like @tcollection.load }
241
if (p^.left^.symtableprocentry^.owner^.symtabletype=objectsymtable) and
242
not(assigned(p^.left^.methodpointer) and (p^.left^.methodpointer^.treetype=typen)) then
244
hp:=genloadmethodcallnode(pprocsym(p^.left^.symtableprocentry),p^.left^.symtableproc,
245
getcopy(p^.left^.methodpointer));
252
hp:=genloadcallnode(pprocsym(p^.left^.symtableprocentry),p^.left^.symtableproc);
254
{ result is a procedure variable }
255
{ No, to be TP compatible, you must return a pointer to
256
the procedure that is stored in the procvar.}
257
if not(m_tp_procvar in aktmodeswitches) then
259
p^.resulttype:=new(pprocvardef,init);
261
{ it could also be a procvar, not only pprocsym ! }
262
if p^.left^.symtableprocentry^.typ=varsym then
263
hp3:=pabstractprocdef(pvarsym(p^.left^.symtableentry)^.vartype.def)
265
hp3:=pabstractprocdef(pprocsym(p^.left^.symtableprocentry)^.definition);
267
pprocvardef(p^.resulttype)^.proctypeoption:=hp3^.proctypeoption;
268
pprocvardef(p^.resulttype)^.proccalloptions:=hp3^.proccalloptions;
269
pprocvardef(p^.resulttype)^.procoptions:=hp3^.procoptions;
270
pprocvardef(p^.resulttype)^.rettype:=hp3^.rettype;
271
pprocvardef(p^.resulttype)^.symtablelevel:=hp3^.symtablelevel;
273
{ method ? then set the methodpointer flag }
274
if (hp3^.owner^.symtabletype=objectsymtable) and
275
(pobjectdef(hp3^.owner^.defowner)^.is_class) then
277
include(pprocvardef(p^.resulttype)^.procoptions,po_methodpointer);
279
pprocvardef(p^.resulttype)^.procoptions:=pprocvardef(p^.resulttype)^.procoptions+[po_methodpointer];
281
{ we need to process the parameters reverse so they are inserted
282
in the correct right2left order (PFV) }
283
hp2:=pparaitem(hp3^.para^.last);
284
while assigned(hp2) do
286
pprocvardef(p^.resulttype)^.concatpara(hp2^.paratype,hp2^.paratyp);
287
hp2:=pparaitem(hp2^.previous);
291
p^.resulttype:=voidpointerdef;
293
disposetree(p^.left);
299
{ what are we getting the address from an absolute sym? }
301
while assigned(hp) and (hp^.treetype in [vecn,derefn,subscriptn]) do
303
if assigned(hp) and (hp^.treetype=loadn) and
304
((hp^.symtableentry^.typ=absolutesym) and
305
pabsolutesym(hp^.symtableentry)^.absseg) then
307
if not(cs_typed_addresses in aktlocalswitches) then
308
p^.resulttype:=voidfarpointerdef
310
p^.resulttype:=new(ppointerdef,initfardef(p^.left^.resulttype));
314
if not(cs_typed_addresses in aktlocalswitches) then
315
p^.resulttype:=voidpointerdef
317
p^.resulttype:=new(ppointerdef,initdef(p^.left^.resulttype));
322
{ this is like the function addr }
323
inc(parsing_para_level);
324
set_varstate(p^.left,false);
325
dec(parsing_para_level);
329
{ don't allow constants }
330
if is_constnode(p^.left) then
332
aktfilepos:=p^.left^.fileinfo;
333
CGMessage(type_e_no_addr_of_constant);
337
{ we should allow loc_mem for @string }
338
if not(p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
340
aktfilepos:=p^.left^.fileinfo;
341
CGMessage(cg_e_illegal_expression);
345
p^.registers32:=p^.left^.registers32;
346
p^.registersfpu:=p^.left^.registersfpu;
348
p^.registersmmx:=p^.left^.registersmmx;
350
if p^.registers32<1 then
352
{ is this right for object of methods ?? }
353
p^.location.loc:=LOC_REGISTER;
357
{*****************************************************************************
359
*****************************************************************************}
361
procedure firstdoubleaddr(var p : ptree);
363
make_not_regable(p^.left);
365
inc(parsing_para_level);
366
set_varstate(p^.left,false);
367
dec(parsing_para_level);
368
if p^.resulttype=nil then
369
p^.resulttype:=voidpointerdef;
373
if (p^.left^.resulttype^.deftype)<>procvardef then
374
CGMessage(cg_e_illegal_expression);
376
if (p^.left^.location.loc<>LOC_REFERENCE) then
377
CGMessage(cg_e_illegal_expression);
379
p^.registers32:=p^.left^.registers32;
380
p^.registersfpu:=p^.left^.registersfpu;
382
p^.registersmmx:=p^.left^.registersmmx;
384
if p^.registers32<1 then
386
p^.location.loc:=LOC_REGISTER;
390
{*****************************************************************************
392
*****************************************************************************}
394
procedure firstderef(var p : ptree);
397
set_varstate(p^.left,true);
400
p^.resulttype:=generrordef;
404
p^.registers32:=max(p^.left^.registers32,1);
405
p^.registersfpu:=p^.left^.registersfpu;
407
p^.registersmmx:=p^.left^.registersmmx;
410
if p^.left^.resulttype^.deftype<>pointerdef then
411
CGMessage(cg_e_invalid_qualifier);
413
p^.resulttype:=ppointerdef(p^.left^.resulttype)^.pointertype.def;
414
p^.location.loc:=LOC_REFERENCE;
418
{*****************************************************************************
420
*****************************************************************************}
422
procedure firstsubscript(var p : ptree);
427
p^.resulttype:=generrordef;
430
p^.resulttype:=p^.vs^.vartype.def;
432
p^.registers32:=p^.left^.registers32;
433
p^.registersfpu:=p^.left^.registersfpu;
435
p^.registersmmx:=p^.left^.registersmmx;
437
{ classes must be dereferenced implicit }
438
if (p^.left^.resulttype^.deftype=objectdef) and
439
pobjectdef(p^.left^.resulttype)^.is_class then
441
if p^.registers32=0 then
443
p^.location.loc:=LOC_REFERENCE;
447
if (p^.left^.location.loc<>LOC_MEM) and
448
(p^.left^.location.loc<>LOC_REFERENCE) then
449
CGMessage(cg_e_illegal_expression);
450
set_location(p^.location,p^.left^.location);
455
{*****************************************************************************
457
*****************************************************************************}
459
procedure firstvec(var p : ptree);
464
tcsym : ptypedconstsym;
472
{ range check only for arrays }
473
if (p^.left^.resulttype^.deftype=arraydef) then
475
if (isconvertable(p^.right^.resulttype,parraydef(p^.left^.resulttype)^.rangetype.def,
476
ct,ordconstn,false)=0) and
477
not(is_equal(p^.right^.resulttype,parraydef(p^.left^.resulttype)^.rangetype.def)) then
478
CGMessage(type_e_mismatch);
480
{ Never convert a boolean or a char !}
481
{ maybe type conversion }
482
if (p^.right^.resulttype^.deftype<>enumdef) and
483
not(is_char(p^.right^.resulttype)) and
484
not(is_boolean(p^.right^.resulttype)) then
486
p^.right:=gentypeconvnode(p^.right,s32bitdef);
492
{ are we accessing a pointer[], then convert the pointer to
493
an array first, in FPC this is allowed for all pointers in
494
delphi/tp7 it's only allowed for pchars }
495
if (p^.left^.resulttype^.deftype=pointerdef) and
496
((m_fpc in aktmodeswitches) or
497
is_pchar(p^.left^.resulttype)) then
499
{ convert pointer to array }
500
harr:=new(parraydef,init(0,$7fffffff,s32bitdef));
501
parraydef(harr)^.elementtype.def:=ppointerdef(p^.left^.resulttype)^.pointertype.def;
502
p^.left:=gentypeconvnode(p^.left,harr);
506
p^.resulttype:=parraydef(harr)^.elementtype.def
509
{ determine return type }
510
if not assigned(p^.resulttype) then
511
if p^.left^.resulttype^.deftype=arraydef then
512
p^.resulttype:=parraydef(p^.left^.resulttype)^.elementtype.def
513
else if p^.left^.resulttype^.deftype=stringdef then
515
{ indexed access to strings }
516
case pstringdef(p^.left^.resulttype)^.string_typ of
518
st_widestring : p^.resulttype:=cwchardef;
520
st_ansistring : p^.resulttype:=cchardef;
521
st_longstring : p^.resulttype:=cchardef;
522
st_shortstring : p^.resulttype:=cchardef;
526
CGMessage(type_e_array_required);
528
{ the register calculation is easy if a const index is used }
529
if p^.right^.treetype=ordconstn then
532
{ constant evaluation }
533
if (p^.left^.treetype=loadn) and
534
(p^.left^.symtableentry^.typ=typedconstsym) then
536
tcsym:=ptypedconstsym(p^.left^.symtableentry);
537
if tcsym^.defintion^.typ=stringdef then
543
p^.registers32:=p^.left^.registers32;
545
{ for ansi/wide strings, we need at least one register }
546
if is_ansistring(p^.left^.resulttype) or
547
is_widestring(p^.left^.resulttype) then
548
p^.registers32:=max(p^.registers32,1);
552
{ this rules are suboptimal, but they should give }
554
p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
556
{ for ansi/wide strings, we need at least one register }
557
if is_ansistring(p^.left^.resulttype) or
558
is_widestring(p^.left^.resulttype) then
559
p^.registers32:=max(p^.registers32,1);
561
{ need we an extra register when doing the restore ? }
562
if (p^.left^.registers32<=p^.right^.registers32) and
563
{ only if the node needs less than 3 registers }
564
{ two for the right node and one for the }
566
(p^.registers32<3) then
569
{ need we an extra register for the index ? }
570
if (p^.right^.location.loc<>LOC_REGISTER)
571
{ only if the right node doesn't need a register }
572
and (p^.right^.registers32<1) then
575
{ not correct, but what works better ?
576
if p^.left^.registers32>0 then
577
p^.registers32:=max(p^.registers32,2)
580
p^.registers32:=max(p^.registers32,1);
583
p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
585
p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
587
if p^.left^.location.loc in [LOC_CREGISTER,LOC_REFERENCE] then
588
p^.location.loc:=LOC_REFERENCE
590
p^.location.loc:=LOC_MEM;
594
{*****************************************************************************
596
*****************************************************************************}
598
procedure firstself(var p : ptree);
600
if (p^.resulttype^.deftype=classrefdef) or
601
((p^.resulttype^.deftype=objectdef)
602
and pobjectdef(p^.resulttype)^.is_class
604
p^.location.loc:=LOC_CREGISTER
606
p^.location.loc:=LOC_REFERENCE;
610
{*****************************************************************************
612
*****************************************************************************}
614
procedure firstwith(var p : ptree);
616
symtable : pwithsymtable;
619
if assigned(p^.left) and assigned(p^.right) then
622
unset_varstate(p^.left);
623
set_varstate(p^.left,true);
626
symtable:=p^.withsymtable;
627
for i:=1 to p^.tablecount do
629
if (p^.left^.treetype=loadn) and
630
(p^.left^.symtable=aktprocsym^.definition^.localst) then
631
symtable^.direct_with:=true;
632
symtable^.withnode:=p;
633
symtable:=pwithsymtable(symtable^.next);
640
p^.resulttype:=voiddef;
654
Revision 1.1.2.3 2000/12/05 15:12:21 jonas
657
Revision 1.1.2.2 2000/08/20 15:03:54 peter
658
* don't allow pointer indexing in non-fpc modes
659
* array type required message instead of type mismatch
661
Revision 1.1.2.1 2000/08/02 19:37:52 peter
662
* unset_varstate function to reset varstateset variable, fixes bug 1034
664
Revision 1.1 2000/07/13 06:30:00 michael
667
Revision 1.45 2000/04/08 09:30:01 peter
668
* fixed pointer->array conversion when resulttype was already set
670
Revision 1.44 2000/03/23 16:29:32 jonas
671
* real fix for web bug882
673
Revision 1.43 2000/03/22 15:41:10 jonas
676
Revision 1.42 2000/02/17 14:53:43 florian
677
* some updates for the newcg
679
Revision 1.41 2000/02/09 13:23:08 peter
682
Revision 1.40 2000/01/10 16:38:43 pierre
683
* suppress wrong warning for with vars
685
Revision 1.39 2000/01/10 00:42:44 pierre
688
Revision 1.38 2000/01/07 09:36:24 pierre
689
* With argument is set as used to avoid unnecessary warnings
691
Revision 1.37 2000/01/07 01:14:46 peter
692
* updated copyright to 2000
694
Revision 1.36 1999/11/30 10:40:58 peter
697
Revision 1.35 1999/11/29 22:36:48 florian
698
* problem with taking the address of abstract procedures fixed
700
Revision 1.34 1999/11/18 15:34:51 pierre
701
* Notes/Hints for local syms changed to
702
Set_varstate function
704
Revision 1.33 1999/11/17 17:05:07 pierre
705
* Notes/hints changes
707
Revision 1.32 1999/11/06 14:34:30 peter
708
* truncated log to 20 revs
710
Revision 1.31 1999/10/26 12:30:46 peter
711
* const parameter is now checked
712
* better and generic check if a node can be used for assigning
714
* procvar equal works now (it never had worked at least from 0.99.8)
715
* defcoll changed to linkedlist with pparaitem so it can easily be
716
walked both directions
718
Revision 1.30 1999/10/13 10:40:55 peter
719
* subscript support for tp_procvar
721
Revision 1.29 1999/09/27 23:45:02 peter
722
* procinfo is now a pointer
723
* support for result setting in sub procedure
725
Revision 1.28 1999/09/17 17:14:12 peter
726
* @procvar fixes for tp mode
727
* @<id>:= gives now an error
729
Revision 1.27 1999/09/11 11:10:39 florian
730
* fix of my previous commit, make cycle was broken
732
Revision 1.26 1999/09/11 09:08:34 florian
734
* fixed some problems with procedure variables and procedures of object,
735
especially in TP mode. Procedure of object doesn't apply only to classes,
736
it is also allowed for objects !!
738
Revision 1.25 1999/08/23 23:34:15 pierre
739
* one more register needed if hnewn with CREGISTER
741
Revision 1.24 1999/08/05 16:53:25 peter
742
* V_Fatal=1, all other V_ are also increased
743
* Check for local procedure when assigning procvar
744
* fixed comment parsing because directives
745
* oldtp mode directives better supported
746
* added some messages to errore.msg
748
Revision 1.23 1999/08/04 00:23:44 florian
749
* renamed i386asm and i386base to cpuasm and cpubase
751
Revision 1.22 1999/08/03 22:03:35 peter
752
* moved bitmask constants to sets
753
* some other type/const renamings