Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / cgai386.pas
blobffb2ae73af8fe0ade58b2e100f2bd64e83d80f40
2 $Id$
3 Copyright (c) 1998-2000 by Florian Klaempfl
5 Helper routines for the i386 code generator
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 ****************************************************************************}
23 unit cgai386;
25 interface
27 uses
28 cobjects,tree,
29 cpubase,cpuasm,
30 symconst,symtable,aasm;
32 {$define TESTGETTEMP to store const that
33 are written into temps for later release PM }
35 function def_opsize(p1:pdef):topsize;
36 function def2def_opsize(p1,p2:pdef):topsize;
37 function def_getreg(p1:pdef):tregister;
38 function makereg8(r:tregister):tregister;
39 function makereg16(r:tregister):tregister;
40 function makereg32(r:tregister):tregister;
43 procedure locflags2reg(var l:tlocation;opsize:topsize);
44 procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: pasmlabel);
47 procedure emitlab(var l : pasmlabel);
48 procedure emitjmp(c : tasmcond;var l : pasmlabel);
49 procedure emit_flag2reg(flag:tresflags;hregister:tregister);
51 procedure emit_none(i : tasmop;s : topsize);
53 procedure emit_const(i : tasmop;s : topsize;c : longint);
54 procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
55 procedure emit_ref(i : tasmop;s : topsize;ref : preference);
57 procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
58 procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
59 procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
60 procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
61 procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
63 procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
64 procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
67 procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
68 procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
69 procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
70 procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
72 procedure emitcall(const routine:string);
74 procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
75 procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
76 procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
77 procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
78 procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
79 procedure emit_push_loc(const t:tlocation);
80 procedure emit_push_mem_size(const t: treference; size: longint);
82 { pushes qword location to the stack }
83 procedure emit_pushq_loc(const t : tlocation);
84 procedure release_qword_loc(const t : tlocation);
86 { remove non regvar registers in loc from regs (in the format }
87 { pushusedregisters uses) }
88 procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
89 { releases the registers of a location }
90 procedure release_loc(const t : tlocation);
92 procedure emit_pushw_loc(const t:tlocation);
93 procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
94 procedure emit_to_mem(var p:ptree);
95 procedure emit_to_reg16(var hr:tregister);
96 procedure emit_to_reg32(var hr:tregister);
97 procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
98 procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
100 procedure copyshortstring(const dref,sref : treference;len : byte;
101 loadref, del_sref: boolean);
102 procedure loadansistring(p : ptree);
104 procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
105 procedure incrstringref(t : pdef;const ref : treference);
106 procedure decrstringref(t : pdef;const ref : treference);
108 function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
109 procedure push_int(l : longint);
110 procedure emit_push_mem(const ref : treference);
111 procedure emitpushreferenceaddr(const ref : treference);
112 procedure pushsetelement(p : ptree);
113 procedure restore(p : ptree;isint64 : boolean);
114 procedure push_value_para(p:ptree;inlined,is_cdecl:boolean;
115 para_offset:longint;alignment : longint);
117 {$ifdef TEMPS_NOT_PUSH}
118 { does the same as restore/\v, but uses temp. space instead of pushing }
119 function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
120 procedure restorefromtemp(p : ptree;isint64 : boolean);
121 {$endif TEMPS_NOT_PUSH}
123 procedure floatload(t : tfloattype;const ref : treference);
124 procedure floatstore(t : tfloattype;const ref : treference);
125 procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
126 procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
128 procedure maybe_loadesi;
129 procedure maketojumpbool(p : ptree);
130 procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;destreg:Tregister;delloc:boolean);
131 procedure emitoverflowcheck(p:ptree);
132 procedure emitrangecheck(p:ptree;todef:pdef);
133 procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
134 procedure firstcomplex(p : ptree);
136 procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
137 stackframe:longint;
138 var parasize:longint;var nostackframe:boolean;
139 inlined : boolean);
140 procedure genexitcode(alist : paasmoutput;parasize:longint;
141 nostackframe,inlined:boolean);
143 { if a unit doesn't have a explicit init/final code, }
144 { we've to generate one, if the units has ansistrings }
145 { in the interface or implementation }
146 procedure genimplicitunitfinal(alist : paasmoutput);
147 procedure genimplicitunitinit(alist : paasmoutput);
148 {$ifdef test_dest_loc}
150 const
151 { used to avoid temporary assignments }
152 dest_loc_known : boolean = false;
153 in_dest_loc : boolean = false;
154 dest_loc_tree : ptree = nil;
158 dest_loc : tlocation;
160 procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
162 {$endif test_dest_loc}
164 implementation
166 uses
167 strings,globtype,systems,globals,verbose,files,types,pbase,
168 tgeni386,temp_gen,hcodegen,ppu
169 {$ifdef GDB}
170 ,gdb
171 {$endif}
172 {$ifndef NOTARGETWIN32}
173 ,t_win32
174 {$endif}
178 {*****************************************************************************
179 Helpers
180 *****************************************************************************}
182 function def_opsize(p1:pdef):topsize;
183 begin
184 case p1^.size of
185 1 : def_opsize:=S_B;
186 2 : def_opsize:=S_W;
187 4 : def_opsize:=S_L;
188 else
189 internalerror(78);
190 end;
191 end;
194 function def2def_opsize(p1,p2:pdef):topsize;
196 o1 : topsize;
197 begin
198 case p1^.size of
199 1 : o1:=S_B;
200 2 : o1:=S_W;
201 4 : o1:=S_L;
202 { I don't know if we need it (FK) }
203 8 : o1:=S_L;
204 else
205 internalerror(78);
206 end;
207 if assigned(p2) then
208 begin
209 case p2^.size of
210 1 : o1:=S_B;
211 2 : begin
212 if o1=S_B then
213 o1:=S_BW
214 else
215 o1:=S_W;
216 end;
217 4,8:
218 begin
219 case o1 of
220 S_B : o1:=S_BL;
221 S_W : o1:=S_WL;
222 end;
223 end;
224 end;
225 end;
226 def2def_opsize:=o1;
227 end;
230 function def_getreg(p1:pdef):tregister;
231 begin
232 case p1^.size of
233 1 : def_getreg:=reg32toreg8(getregister32);
234 2 : def_getreg:=reg32toreg16(getregister32);
235 4 : def_getreg:=getregister32;
236 else
237 internalerror(78);
238 end;
239 end;
242 function makereg8(r:tregister):tregister;
243 begin
244 case r of
245 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
246 makereg8:=reg32toreg8(r);
247 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
248 makereg8:=reg16toreg8(r);
249 R_AL,R_BL,R_CL,R_DL :
250 makereg8:=r;
251 end;
252 end;
255 function makereg16(r:tregister):tregister;
256 begin
257 case r of
258 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
259 makereg16:=reg32toreg16(r);
260 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
261 makereg16:=r;
262 R_AL,R_BL,R_CL,R_DL :
263 makereg16:=reg8toreg16(r);
264 end;
265 end;
268 function makereg32(r:tregister):tregister;
269 begin
270 case r of
271 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
272 makereg32:=r;
273 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
274 makereg32:=reg16toreg32(r);
275 R_AL,R_BL,R_CL,R_DL :
276 makereg32:=reg8toreg32(r);
277 end;
278 end;
281 procedure locflags2reg(var l:tlocation;opsize:topsize);
283 hregister : tregister;
284 begin
285 if (l.loc=LOC_FLAGS) then
286 begin
287 hregister:=getregister32;
288 case opsize of
289 S_W : hregister:=reg32toreg16(hregister);
290 S_B : hregister:=reg32toreg8(hregister);
291 end;
292 emit_flag2reg(l.resflags,hregister);
293 l.loc:=LOC_REGISTER;
294 l.register:=hregister;
296 else internalerror(270720001);
297 end;
300 procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: pasmlabel);
302 hregister : tregister;
303 hl : pasmlabel;
304 begin
305 if l.loc = LOC_JUMP then
306 begin
307 hregister:=getregister32;
308 case opsize of
309 S_W : hregister:=reg32toreg16(hregister);
310 S_B : hregister:=reg32toreg8(hregister);
311 end;
312 l.loc:=LOC_REGISTER;
313 l.register:=hregister;
314 emitlab(truelabel);
315 truelabel:=otl;
316 emit_const_reg(A_MOV,opsize,1,hregister);
317 getlabel(hl);
318 emitjmp(C_None,hl);
319 emitlab(falselabel);
320 falselabel:=ofl;
321 emit_reg_reg(A_XOR,S_L,makereg32(hregister),
322 makereg32(hregister));
323 emitlab(hl);
325 else internalerror(270720002);
326 end;
329 {*****************************************************************************
330 Emit Assembler
331 *****************************************************************************}
333 procedure emitlab(var l : pasmlabel);
334 begin
335 if not l^.is_set then
336 exprasmlist^.concat(new(pai_label,init(l)))
337 else
338 internalerror(7453984);
339 end;
341 {$ifdef nojmpfix}
342 procedure emitjmp(c : tasmcond;var l : pasmlabel);
344 ai : Paicpu;
345 begin
346 if c=C_None then
347 exprasmlist^.concat(new(paicpu,op_sym(A_JMP,S_NO,l)))
348 else
349 begin
350 ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
351 ai^.SetCondition(c);
352 ai^.is_jmp:=true;
353 exprasmlist^.concat(ai);
354 end;
355 end;
356 {$else nojmpfix}
357 procedure emitjmp(c : tasmcond;var l : pasmlabel);
359 ai : Paicpu;
360 begin
361 if c=C_None then
362 ai := new(paicpu,op_sym(A_JMP,S_NO,l))
363 else
364 begin
365 ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
366 ai^.SetCondition(c);
367 end;
368 ai^.is_jmp:=true;
369 exprasmlist^.concat(ai);
370 end;
371 {$endif nojmpfix}
373 procedure emit_flag2reg(flag:tresflags;hregister:tregister);
375 ai : paicpu;
376 hreg : tregister;
377 begin
378 hreg:=makereg8(hregister);
379 ai:=new(paicpu,op_reg(A_Setcc,S_B,hreg));
380 ai^.SetCondition(flag_2_cond[flag]);
381 exprasmlist^.concat(ai);
382 if hreg<>hregister then
383 begin
384 if hregister in regset16bit then
385 emit_to_reg16(hreg)
386 else
387 emit_to_reg32(hreg);
388 end;
389 end;
392 procedure emit_none(i : tasmop;s : topsize);
393 begin
394 exprasmlist^.concat(new(paicpu,op_none(i,s)));
395 end;
397 procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
398 begin
399 exprasmlist^.concat(new(paicpu,op_reg(i,s,reg)));
400 end;
402 procedure emit_ref(i : tasmop;s : topsize;ref : preference);
403 begin
404 exprasmlist^.concat(new(paicpu,op_ref(i,s,ref)));
405 end;
407 procedure emit_const(i : tasmop;s : topsize;c : longint);
408 begin
409 exprasmlist^.concat(new(paicpu,op_const(i,s,c)));
410 end;
412 procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
413 begin
414 exprasmlist^.concat(new(paicpu,op_const_reg(i,s,c,reg)));
415 end;
417 procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
418 begin
419 exprasmlist^.concat(new(paicpu,op_const_ref(i,s,c,ref)));
420 end;
422 procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
423 begin
424 exprasmlist^.concat(new(paicpu,op_ref_reg(i,s,ref,reg)));
425 end;
427 procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
428 begin
429 exprasmlist^.concat(new(paicpu,op_reg_ref(i,s,reg,ref)));
430 end;
432 procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
433 begin
434 if (reg1<>reg2) or (i<>A_MOV) then
435 exprasmlist^.concat(new(paicpu,op_reg_reg(i,s,reg1,reg2)));
436 end;
438 procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
439 begin
440 exprasmlist^.concat(new(paicpu,op_const_reg_reg(i,s,c,reg1,reg2)));
441 end;
443 procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
444 begin
445 exprasmlist^.concat(new(paicpu,op_reg_reg_reg(i,s,reg1,reg2,reg3)));
446 end;
448 procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
449 begin
450 exprasmlist^.concat(new(paicpu,op_sym(i,s,op)));
451 end;
453 procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
454 begin
455 exprasmlist^.concat(new(paicpu,op_sym_ofs(i,s,op,ofs)));
456 end;
458 procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
459 begin
460 exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(i,s,op,ofs,reg)));
461 end;
463 procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
464 begin
465 exprasmlist^.concat(new(paicpu,op_sym_ofs_ref(i,s,op,ofs,ref)));
466 end;
468 procedure emitcall(const routine:string);
469 begin
470 exprasmlist^.concat(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
471 end;
473 { only usefull in startup code }
474 procedure emitinsertcall(const routine:string);
475 begin
476 exprasmlist^.insert(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
477 end;
480 procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
482 hreg : tregister;
483 pushedeax : boolean;
485 begin
486 pushedeax:=false;
487 case t.loc of
488 LOC_REGISTER,
489 LOC_CREGISTER : begin
490 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
491 t.register,newreference(ref))));
492 ungetregister32(t.register); { the register is not needed anymore }
493 end;
494 LOC_MEM,
495 LOC_REFERENCE : begin
496 if t.reference.is_immediate then
497 emit_const_ref(A_MOV,siz,
498 t.reference.offset,newreference(ref))
499 else
500 begin
501 case siz of
502 S_B : begin
503 { we can't do a getregister in the code generator }
504 { without problems!!! }
505 if usablereg32>0 then
506 hreg:=reg32toreg8(getregister32)
507 else
508 begin
509 emit_reg(A_PUSH,S_L,R_EAX);
510 pushedeax:=true;
511 hreg:=R_AL;
512 end;
513 end;
514 S_W : hreg:=R_DI;
515 S_L : hreg:=R_EDI;
516 end;
517 {$ifndef noAllocEdi}
518 if hreg in [R_DI,R_EDI] then
519 getexplicitregister32(R_EDI);
520 {$endif noAllocEdi}
521 emit_ref_reg(A_MOV,siz,
522 newreference(t.reference),hreg);
523 del_reference(t.reference);
524 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
525 hreg,newreference(ref))));
526 if siz=S_B then
527 begin
528 if pushedeax then
529 emit_reg(A_POP,S_L,R_EAX)
530 else
531 ungetregister(hreg);
532 end;
533 {$ifndef noAllocEdi}
534 if hreg in [R_DI,R_EDI] then
535 ungetregister32(R_EDI);
536 {$endif noAllocEdi}
537 { we can release the registers }
538 { but only AFTER the MOV! Important for the optimizer!
539 (JM)}
540 del_reference(ref);
541 end;
542 if freetemp then
543 ungetiftemp(t.reference);
544 end;
545 else
546 internalerror(330);
547 end;
548 end;
551 procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
552 begin
553 case t.loc of
554 LOC_REGISTER,
555 LOC_CREGISTER : begin
556 emit_reg_reg(A_MOV,S_L,t.register,reg);
557 ungetregister32(t.register); { the register is not needed anymore }
558 end;
559 LOC_MEM,
560 LOC_REFERENCE : begin
561 if t.reference.is_immediate then
562 emit_const_reg(A_MOV,S_L,
563 t.reference.offset,reg)
564 else
565 begin
566 emit_ref_reg(A_MOV,S_L,
567 newreference(t.reference),reg);
568 end;
569 end;
570 else
571 internalerror(330);
572 end;
573 end;
575 procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
576 begin
577 case t.loc of
578 LOC_REGISTER,
579 LOC_CREGISTER : begin
580 emit_reg_reg(A_MOV,RegSize(Reg),
581 reg,t.register);
582 end;
583 LOC_MEM,
584 LOC_REFERENCE : begin
585 if t.reference.is_immediate then
586 internalerror(334)
587 else
588 begin
589 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,RegSize(Reg),
590 Reg,newreference(t.reference))));
591 end;
592 end;
593 else
594 internalerror(330);
595 end;
596 end;
599 procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
600 begin
601 case t.loc of
602 LOC_MEM,
603 LOC_REFERENCE : begin
604 if t.reference.is_immediate then
605 internalerror(331)
606 else
607 begin
608 emit_ref_reg(A_LEA,S_L,
609 newreference(t.reference),reg);
610 end;
611 if freetemp then
612 ungetiftemp(t.reference);
613 end;
614 else
615 internalerror(332);
616 end;
617 end;
620 procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
621 begin
622 case t.loc of
623 LOC_REGISTER,
624 LOC_CREGISTER : begin
625 emit_reg_reg(A_MOV,S_L,
626 reglow,t.registerlow);
627 emit_reg_reg(A_MOV,S_L,
628 reghigh,t.registerhigh);
629 end;
630 LOC_MEM,
631 LOC_REFERENCE : begin
632 if t.reference.is_immediate then
633 internalerror(334)
634 else
635 begin
636 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
637 Reglow,newreference(t.reference))));
638 inc(t.reference.offset,4);
639 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
640 Reghigh,newreference(t.reference))));
641 end;
642 end;
643 else
644 internalerror(330);
645 end;
646 end;
649 procedure emit_pushq_loc(const t : tlocation);
652 hr : preference;
654 begin
655 case t.loc of
656 LOC_REGISTER,
657 LOC_CREGISTER:
658 begin
659 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
660 t.registerhigh)));
661 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
662 t.registerlow)));
663 end;
664 LOC_MEM,
665 LOC_REFERENCE:
666 begin
667 hr:=newreference(t.reference);
668 inc(hr^.offset,4);
669 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
670 hr)));
671 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
672 newreference(t.reference))));
673 ungetiftemp(t.reference);
674 end;
675 else internalerror(331);
676 end;
677 end;
679 procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
680 begin
681 case t.loc of
682 LOC_REGISTER:
683 { can't be a regvar, since it would be LOC_CREGISTER then }
684 regs := regs and not($80 shr byte(t.register));
685 LOC_MEM,LOC_REFERENCE:
686 begin
687 if not(cs_regalloc in aktglobalswitches) or
688 (t.reference.base in usableregs) then
689 regs := regs and
690 not($80 shr byte(t.reference.base));
691 if not(cs_regalloc in aktglobalswitches) or
692 (t.reference.index in usableregs) then
693 regs := regs and
694 not($80 shr byte(t.reference.index));
695 end;
696 end;
697 end;
700 procedure release_loc(const t : tlocation);
702 begin
703 case t.loc of
704 LOC_REGISTER,
705 LOC_CREGISTER:
706 begin
707 ungetregister32(t.register);
708 end;
709 LOC_MEM,
710 LOC_REFERENCE:
711 del_reference(t.reference);
712 else internalerror(332);
713 end;
714 end;
716 procedure release_qword_loc(const t : tlocation);
717 begin
718 case t.loc of
719 LOC_REGISTER,
720 LOC_CREGISTER:
721 begin
722 ungetregister32(t.registerhigh);
723 ungetregister32(t.registerlow);
724 end;
725 LOC_MEM,
726 LOC_REFERENCE:
727 del_reference(t.reference);
728 else internalerror(331);
729 end;
730 end;
733 procedure emit_push_loc(const t:tlocation);
734 begin
735 case t.loc of
736 LOC_REGISTER,
737 LOC_CREGISTER : begin
738 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))));
739 ungetregister(t.register); { the register is not needed anymore }
740 end;
741 LOC_MEM,
742 LOC_REFERENCE : begin
743 if t.reference.is_immediate then
744 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,t.reference.offset)))
745 else
746 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(t.reference))));
747 del_reference(t.reference);
748 ungetiftemp(t.reference);
749 end;
750 else
751 internalerror(330);
752 end;
753 end;
756 procedure emit_pushw_loc(const t:tlocation);
758 opsize : topsize;
759 begin
760 case t.loc of
761 LOC_REGISTER,
762 LOC_CREGISTER : begin
763 if target_os.stackalignment=4 then
764 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))))
765 else
766 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,makereg16(t.register))));
767 ungetregister(t.register); { the register is not needed anymore }
768 end;
769 LOC_MEM,
770 LOC_REFERENCE : begin
771 if target_os.stackalignment=4 then
772 opsize:=S_L
773 else
774 opsize:=S_W;
775 if t.reference.is_immediate then
776 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,t.reference.offset)))
777 else
778 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,newreference(t.reference))));
779 del_reference(t.reference);
780 ungetiftemp(t.reference);
781 end;
782 else
783 internalerror(330);
784 end;
785 end;
788 procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
789 begin
790 case t.loc of
791 LOC_MEM,
792 LOC_REFERENCE : begin
793 if t.reference.is_immediate then
794 internalerror(331)
795 else
796 begin
797 {$ifndef noAllocEdi}
798 getexplicitregister32(R_EDI);
799 {$endif noAllocEdi}
800 emit_ref_reg(A_LEA,S_L,
801 newreference(t.reference),R_EDI);
802 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
803 R_EDI,newreference(ref))));
804 {$ifndef noAllocEdi}
805 ungetregister32(R_EDI);
806 {$endif noAllocEdi}
807 end;
808 { release the registers }
809 del_reference(t.reference);
810 if freetemp then
811 ungetiftemp(t.reference);
812 end;
813 else
814 internalerror(332);
815 end;
816 end;
819 procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
820 begin
821 case t.loc of
822 LOC_MEM,
823 LOC_REFERENCE : begin
824 if t.reference.is_immediate then
825 internalerror(331)
826 else
827 begin
828 {$ifndef noAllocEdi}
829 getexplicitregister32(R_EDI);
830 {$endif noAllocEdi}
831 emit_ref_reg(A_LEA,S_L,
832 newreference(t.reference),R_EDI);
833 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
834 {$ifndef noAllocEdi}
835 ungetregister32(R_EDI);
836 {$endif noAllocEdi}
837 end;
838 if freetemp then
839 ungetiftemp(t.reference);
840 end;
841 else
842 internalerror(332);
843 end;
844 end;
846 procedure emit_push_mem_size(const t: treference; size: longint);
849 s: topsize;
851 begin
852 if t.is_immediate then
853 begin
854 if (size=4) or
855 (target_os.stackalignment=4) then
856 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,t.offset)))
857 else
858 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,t.offset)));
860 else
861 if size < 4 then
862 begin
863 getexplicitregister32(R_EDI);
864 case size of
865 1: s := S_BL;
866 2: s := S_WL;
867 else internalerror(200008071);
868 end;
869 exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOVZX,s,
870 newreference(t),R_EDI)));
871 if target_os.stackalignment=4 then
872 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)))
873 else
874 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,R_DI)));
875 ungetregister32(R_EDI);
877 else
878 if size = 4 then
879 emit_push_mem(t)
880 else
881 internalerror(200008072);
882 end;
885 procedure emit_to_mem(var p:ptree);
888 r : treference;
890 begin
891 case p^.location.loc of
892 LOC_FPU : begin
893 reset_reference(p^.location.reference);
894 gettempofsizereference(10,p^.location.reference);
895 floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
896 { This can't be never a l-value! (FK)
897 p^.location.loc:=LOC_REFERENCE; }
898 end;
899 LOC_REGISTER:
900 begin
901 if is_64bitint(p^.resulttype) then
902 begin
903 gettempofsizereference(8,r);
904 emit_reg_ref(A_MOV,S_L,p^.location.registerlow,
905 newreference(r));
906 inc(r.offset,4);
907 emit_reg_ref(A_MOV,S_L,p^.location.registerhigh,
908 newreference(r));
909 dec(r.offset,4);
910 p^.location.reference:=r;
912 else
913 internalerror(1405001);
914 end;
915 LOC_MEM,
916 LOC_REFERENCE : ;
917 LOC_CFPUREGISTER : begin
918 emit_reg(A_FLD,S_NO,correct_fpuregister(p^.location.register,fpuvaroffset));
919 inc(fpuvaroffset);
920 reset_reference(p^.location.reference);
921 gettempofsizereference(10,p^.location.reference);
922 floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
923 { This can't be never a l-value! (FK)
924 p^.location.loc:=LOC_REFERENCE; }
925 end;
926 else
927 internalerror(333);
928 end;
929 p^.location.loc:=LOC_MEM;
930 end;
933 procedure emit_to_reg16(var hr:tregister);
934 begin
935 { ranges are a little bit bug sensitive ! }
936 case hr of
937 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
938 begin
939 hr:=reg32toreg16(hr);
940 end;
941 R_AL,R_BL,R_CL,R_DL:
942 begin
943 hr:=reg8toreg16(hr);
944 emit_const_reg(A_AND,S_W,$ff,hr);
945 end;
946 R_AH,R_BH,R_CH,R_DH:
947 begin
948 hr:=reg8toreg16(hr);
949 emit_const_reg(A_AND,S_W,$ff00,hr);
950 end;
951 end;
952 end;
955 procedure emit_to_reg32(var hr:tregister);
956 begin
957 { ranges are a little bit bug sensitive ! }
958 case hr of
959 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
960 begin
961 hr:=reg16toreg32(hr);
962 emit_const_reg(A_AND,S_L,$ffff,hr);
963 end;
964 R_AL,R_BL,R_CL,R_DL:
965 begin
966 hr:=reg8toreg32(hr);
967 emit_const_reg(A_AND,S_L,$ff,hr);
968 end;
969 R_AH,R_BH,R_CH,R_DH:
970 begin
971 hr:=reg8toreg32(hr);
972 emit_const_reg(A_AND,S_L,$ff00,hr);
973 end;
974 end;
975 end;
977 procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
980 hr : preference;
982 begin
983 { if we load a 64 bit reference, we must be careful because }
984 { we could overwrite the registers of the reference by }
985 { accident }
986 getexplicitregister32(R_EDI);
987 if r.base=rl then
988 begin
989 emit_reg_reg(A_MOV,S_L,r.base,
990 R_EDI);
991 r.base:=R_EDI;
993 else if r.index=rl then
994 begin
995 emit_reg_reg(A_MOV,S_L,r.index,
996 R_EDI);
997 r.index:=R_EDI;
998 end;
999 emit_ref_reg(A_MOV,S_L,
1000 newreference(r),rl);
1001 hr:=newreference(r);
1002 inc(hr^.offset,4);
1003 emit_ref_reg(A_MOV,S_L,
1004 hr,rh);
1005 ungetregister32(R_EDI);
1006 end;
1008 {*****************************************************************************
1009 Emit String Functions
1010 *****************************************************************************}
1012 procedure copyshortstring(const dref,sref : treference;len : byte;
1013 loadref, del_sref: boolean);
1014 begin
1015 emitpushreferenceaddr(dref);
1016 { if it's deleted right before it's used, the optimizer can move }
1017 { the reg deallocations to the right places (JM) }
1018 if del_sref then
1019 del_reference(sref);
1020 if loadref then
1021 emit_push_mem(sref)
1022 else
1023 emitpushreferenceaddr(sref);
1024 push_int(len);
1025 emitcall('FPC_SHORTSTR_COPY');
1026 maybe_loadesi;
1027 end;
1029 procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
1030 begin
1031 emitpushreferenceaddr(dref);
1032 if loadref then
1033 emit_push_mem(sref)
1034 else
1035 emitpushreferenceaddr(sref);
1036 push_int(len);
1037 emitcall('FPC_LONGSTR_COPY');
1038 maybe_loadesi;
1039 end;
1042 procedure incrstringref(t : pdef;const ref : treference);
1045 pushedregs : tpushed;
1047 begin
1048 pushusedregisters(pushedregs,$ff);
1049 emitpushreferenceaddr(ref);
1050 if is_ansistring(t) then
1051 begin
1052 emitcall('FPC_ANSISTR_INCR_REF');
1054 else if is_widestring(t) then
1055 begin
1056 emitcall('FPC_WIDESTR_INCR_REF');
1058 else internalerror(1859);
1059 popusedregisters(pushedregs);
1060 end;
1063 procedure decrstringref(t : pdef;const ref : treference);
1066 pushedregs : tpushed;
1068 begin
1069 pushusedregisters(pushedregs,$ff);
1070 emitpushreferenceaddr(ref);
1071 if is_ansistring(t) then
1072 begin
1073 emitcall('FPC_ANSISTR_DECR_REF');
1075 else if is_widestring(t) then
1076 begin
1077 emitcall('FPC_WIDESTR_DECR_REF');
1079 else internalerror(1859);
1080 popusedregisters(pushedregs);
1081 end;
1083 procedure loadansistring(p : ptree);
1085 copies an ansistring from p^.right to p^.left, we
1086 assume, that both sides are ansistring, firstassignement have
1087 to take care of that, an ansistring can't be a register variable
1090 pushed : tpushed;
1091 regs_to_push: byte;
1092 ungettemp : boolean;
1093 begin
1094 { before pushing any parameter, we have to save all used }
1095 { registers, but before that we have to release the }
1096 { registers of that node to save uneccessary pushed }
1097 { so be careful, if you think you can optimize that code (FK) }
1099 { nevertheless, this has to be changed, because otherwise the }
1100 { register is released before it's contents are pushed -> }
1101 { problems with the optimizer (JM) }
1102 del_reference(p^.left^.location.reference);
1103 ungettemp:=false;
1104 { Find out which registers have to be pushed (JM) }
1105 regs_to_push := $ff;
1106 remove_non_regvars_from_loc(p^.right^.location,regs_to_push);
1107 { And push them (JM) }
1108 pushusedregisters(pushed,regs_to_push);
1109 case p^.right^.location.loc of
1110 LOC_REGISTER,LOC_CREGISTER:
1111 begin
1112 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register)));
1113 ungetregister32(p^.right^.location.register);
1114 end;
1115 LOC_REFERENCE,LOC_MEM:
1116 begin
1117 { First release the registers because emit_push_mem may }
1118 { load the reference in edi before pushing and then the }
1119 { dealloc is too late (and optimizations are missed (JM) }
1120 del_reference(p^.right^.location.reference);
1121 { This one doesn't need extra registers (JM) }
1122 emit_push_mem(p^.right^.location.reference);
1123 ungettemp:=true;
1124 end;
1125 end;
1126 emitpushreferenceaddr(p^.left^.location.reference);
1127 del_reference(p^.left^.location.reference);
1128 emitcall('FPC_ANSISTR_ASSIGN');
1129 maybe_loadesi;
1130 popusedregisters(pushed);
1131 if ungettemp then
1132 ungetiftemp(p^.right^.location.reference);
1133 end;
1136 {*****************************************************************************
1137 Emit Push Functions
1138 *****************************************************************************}
1140 function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
1142 pushed : boolean;
1143 {hregister : tregister; }
1144 {$ifdef TEMPS_NOT_PUSH}
1145 href : treference;
1146 {$endif TEMPS_NOT_PUSH}
1147 begin
1148 if needed>usablereg32 then
1149 begin
1150 if (p^.location.loc=LOC_REGISTER) then
1151 begin
1152 if isint64 then
1153 begin
1154 {$ifdef TEMPS_NOT_PUSH}
1155 gettempofsizereference(href,8);
1156 p^.temp_offset:=href.offset;
1157 href.offset:=href.offset+4;
1158 exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
1159 href.offset:=href.offset-4;
1160 {$else TEMPS_NOT_PUSH}
1161 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
1162 {$endif TEMPS_NOT_PUSH}
1163 ungetregister32(p^.location.registerhigh);
1165 {$ifdef TEMPS_NOT_PUSH}
1166 else
1167 begin
1168 gettempofsizereference(href,4);
1169 p^.temp_offset:=href.offset;
1171 {$endif TEMPS_NOT_PUSH}
1173 pushed:=true;
1174 {$ifdef TEMPS_NOT_PUSH}
1175 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
1176 {$else TEMPS_NOT_PUSH}
1177 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
1178 {$endif TEMPS_NOT_PUSH}
1179 ungetregister32(p^.location.register);
1181 else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
1182 ((p^.location.reference.base<>R_NO) or
1183 (p^.location.reference.index<>R_NO)
1184 ) then
1185 begin
1186 del_reference(p^.location.reference);
1187 {$ifndef noAllocEdi}
1188 getexplicitregister32(R_EDI);
1189 {$endif noAllocEdi}
1190 emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
1191 R_EDI);
1192 {$ifdef TEMPS_NOT_PUSH}
1193 gettempofsizereference(href,4);
1194 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
1195 p^.temp_offset:=href.offset;
1196 {$else TEMPS_NOT_PUSH}
1197 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
1198 {$endif TEMPS_NOT_PUSH}
1199 {$ifndef noAllocEdi}
1200 ungetregister32(R_EDI);
1201 {$endif noAllocEdi}
1202 pushed:=true;
1204 else pushed:=false;
1206 else pushed:=false;
1207 maybe_push:=pushed;
1208 end;
1210 {$ifdef TEMPS_NOT_PUSH}
1211 function maybe_savetotemp(needed : byte;p : ptree;isint64 : boolean) : boolean;
1214 pushed : boolean;
1215 href : treference;
1217 begin
1218 if needed>usablereg32 then
1219 begin
1220 if (p^.location.loc=LOC_REGISTER) then
1221 begin
1222 if isint64(p^.resulttype) then
1223 begin
1224 gettempofsizereference(href,8);
1225 p^.temp_offset:=href.offset;
1226 href.offset:=href.offset+4;
1227 exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
1228 href.offset:=href.offset-4;
1229 ungetregister32(p^.location.registerhigh);
1231 else
1232 begin
1233 gettempofsizereference(href,4);
1234 p^.temp_offset:=href.offset;
1235 end;
1236 pushed:=true;
1237 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
1238 ungetregister32(p^.location.register);
1240 else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
1241 ((p^.location.reference.base<>R_NO) or
1242 (p^.location.reference.index<>R_NO)
1243 ) then
1244 begin
1245 del_reference(p^.location.reference);
1246 {$ifndef noAllocEdi}
1247 getexplicitregister32(R_EDI);
1248 {$endif noAllocEdi}
1249 emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
1250 R_EDI);
1251 gettempofsizereference(href,4);
1252 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
1253 {$ifndef noAllocEdi}
1254 ungetregister32(R_EDI);
1255 {$endif noAllocEdi}
1256 p^.temp_offset:=href.offset;
1257 pushed:=true;
1259 else pushed:=false;
1261 else pushed:=false;
1262 maybe_push:=pushed;
1263 end;
1264 {$endif TEMPS_NOT_PUSH}
1267 procedure push_int(l : longint);
1268 begin
1269 if (l = 0) and
1270 not(aktoptprocessor in [Class386, ClassP6]) and
1271 not(cs_littlesize in aktglobalswitches)
1272 Then
1273 begin
1274 {$ifndef noAllocEdi}
1275 getexplicitregister32(R_EDI);
1276 {$endif noAllocEdi}
1277 emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
1278 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
1279 {$ifndef noAllocEdi}
1280 ungetregister32(R_EDI);
1281 {$endif noAllocEdi}
1283 else
1284 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,l)));
1285 end;
1287 procedure emit_push_mem(const ref : treference);
1289 begin
1290 if ref.is_immediate then
1291 push_int(ref.offset)
1292 else
1293 begin
1294 if not(aktoptprocessor in [Class386, ClassP6]) and
1295 not(cs_littlesize in aktglobalswitches)
1296 then
1297 begin
1298 {$ifndef noAllocEdi}
1299 getexplicitregister32(R_EDI);
1300 {$endif noAllocEdi}
1301 emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
1302 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
1303 {$ifndef noAllocEdi}
1304 ungetregister32(R_EDI);
1305 {$endif noAllocEdi}
1307 else exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(ref))));
1308 end;
1309 end;
1312 procedure emitpushreferenceaddr(const ref : treference);
1314 href : treference;
1315 begin
1316 { this will fail for references to other segments !!! }
1317 if ref.is_immediate then
1318 { is this right ? }
1319 begin
1320 { push_int(ref.offset)}
1321 gettempofsizereference(4,href);
1322 emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
1323 emitpushreferenceaddr(href);
1324 del_reference(href);
1326 else
1327 begin
1328 if ref.segment<>R_NO then
1329 CGMessage(cg_e_cant_use_far_pointer_there);
1330 if (ref.base=R_NO) and (ref.index=R_NO) then
1331 exprasmlist^.concat(new(paicpu,op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset)))
1332 else if (ref.base=R_NO) and (ref.index<>R_NO) and
1333 (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
1334 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.index)))
1335 else if (ref.base<>R_NO) and (ref.index=R_NO) and
1336 (ref.offset=0) and (ref.symbol=nil) then
1337 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.base)))
1338 else
1339 begin
1340 {$ifndef noAllocEdi}
1341 getexplicitregister32(R_EDI);
1342 {$endif noAllocEdi}
1343 emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
1344 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
1345 {$ifndef noAllocEdi}
1346 ungetregister32(R_EDI);
1347 {$endif noAllocEdi}
1348 end;
1349 end;
1350 end;
1353 procedure pushsetelement(p : ptree);
1355 copies p a set element on the stack
1358 hr,hr16,hr32 : tregister;
1359 begin
1360 { copy the element on the stack, slightly complicated }
1361 if p^.treetype=ordconstn then
1362 begin
1363 if target_os.stackalignment=4 then
1364 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,p^.value)))
1365 else
1366 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,p^.value)));
1368 else
1369 begin
1370 case p^.location.loc of
1371 LOC_REGISTER,
1372 LOC_CREGISTER :
1373 begin
1374 hr:=p^.location.register;
1375 case hr of
1376 R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
1377 begin
1378 hr16:=reg32toreg16(hr);
1379 hr32:=hr;
1380 end;
1381 R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
1382 begin
1383 hr16:=hr;
1384 hr32:=reg16toreg32(hr);
1385 end;
1386 R_AL,R_BL,R_CL,R_DL :
1387 begin
1388 hr16:=reg8toreg16(hr);
1389 hr32:=reg8toreg32(hr);
1390 end;
1391 end;
1392 if target_os.stackalignment=4 then
1393 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
1394 else
1395 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
1396 ungetregister32(hr32);
1397 end;
1398 else
1399 begin
1400 { you can't push more bytes than the size of the element, }
1401 { because this may cross a page boundary and you'll get a }
1402 { sigsegv (JM) }
1403 emit_push_mem_size(p^.location.reference,1);
1404 del_reference(p^.location.reference);
1405 end;
1406 end;
1407 end;
1408 end;
1411 procedure restore(p : ptree;isint64 : boolean);
1413 hregister : tregister;
1414 {$ifdef TEMPS_NOT_PUSH}
1415 href : treference;
1416 {$endif TEMPS_NOT_PUSH}
1417 begin
1418 hregister:=getregister32;
1419 {$ifdef TEMPS_NOT_PUSH}
1420 reset_reference(href);
1421 href.base:=procinfo^.frame_pointer;
1422 href.offset:=p^.temp_offset;
1423 emit_ref_reg(A_MOV,S_L,href,hregister);
1424 {$else TEMPS_NOT_PUSH}
1425 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
1426 {$endif TEMPS_NOT_PUSH}
1427 if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
1428 begin
1429 p^.location.register:=hregister;
1430 if isint64 then
1431 begin
1432 p^.location.registerhigh:=getregister32;
1433 {$ifdef TEMPS_NOT_PUSH}
1434 href.offset:=p^.temp_offset+4;
1435 emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
1436 { set correctly for release ! }
1437 href.offset:=p^.temp_offset;
1438 {$else TEMPS_NOT_PUSH}
1439 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p^.location.registerhigh)));
1440 {$endif TEMPS_NOT_PUSH}
1441 end;
1443 else
1444 begin
1445 reset_reference(p^.location.reference);
1446 { any reasons why this was moved into the index register ? }
1447 { normally usage of base register is much better (FK) }
1448 p^.location.reference.base:=hregister;
1449 { Why is this done? We can never be sure about p^.left
1450 because otherwise secondload fails !!!
1451 set_location(p^.left^.location,p^.location);}
1452 end;
1453 {$ifdef TEMPS_NOT_PUSH}
1454 ungetiftemp(href);
1455 {$endif TEMPS_NOT_PUSH}
1456 end;
1458 {$ifdef TEMPS_NOT_PUSH}
1459 procedure restorefromtemp(p : ptree;isint64 : boolean);
1461 hregister : tregister;
1462 href : treference;
1464 begin
1465 hregister:=getregister32;
1466 reset_reference(href);
1467 href.base:=procinfo^.frame_pointer;
1468 href.offset:=p^.temp_offset;
1469 emit_ref_reg(A_MOV,S_L,href,hregister);
1470 if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
1471 begin
1472 p^.location.register:=hregister;
1473 if isint64 then
1474 begin
1475 p^.location.registerhigh:=getregister32;
1476 href.offset:=p^.temp_offset+4;
1477 emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
1478 { set correctly for release ! }
1479 href.offset:=p^.temp_offset;
1480 end;
1482 else
1483 begin
1484 reset_reference(p^.location.reference);
1485 p^.location.reference.base:=hregister;
1486 { Why is this done? We can never be sure about p^.left
1487 because otherwise secondload fails PM
1488 set_location(p^.left^.location,p^.location);}
1489 end;
1490 ungetiftemp(href);
1491 end;
1492 {$endif TEMPS_NOT_PUSH}
1494 procedure push_value_para(p:ptree;inlined,is_cdecl:boolean;
1495 para_offset:longint;alignment : longint);
1497 tempreference : treference;
1498 r : preference;
1499 opsize : topsize;
1500 op : tasmop;
1501 hreg : tregister;
1502 size : longint;
1503 hlabel : pasmlabel;
1504 begin
1505 case p^.location.loc of
1506 LOC_REGISTER,
1507 LOC_CREGISTER:
1508 begin
1509 case p^.location.register of
1510 R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
1511 R_EDI,R_ESP,R_EBP :
1512 begin
1513 if p^.resulttype^.size=8 then
1514 begin
1515 inc(pushedparasize,8);
1516 if inlined then
1517 begin
1518 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1519 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
1520 p^.location.registerlow,r)));
1521 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
1522 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
1523 p^.location.registerhigh,r)));
1525 else
1526 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
1527 ungetregister32(p^.location.registerhigh);
1528 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerlow)));
1529 ungetregister32(p^.location.registerlow);
1531 else
1532 begin
1533 inc(pushedparasize,4);
1534 if inlined then
1535 begin
1536 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1537 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
1538 p^.location.register,r)));
1540 else
1541 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
1542 ungetregister32(p^.location.register);
1543 end;
1544 end;
1545 R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
1546 begin
1547 if alignment=4 then
1548 begin
1549 opsize:=S_L;
1550 hreg:=reg16toreg32(p^.location.register);
1551 inc(pushedparasize,4);
1553 else
1554 begin
1555 opsize:=S_W;
1556 hreg:=p^.location.register;
1557 inc(pushedparasize,2);
1558 end;
1559 if inlined then
1560 begin
1561 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1562 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
1564 else
1565 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
1566 ungetregister32(reg16toreg32(p^.location.register));
1567 end;
1568 R_AL,R_BL,R_CL,R_DL:
1569 begin
1570 if alignment=4 then
1571 begin
1572 opsize:=S_L;
1573 hreg:=reg8toreg32(p^.location.register);
1574 inc(pushedparasize,4);
1576 else
1577 begin
1578 opsize:=S_W;
1579 hreg:=reg8toreg16(p^.location.register);
1580 inc(pushedparasize,2);
1581 end;
1582 { we must push always 16 bit }
1583 if inlined then
1584 begin
1585 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1586 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
1588 else
1589 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
1590 ungetregister32(reg8toreg32(p^.location.register));
1591 end;
1592 else internalerror(1899);
1593 end;
1594 end;
1595 LOC_FPU:
1596 begin
1597 size:=align(pfloatdef(p^.resulttype)^.size,alignment);
1598 inc(pushedparasize,size);
1599 if not inlined then
1600 emit_const_reg(A_SUB,S_L,size,R_ESP);
1601 {$ifdef GDB}
1602 if (cs_debuginfo in aktmoduleswitches) and
1603 (exprasmlist^.first=exprasmlist^.last) then
1604 exprasmlist^.concat(new(pai_force_line,init));
1605 {$endif GDB}
1606 r:=new_reference(R_ESP,0);
1607 floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
1608 { this is the easiest case for inlined !! }
1609 if inlined then
1610 begin
1611 r^.base:=procinfo^.framepointer;
1612 r^.offset:=para_offset-pushedparasize;
1613 end;
1614 exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
1615 dec(fpuvaroffset);
1616 end;
1617 LOC_CFPUREGISTER:
1618 begin
1619 exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
1620 correct_fpuregister(p^.location.register,fpuvaroffset))));
1621 size:=align(pfloatdef(p^.resulttype)^.size,alignment);
1622 inc(pushedparasize,size);
1623 if not inlined then
1624 emit_const_reg(A_SUB,S_L,size,R_ESP);
1625 {$ifdef GDB}
1626 if (cs_debuginfo in aktmoduleswitches) and
1627 (exprasmlist^.first=exprasmlist^.last) then
1628 exprasmlist^.concat(new(pai_force_line,init));
1629 {$endif GDB}
1630 r:=new_reference(R_ESP,0);
1631 floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
1632 { this is the easiest case for inlined !! }
1633 if inlined then
1634 begin
1635 r^.base:=procinfo^.framepointer;
1636 r^.offset:=para_offset-pushedparasize;
1637 end;
1638 exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
1639 end;
1640 LOC_REFERENCE,LOC_MEM:
1641 begin
1642 tempreference:=p^.location.reference;
1643 del_reference(p^.location.reference);
1644 case p^.resulttype^.deftype of
1645 enumdef,
1646 orddef :
1647 begin
1648 case p^.resulttype^.size of
1649 8 : begin
1650 inc(pushedparasize,8);
1651 if inlined then
1652 begin
1653 {$ifndef noAllocEdi}
1654 getexplicitregister32(R_EDI);
1655 {$endif noAllocEdi}
1656 emit_ref_reg(A_MOV,S_L,
1657 newreference(tempreference),R_EDI);
1658 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1659 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1660 {$ifndef noAllocEdi}
1661 ungetregister32(R_EDI);
1662 getexplicitregister32(R_EDI);
1663 {$endif noAllocEdi}
1664 inc(tempreference.offset,4);
1665 emit_ref_reg(A_MOV,S_L,
1666 newreference(tempreference),R_EDI);
1667 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
1668 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1669 {$ifndef noAllocEdi}
1670 ungetregister32(R_EDI);
1671 {$endif noAllocEdi}
1673 else
1674 begin
1675 inc(tempreference.offset,4);
1676 emit_push_mem(tempreference);
1677 dec(tempreference.offset,4);
1678 emit_push_mem(tempreference);
1679 end;
1680 end;
1681 4 : begin
1682 inc(pushedparasize,4);
1683 if inlined then
1684 begin
1685 {$ifndef noAllocEdi}
1686 getexplicitregister32(R_EDI);
1687 {$endif noAllocEdi}
1688 emit_ref_reg(A_MOV,S_L,
1689 newreference(tempreference),R_EDI);
1690 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1691 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1692 {$ifndef noAllocEdi}
1693 ungetregister32(R_EDI);
1694 {$endif noAllocEdi}
1696 else
1697 emit_push_mem(tempreference);
1698 end;
1699 1,2 : begin
1700 if alignment=4 then
1701 begin
1702 opsize:=S_L;
1703 hreg:=R_EDI;
1704 inc(pushedparasize,4);
1706 else
1707 begin
1708 opsize:=S_W;
1709 hreg:=R_DI;
1710 inc(pushedparasize,2);
1711 end;
1712 if inlined then
1713 begin
1714 {$ifndef noAllocEdi}
1715 getexplicitregister32(R_EDI);
1716 {$endif noAllocEdi}
1717 emit_ref_reg(A_MOV,opsize,
1718 newreference(tempreference),hreg);
1719 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1720 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
1721 {$ifndef noAllocEdi}
1722 ungetregister32(R_EDI);
1723 {$endif noAllocEdi}
1725 else
1726 emit_push_mem_size(tempreference,p^.resulttype^.size);
1727 end;
1728 else
1729 internalerror(234231);
1730 end;
1731 end;
1732 floatdef :
1733 begin
1734 case pfloatdef(p^.resulttype)^.typ of
1735 f32bit,
1736 s32real :
1737 begin
1738 inc(pushedparasize,4);
1739 if inlined then
1740 begin
1741 {$ifndef noAllocEdi}
1742 getexplicitregister32(R_EDI);
1743 {$endif noAllocEdi}
1744 emit_ref_reg(A_MOV,S_L,
1745 newreference(tempreference),R_EDI);
1746 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1747 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1748 {$ifndef noAllocEdi}
1749 ungetregister32(R_EDI);
1750 {$endif noAllocEdi}
1752 else
1753 emit_push_mem(tempreference);
1754 end;
1755 s64real,
1756 s64comp :
1757 begin
1758 inc(pushedparasize,4);
1759 inc(tempreference.offset,4);
1760 if inlined then
1761 begin
1762 {$ifndef noAllocEdi}
1763 getexplicitregister32(R_EDI);
1764 {$endif noAllocEdi}
1765 emit_ref_reg(A_MOV,S_L,
1766 newreference(tempreference),R_EDI);
1767 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1768 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1769 {$ifndef noAllocEdi}
1770 ungetregister32(R_EDI);
1771 {$endif noAllocEdi}
1773 else
1774 emit_push_mem(tempreference);
1775 inc(pushedparasize,4);
1776 dec(tempreference.offset,4);
1777 if inlined then
1778 begin
1779 {$ifndef noAllocEdi}
1780 getexplicitregister32(R_EDI);
1781 {$endif noAllocEdi}
1782 emit_ref_reg(A_MOV,S_L,
1783 newreference(tempreference),R_EDI);
1784 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1785 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1786 {$ifndef noAllocEdi}
1787 ungetregister32(R_EDI);
1788 {$endif noAllocEdi}
1790 else
1791 emit_push_mem(tempreference);
1792 end;
1793 s80real :
1794 begin
1795 inc(pushedparasize,4);
1796 if alignment=4 then
1797 inc(tempreference.offset,8)
1798 else
1799 inc(tempreference.offset,6);
1800 if inlined then
1801 begin
1802 {$ifndef noAllocEdi}
1803 getexplicitregister32(R_EDI);
1804 {$endif noAllocEdi}
1805 emit_ref_reg(A_MOV,S_L,
1806 newreference(tempreference),R_EDI);
1807 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1808 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1809 {$ifndef noAllocEdi}
1810 ungetregister32(R_EDI);
1811 {$endif noAllocEdi}
1813 else
1814 emit_push_mem(tempreference);
1815 dec(tempreference.offset,4);
1816 inc(pushedparasize,4);
1817 if inlined then
1818 begin
1819 {$ifndef noAllocEdi}
1820 getexplicitregister32(R_EDI);
1821 {$endif noAllocEdi}
1822 emit_ref_reg(A_MOV,S_L,
1823 newreference(tempreference),R_EDI);
1824 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1825 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1826 {$ifndef noAllocEdi}
1827 ungetregister32(R_EDI);
1828 {$endif noAllocEdi}
1830 else
1831 emit_push_mem(tempreference);
1832 if alignment=4 then
1833 begin
1834 opsize:=S_L;
1835 hreg:=R_EDI;
1836 inc(pushedparasize,4);
1837 dec(tempreference.offset,4);
1839 else
1840 begin
1841 opsize:=S_W;
1842 hreg:=R_DI;
1843 inc(pushedparasize,2);
1844 dec(tempreference.offset,2);
1845 end;
1846 if inlined then
1847 begin
1848 {$ifndef noAllocEdi}
1849 getexplicitregister32(R_EDI);
1850 {$endif noAllocEdi}
1851 emit_ref_reg(A_MOV,opsize,
1852 newreference(tempreference),hreg);
1853 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1854 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
1855 {$ifndef noAllocEdi}
1856 ungetregister32(R_EDI);
1857 {$endif noAllocEdi}
1859 else
1860 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
1861 newreference(tempreference))));
1862 end;
1863 end;
1864 end;
1865 pointerdef,
1866 procvardef,
1867 classrefdef:
1868 begin
1869 inc(pushedparasize,4);
1870 if inlined then
1871 begin
1872 {$ifndef noAllocEdi}
1873 getexplicitregister32(R_EDI);
1874 {$endif noAllocEdi}
1875 emit_ref_reg(A_MOV,S_L,
1876 newreference(tempreference),R_EDI);
1877 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1878 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
1879 {$ifndef noAllocEdi}
1880 ungetregister32(R_EDI);
1881 {$endif noAllocEdi}
1883 else
1884 emit_push_mem(tempreference);
1885 end;
1886 arraydef,
1887 recorddef,
1888 stringdef,
1889 setdef,
1890 objectdef :
1891 begin
1892 { even some structured types are 32 bit }
1893 if is_widestring(p^.resulttype) or
1894 is_ansistring(p^.resulttype) or
1895 is_smallset(p^.resulttype) or
1896 ((p^.resulttype^.deftype in [recorddef,arraydef]) and
1898 (p^.resulttype^.deftype<>arraydef) or not
1899 (parraydef(p^.resulttype)^.IsConstructor or
1900 parraydef(p^.resulttype)^.isArrayOfConst or
1901 is_open_array(p^.resulttype))
1902 ) and
1903 (p^.resulttype^.size<=4)
1904 ) or
1905 ((p^.resulttype^.deftype=objectdef) and
1906 pobjectdef(p^.resulttype)^.is_class) then
1907 begin
1908 if (p^.resulttype^.size>2) or
1909 ((alignment=4) and (p^.resulttype^.size>0)) then
1910 begin
1911 inc(pushedparasize,4);
1912 if inlined then
1913 begin
1914 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1915 concatcopy(tempreference,r^,4,false,false);
1917 else
1918 emit_push_mem(tempreference);
1920 else
1921 begin
1922 if p^.resulttype^.size>0 then
1923 begin
1924 inc(pushedparasize,2);
1925 if inlined then
1926 begin
1927 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1928 concatcopy(tempreference,r^,2,false,false);
1930 else
1931 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
1932 end;
1933 end;
1935 { call by value open array ? }
1936 else if is_cdecl then
1937 begin
1938 { push on stack }
1939 size:=align(p^.resulttype^.size,alignment);
1940 inc(pushedparasize,size);
1941 emit_const_reg(A_SUB,S_L,size,R_ESP);
1942 r:=new_reference(R_ESP,0);
1943 concatcopy(tempreference,r^,size,false,false);
1945 else
1946 internalerror(8954);
1947 end;
1948 else
1949 CGMessage(cg_e_illegal_expression);
1950 end;
1951 end;
1952 LOC_JUMP:
1953 begin
1954 getlabel(hlabel);
1955 if alignment=4 then
1956 begin
1957 opsize:=S_L;
1958 inc(pushedparasize,4);
1960 else
1961 begin
1962 opsize:=S_W;
1963 inc(pushedparasize,2);
1964 end;
1965 emitlab(truelabel);
1966 if inlined then
1967 begin
1968 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1969 emit_const_ref(A_MOV,opsize,1,r);
1971 else
1972 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
1973 emitjmp(C_None,hlabel);
1974 emitlab(falselabel);
1975 if inlined then
1976 begin
1977 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
1978 emit_const_ref(A_MOV,opsize,0,r);
1980 else
1981 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
1982 emitlab(hlabel);
1983 end;
1984 LOC_FLAGS:
1985 begin
1986 if not(R_EAX in unused) then
1987 begin
1988 {$ifndef noAllocEdi}
1989 getexplicitregister32(R_EDI);
1990 {$endif noAllocEdi}
1991 emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
1992 end;
1993 emit_flag2reg(p^.location.resflags,R_AL);
1994 emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
1995 if alignment=4 then
1996 begin
1997 opsize:=S_L;
1998 hreg:=R_EAX;
1999 inc(pushedparasize,4);
2001 else
2002 begin
2003 opsize:=S_W;
2004 hreg:=R_AX;
2005 inc(pushedparasize,2);
2006 end;
2007 if inlined then
2008 begin
2009 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
2010 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
2012 else
2013 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
2014 if not(R_EAX in unused) then
2015 begin
2016 emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
2017 {$ifndef noAllocEdi}
2018 ungetregister32(R_EDI);
2019 {$endif noAllocEdi}
2020 end;
2021 end;
2022 {$ifdef SUPPORT_MMX}
2023 LOC_MMXREGISTER,
2024 LOC_CMMXREGISTER:
2025 begin
2026 inc(pushedparasize,8); { was missing !!! (PM) }
2027 emit_const_reg(
2028 A_SUB,S_L,8,R_ESP);
2029 {$ifdef GDB}
2030 if (cs_debuginfo in aktmoduleswitches) and
2031 (exprasmlist^.first=exprasmlist^.last) then
2032 exprasmlist^.concat(new(pai_force_line,init));
2033 {$endif GDB}
2034 if inlined then
2035 begin
2036 r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
2037 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
2038 p^.location.register,r)));
2040 else
2041 begin
2042 r:=new_reference(R_ESP,0);
2043 exprasmlist^.concat(new(paicpu,op_reg_ref(
2044 A_MOVQ,S_NO,p^.location.register,r)));
2045 end;
2046 end;
2047 {$endif SUPPORT_MMX}
2048 end;
2049 end;
2053 {*****************************************************************************
2054 Emit Float Functions
2055 *****************************************************************************}
2057 procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
2058 begin
2059 case t of
2060 s32real : begin
2061 op:=A_FLD;
2062 s:=S_FS;
2063 end;
2064 s64real : begin
2065 op:=A_FLD;
2066 { ???? }
2067 s:=S_FL;
2068 end;
2069 s80real : begin
2070 op:=A_FLD;
2071 s:=S_FX;
2072 end;
2073 s64comp : begin
2074 op:=A_FILD;
2075 s:=S_IQ;
2076 end;
2077 else internalerror(17);
2078 end;
2079 end;
2082 procedure floatload(t : tfloattype;const ref : treference);
2084 op : tasmop;
2085 s : topsize;
2086 begin
2087 floatloadops(t,op,s);
2088 exprasmlist^.concat(new(paicpu,op_ref(op,s,
2089 newreference(ref))));
2090 inc(fpuvaroffset);
2091 end;
2094 procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
2095 begin
2096 case t of
2097 s32real : begin
2098 op:=A_FSTP;
2099 s:=S_FS;
2100 end;
2101 s64real : begin
2102 op:=A_FSTP;
2103 s:=S_FL;
2104 end;
2105 s80real : begin
2106 op:=A_FSTP;
2107 s:=S_FX;
2108 end;
2109 s64comp : begin
2110 op:=A_FISTP;
2111 s:=S_IQ;
2112 end;
2113 else
2114 internalerror(17);
2115 end;
2116 end;
2119 procedure floatstore(t : tfloattype;const ref : treference);
2121 op : tasmop;
2122 s : topsize;
2123 begin
2124 floatstoreops(t,op,s);
2125 exprasmlist^.concat(new(paicpu,op_ref(op,s,
2126 newreference(ref))));
2127 dec(fpuvaroffset);
2128 end;
2131 {*****************************************************************************
2132 Emit Functions
2133 *****************************************************************************}
2135 procedure maketojumpbool(p : ptree);
2137 produces jumps to true respectively false labels using boolean expressions
2140 opsize : topsize;
2141 storepos : tfileposinfo;
2142 begin
2143 if p^.error then
2144 exit;
2145 storepos:=aktfilepos;
2146 aktfilepos:=p^.fileinfo;
2147 if is_boolean(p^.resulttype) then
2148 begin
2149 if is_constboolnode(p) then
2150 begin
2151 if p^.value<>0 then
2152 emitjmp(C_None,truelabel)
2153 else
2154 emitjmp(C_None,falselabel);
2156 else
2157 begin
2158 opsize:=def_opsize(p^.resulttype);
2159 case p^.location.loc of
2160 LOC_CREGISTER,LOC_REGISTER : begin
2161 emit_reg_reg(A_OR,opsize,p^.location.register,
2162 p^.location.register);
2163 ungetregister(p^.location.register);
2164 emitjmp(C_NZ,truelabel);
2165 emitjmp(C_None,falselabel);
2166 end;
2167 LOC_MEM,LOC_REFERENCE : begin
2168 emit_const_ref(
2169 A_CMP,opsize,0,newreference(p^.location.reference));
2170 del_reference(p^.location.reference);
2171 emitjmp(C_NZ,truelabel);
2172 emitjmp(C_None,falselabel);
2173 end;
2174 LOC_FLAGS : begin
2175 emitjmp(flag_2_cond[p^.location.resflags],truelabel);
2176 emitjmp(C_None,falselabel);
2177 end;
2178 end;
2179 end;
2181 else
2182 CGMessage(type_e_mismatch);
2183 aktfilepos:=storepos;
2184 end;
2187 { produces if necessary overflowcode }
2188 procedure emitoverflowcheck(p:ptree);
2190 hl : pasmlabel;
2191 begin
2192 if not(cs_check_overflow in aktlocalswitches) then
2193 exit;
2194 getlabel(hl);
2195 if not ((p^.resulttype^.deftype=pointerdef) or
2196 ((p^.resulttype^.deftype=orddef) and
2197 (porddef(p^.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
2198 bool8bit,bool16bit,bool32bit]))) then
2199 emitjmp(C_NO,hl)
2200 else
2201 emitjmp(C_NB,hl);
2202 emitcall('FPC_OVERFLOW');
2203 emitlab(hl);
2204 end;
2206 { produces range check code, while one of the operands is a 64 bit
2207 integer }
2208 procedure emitrangecheck64(p : ptree;todef : pdef);
2211 neglabel,
2212 poslabel,
2213 endlabel: pasmlabel;
2214 href : preference;
2215 hreg : tregister;
2216 hdef : porddef;
2217 fromdef : pdef;
2218 opcode : tasmop;
2219 opsize : topsize;
2220 oldregisterdef: boolean;
2221 from_signed,to_signed: boolean;
2223 begin
2224 fromdef:=p^.resulttype;
2225 from_signed := is_signed(fromdef);
2226 to_signed := is_signed(todef);
2228 if not is_64bitint(todef) then
2229 begin
2230 oldregisterdef := registerdef;
2231 registerdef := false;
2233 { get the high dword in a register }
2234 if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
2235 hreg := p^.location.registerhigh
2236 else
2237 begin
2238 hreg := getexplicitregister32(R_EDI);
2239 href := newreference(p^.location.reference);
2240 inc(href^.offset,4);
2241 emit_ref_reg(A_MOV,S_L,href,hreg);
2242 end;
2243 getlabel(poslabel);
2245 { check high dword, must be 0 (for positive numbers) }
2246 emit_reg_reg(A_TEST,S_L,hreg,hreg);
2247 emitjmp(C_E,poslabel);
2249 { It can also be $ffffffff, but only for negative numbers }
2250 if from_signed and to_signed then
2251 begin
2252 getlabel(neglabel);
2253 emit_const_reg(A_CMP,S_L,$ffffffff,hreg);
2254 emitjmp(C_E,neglabel);
2255 end;
2256 if hreg = R_EDI then
2257 ungetregister32(hreg);
2258 { For all other values we have a range check error }
2259 emitcall('FPC_RANGEERROR');
2261 { if the high dword = 0, the low dword can be considered a }
2262 { simple cardinal }
2263 emitlab(poslabel);
2264 new(hdef,init(u32bit,0,$ffffffff));
2265 { the real p^.resulttype is already saved in fromdef }
2266 p^.resulttype := hdef;
2267 emitrangecheck(p,todef);
2268 dispose(hdef,done);
2269 { restore original resulttype }
2270 p^.resulttype := todef;
2272 if from_signed and to_signed then
2273 begin
2274 getlabel(endlabel);
2275 emitjmp(C_NO,endlabel);
2276 { if the high dword = $ffffffff, then the low dword (when }
2277 { considered as a longint) must be < 0 }
2278 emitlab(neglabel);
2279 if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
2280 hreg := p^.location.registerlow
2281 else
2282 begin
2283 hreg := getexplicitregister32(R_EDI);
2284 emit_ref_reg(A_MOV,S_L,
2285 newreference(p^.location.reference),hreg);
2286 end;
2287 { get a new neglabel (JM) }
2288 getlabel(neglabel);
2289 emit_reg_reg(A_TEST,S_L,hreg,hreg);
2290 if hreg = R_EDI then
2291 ungetregister32(hreg);
2292 emitjmp(C_L,neglabel);
2294 emitcall('FPC_RANGEERROR');
2296 { if we get here, the 64bit value lies between }
2297 { longint($80000000) and -1 (JM) }
2298 emitlab(neglabel);
2299 new(hdef,init(s32bit,$80000000,-1));
2300 p^.resulttype := hdef;
2301 emitrangecheck(p,todef);
2302 dispose(hdef,done);
2303 emitlab(endlabel);
2304 end;
2305 registerdef := oldregisterdef;
2306 p^.resulttype := fromdef;
2307 { restore p's resulttype }
2309 else
2310 { todef = 64bit int }
2311 { no 64bit subranges supported, so only a small check is necessary }
2313 { if both are signed or both are unsigned, no problem! }
2314 if (from_signed xor to_signed) and
2315 { also not if the fromdef is unsigned and < 64bit, since that will }
2316 { always fit in a 64bit int (todef is 64bit) }
2317 (from_signed or
2318 (porddef(fromdef)^.typ = u64bit)) then
2319 begin
2320 { in all cases, there is only a problem if the higest bit is set }
2321 if p^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
2322 if is_64bitint(fromdef) then
2323 hreg := p^.location.registerhigh
2324 else
2325 hreg := p^.location.register
2326 else
2327 begin
2328 hreg := getexplicitregister32(R_EDI);
2329 case p^.resulttype^.size of
2330 1: opsize := S_BL;
2331 2: opsize := S_WL;
2332 4,8: opsize := S_L;
2333 end;
2334 if opsize in [S_BL,S_WL] then
2335 if from_signed then
2336 opcode := A_MOVSX
2337 else opcode := A_MOVZX
2338 else
2339 opcode := A_MOV;
2340 href := newreference(p^.location.reference);
2341 if p^.resulttype^.size = 8 then
2342 inc(href^.offset,4);
2343 emit_ref_reg(opcode,opsize,href,hreg);
2344 end;
2345 getlabel(poslabel);
2346 emit_reg_reg(A_TEST,regsize(hreg),hreg,hreg);
2347 if hreg = R_EDI then
2348 ungetregister32(hreg);
2349 emitjmp(C_GE,poslabel);
2350 emitcall('FPC_RANGEERROR');
2351 emitlab(poslabel);
2352 end;
2353 end;
2355 { produces if necessary rangecheckcode }
2356 procedure emitrangecheck(p:ptree;todef:pdef);
2358 generate range checking code for the value at location t. The
2359 type used is the checked against todefs ranges. fromdef (p^.resulttype)
2360 is the original type used at that location, when both defs are
2361 equal the check is also insert (needed for succ,pref,inc,dec)
2364 neglabel,
2365 poslabel : pasmlabel;
2366 href : treference;
2367 rstr : string;
2368 hreg : tregister;
2369 opsize : topsize;
2370 op : tasmop;
2371 fromdef : pdef;
2372 lto,hto,
2373 lfrom,hfrom : longint;
2374 doublebound,
2375 is_reg,
2376 popecx : boolean;
2377 begin
2378 { range checking on and range checkable value? }
2379 if not(cs_check_range in aktlocalswitches) or
2380 not(todef^.deftype in [orddef,enumdef,arraydef]) then
2381 exit;
2382 { only check when assigning to scalar, subranges are different,
2383 when todef=fromdef then the check is always generated }
2384 fromdef:=p^.resulttype;
2385 if is_64bitint(fromdef) or is_64bitint(todef) then
2386 begin
2387 emitrangecheck64(p,todef);
2388 exit;
2389 end;
2390 {we also need lto and hto when checking if we need to use doublebound!
2391 (JM)}
2392 getrange(todef,lto,hto);
2393 if todef<>fromdef then
2394 begin
2395 getrange(p^.resulttype,lfrom,hfrom);
2396 { first check for not being u32bit, then if the to is bigger than
2397 from }
2398 if (lto<hto) and (lfrom<hfrom) and
2399 (lto<=lfrom) and (hto>=hfrom) then
2400 exit;
2401 end;
2402 { generate the rangecheck code for the def where we are going to
2403 store the result }
2404 doublebound:=false;
2405 case todef^.deftype of
2406 orddef :
2407 begin
2408 porddef(todef)^.genrangecheck;
2409 rstr:=porddef(todef)^.getrangecheckstring;
2410 doublebound:=
2411 ((porddef(todef)^.typ=u32bit) and (lto>hto)) or
2412 (is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
2413 (is_signed(fromdef) and (porddef(todef)^.typ=u32bit));
2414 end;
2415 enumdef :
2416 begin
2417 penumdef(todef)^.genrangecheck;
2418 rstr:=penumdef(todef)^.getrangecheckstring;
2419 end;
2420 arraydef :
2421 begin
2422 parraydef(todef)^.genrangecheck;
2423 rstr:=parraydef(todef)^.getrangecheckstring;
2424 doublebound:=(lto>hto);
2425 end;
2426 end;
2427 { get op and opsize }
2428 opsize:=def2def_opsize(fromdef,u32bitdef);
2429 if opsize in [S_B,S_W,S_L] then
2430 op:=A_MOV
2431 else
2432 if is_signed(fromdef) then
2433 op:=A_MOVSX
2434 else
2435 op:=A_MOVZX;
2436 is_reg:=(p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
2437 if is_reg then
2438 hreg:=p^.location.register;
2439 if not target_os.use_bound_instruction then
2440 begin
2441 { FPC_BOUNDCHECK needs to be called with
2442 %ecx - value
2443 %edi - pointer to the ranges }
2444 popecx:=false;
2445 if not(is_reg) or
2446 (p^.location.register<>R_ECX) then
2447 begin
2448 if not(R_ECX in unused) then
2449 begin
2450 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
2451 popecx:=true;
2453 else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
2454 if is_reg then
2455 emit_reg_reg(op,opsize,p^.location.register,R_ECX)
2456 else
2457 emit_ref_reg(op,opsize,newreference(p^.location.reference),R_ECX);
2458 end;
2459 if doublebound then
2460 begin
2461 getlabel(neglabel);
2462 getlabel(poslabel);
2463 emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
2464 emitjmp(C_L,neglabel);
2465 end;
2466 { insert bound instruction only }
2467 getexplicitregister32(R_EDI);
2468 exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
2469 emitcall('FPC_BOUNDCHECK');
2470 ungetregister32(R_EDI);
2471 { u32bit needs 2 checks }
2472 if doublebound then
2473 begin
2474 emitjmp(C_None,poslabel);
2475 emitlab(neglabel);
2476 { if a cardinal is > $7fffffff, this is an illegal longint }
2477 { value (and vice versa)! (JM) }
2478 if ((todef^.deftype = orddef) and
2479 ((is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
2480 (is_signed(fromdef) and (porddef(todef)^.typ=u32bit)))) or
2481 { similar for array indexes (JM) }
2482 ((todef^.deftype = arraydef) and
2483 (((lto < 0) and (porddef(fromdef)^.typ=u32bit)) or
2484 ((lto >= 0) and is_signed(fromdef)))) then
2485 emitcall('FPC_RANGEERROR')
2486 else
2487 begin
2488 getexplicitregister32(R_EDI);
2489 exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
2490 emitcall('FPC_BOUNDCHECK');
2491 ungetregister32(R_EDI);
2492 end;
2493 emitlab(poslabel);
2494 end;
2495 if popecx then
2496 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
2497 else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
2499 else
2500 begin
2501 reset_reference(href);
2502 href.symbol:=newasmsymbol(rstr);
2503 { load the value in a register }
2504 if is_reg then
2505 begin
2506 { be sure that hreg is a 32 bit reg, if not load it in %edi }
2507 if p^.location.register in [R_EAX..R_EDI] then
2508 hreg:=p^.location.register
2509 else
2510 begin
2511 getexplicitregister32(R_EDI);
2512 emit_reg_reg(op,opsize,p^.location.register,R_EDI);
2513 hreg:=R_EDI;
2514 end;
2516 else
2517 begin
2518 getexplicitregister32(R_EDI);
2519 emit_ref_reg(op,opsize,newreference(p^.location.reference),R_EDI);
2520 hreg:=R_EDI;
2521 end;
2522 if doublebound then
2523 begin
2524 getlabel(neglabel);
2525 getlabel(poslabel);
2526 emit_reg_reg(A_TEST,S_L,hreg,hreg);
2527 emitjmp(C_L,neglabel);
2528 end;
2529 { insert bound instruction only }
2530 exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
2531 { u32bit needs 2 checks }
2532 if doublebound then
2533 begin
2534 href.offset:=8;
2535 emitjmp(C_None,poslabel);
2536 emitlab(neglabel);
2537 exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
2538 emitlab(poslabel);
2539 end;
2540 if hreg = R_EDI then
2541 ungetregister32(R_EDI);
2542 end;
2543 end;
2546 procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
2548 const
2549 isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
2550 ishr : array[0..3] of byte=(2,0,1,0);
2553 ecxpushed : boolean;
2554 helpsize : longint;
2555 i : byte;
2556 reg8,reg32 : tregister;
2557 swap : boolean;
2559 procedure maybepushecx;
2560 begin
2561 if not(R_ECX in unused) then
2562 begin
2563 exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
2564 ecxpushed:=true;
2566 else getexplicitregister32(R_ECX);
2567 end;
2569 begin
2570 {$IfNDef regallocfix}
2571 If delsource then
2572 del_reference(source);
2573 {$EndIf regallocfix}
2574 if (not loadref) and
2575 ((size<=8) or
2576 (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
2577 begin
2578 helpsize:=size shr 2;
2579 {$ifndef noAllocEdi}
2580 getexplicitregister32(R_EDI);
2581 {$endif noAllocEdi}
2582 for i:=1 to helpsize do
2583 begin
2584 emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
2585 {$ifdef regallocfix}
2586 If (size = 4) and delsource then
2587 del_reference(source);
2588 {$endif regallocfix}
2589 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest))));
2590 inc(source.offset,4);
2591 inc(dest.offset,4);
2592 dec(size,4);
2593 end;
2594 if size>1 then
2595 begin
2596 emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
2597 {$ifdef regallocfix}
2598 If (size = 2) and delsource then
2599 del_reference(source);
2600 {$endif regallocfix}
2601 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_W,R_DI,newreference(dest))));
2602 inc(source.offset,2);
2603 inc(dest.offset,2);
2604 dec(size,2);
2605 end;
2606 {$ifndef noAllocEdi}
2607 ungetregister32(R_EDI);
2608 {$endif noAllocEdi}
2609 if size>0 then
2610 begin
2611 { and now look for an 8 bit register }
2612 swap:=false;
2613 if R_EAX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EAX))
2614 else if R_EDX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EDX))
2615 else if R_EBX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EBX))
2616 else if R_ECX in unused then reg8:=reg32toreg8(getexplicitregister32(R_ECX))
2617 else
2618 begin
2619 swap:=true;
2620 { we need only to check 3 registers, because }
2621 { one is always not index or base }
2622 if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
2623 begin
2624 reg8:=R_AL;
2625 reg32:=R_EAX;
2627 else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
2628 begin
2629 reg8:=R_BL;
2630 reg32:=R_EBX;
2632 else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
2633 begin
2634 reg8:=R_CL;
2635 reg32:=R_ECX;
2636 end;
2637 end;
2638 if swap then
2639 { was earlier XCHG, of course nonsense }
2640 begin
2641 {$ifndef noAllocEdi}
2642 getexplicitregister32(R_EDI);
2643 {$endif noAllocEdi}
2644 emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
2645 end;
2646 emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
2647 {$ifdef regallocfix}
2648 If delsource then
2649 del_reference(source);
2650 {$endif regallocfix}
2651 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_B,reg8,newreference(dest))));
2652 if swap then
2653 begin
2654 emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
2655 {$ifndef noAllocEdi}
2656 ungetregister32(R_EDI);
2657 {$endif noAllocEdi}
2659 else
2660 ungetregister(reg8);
2661 end;
2663 else
2664 begin
2665 {$ifndef noAllocEdi}
2666 getexplicitregister32(R_EDI);
2667 {$endif noAllocEdi}
2668 emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
2669 {$ifdef regallocfix}
2670 {is this ok?? (JM)}
2671 del_reference(dest);
2672 {$endif regallocfix}
2673 {$ifndef noAllocEdi}
2674 exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
2675 {$endif noAllocEdi}
2676 if loadref then
2677 emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
2678 else
2679 begin
2680 emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
2681 {$ifdef regallocfix}
2682 if delsource then
2683 del_reference(source);
2684 {$endif regallocfix}
2685 end;
2687 exprasmlist^.concat(new(paicpu,op_none(A_CLD,S_NO)));
2688 ecxpushed:=false;
2689 if cs_littlesize in aktglobalswitches then
2690 begin
2691 maybepushecx;
2692 emit_const_reg(A_MOV,S_L,size,R_ECX);
2693 exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
2694 exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
2696 else
2697 begin
2698 helpsize:=size shr 2;
2699 size:=size and 3;
2700 if helpsize>1 then
2701 begin
2702 maybepushecx;
2703 emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
2704 exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
2705 end;
2706 if helpsize>0 then
2707 exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
2708 if size>1 then
2709 begin
2710 dec(size,2);
2711 exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
2712 end;
2713 if size=1 then
2714 exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
2715 end;
2716 {$ifndef noAllocEdi}
2717 ungetregister32(R_EDI);
2718 exprasmlist^.concat(new(pairegalloc,dealloc(R_ESI)));
2719 {$endif noAllocEdi}
2720 if ecxpushed then
2721 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
2722 else
2723 ungetregister32(R_ECX);
2725 { loading SELF-reference again }
2726 maybe_loadesi;
2727 end;
2728 if delsource then
2729 ungetiftemp(source);
2730 end;
2733 procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;
2734 destreg:Tregister;delloc:boolean);
2736 {A lot smaller and less bug sensitive than the original unfolded loads.}
2738 var tai:Paicpu;
2739 r:Preference;
2741 begin
2742 tai := nil;
2743 case location.loc of
2744 LOC_REGISTER,LOC_CREGISTER:
2745 begin
2746 case orddef^.typ of
2747 u8bit:
2748 tai:=new(paicpu,op_reg_reg(A_MOVZX,S_BL,location.register,destreg));
2749 s8bit:
2750 tai:=new(paicpu,op_reg_reg(A_MOVSX,S_BL,location.register,destreg));
2751 u16bit:
2752 tai:=new(paicpu,op_reg_reg(A_MOVZX,S_WL,location.register,destreg));
2753 s16bit:
2754 tai:=new(paicpu,op_reg_reg(A_MOVSX,S_WL,location.register,destreg));
2755 u32bit,s32bit:
2756 if location.register <> destreg then
2757 tai:=new(paicpu,op_reg_reg(A_MOV,S_L,location.register,destreg));
2758 end;
2759 if delloc then
2760 ungetregister(location.register);
2761 end;
2762 LOC_MEM,
2763 LOC_REFERENCE:
2764 begin
2765 if location.reference.is_immediate then
2766 tai:=new(paicpu,op_const_reg(A_MOV,S_L,location.reference.offset,destreg))
2767 else
2768 begin
2769 r:=newreference(location.reference);
2770 case orddef^.typ of
2771 u8bit:
2772 tai:=new(paicpu,op_ref_reg(A_MOVZX,S_BL,r,destreg));
2773 s8bit:
2774 tai:=new(paicpu,op_ref_reg(A_MOVSX,S_BL,r,destreg));
2775 u16bit:
2776 tai:=new(paicpu,op_ref_reg(A_MOVZX,S_WL,r,destreg));
2777 s16bit:
2778 tai:=new(paicpu,op_ref_reg(A_MOVSX,S_WL,r,destreg));
2779 u32bit:
2780 tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
2781 s32bit:
2782 tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
2783 end;
2784 end;
2785 if delloc then
2786 del_reference(location.reference);
2788 else
2789 internalerror(6);
2790 end;
2791 if assigned(tai) then
2792 exprasmlist^.concat(tai);
2793 end;
2795 { if necessary ESI is reloaded after a call}
2796 procedure maybe_loadesi;
2799 hp : preference;
2800 p : pprocinfo;
2801 i : longint;
2803 begin
2804 if assigned(procinfo^._class) then
2805 begin
2806 {$ifndef noAllocEdi}
2807 exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
2808 {$endif noAllocEdi}
2809 if lexlevel>normal_function_level then
2810 begin
2811 new(hp);
2812 reset_reference(hp^);
2813 hp^.offset:=procinfo^.framepointer_offset;
2814 hp^.base:=procinfo^.framepointer;
2815 emit_ref_reg(A_MOV,S_L,hp,R_ESI);
2816 p:=procinfo^.parent;
2817 for i:=3 to lexlevel-1 do
2818 begin
2819 new(hp);
2820 reset_reference(hp^);
2821 hp^.offset:=p^.framepointer_offset;
2822 hp^.base:=R_ESI;
2823 emit_ref_reg(A_MOV,S_L,hp,R_ESI);
2824 p:=p^.parent;
2825 end;
2826 new(hp);
2827 reset_reference(hp^);
2828 hp^.offset:=p^.selfpointer_offset;
2829 hp^.base:=R_ESI;
2830 emit_ref_reg(A_MOV,S_L,hp,R_ESI);
2832 else
2833 begin
2834 new(hp);
2835 reset_reference(hp^);
2836 hp^.offset:=procinfo^.selfpointer_offset;
2837 hp^.base:=procinfo^.framepointer;
2838 emit_ref_reg(A_MOV,S_L,hp,R_ESI);
2839 end;
2840 end;
2841 end;
2844 { DO NOT RELY on the fact that the ptree is not yet swaped
2845 because of inlining code PM }
2846 procedure firstcomplex(p : ptree);
2848 hp : ptree;
2849 begin
2850 { always calculate boolean AND and OR from left to right }
2851 if (p^.treetype in [orn,andn]) and
2852 (p^.left^.resulttype^.deftype=orddef) and
2853 (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
2854 begin
2855 { p^.swaped:=false}
2856 if p^.swaped then
2857 internalerror(234234);
2859 else
2860 if (p^.left^.registers32<p^.right^.registers32) and
2861 { the following check is appropriate, because all }
2862 { 4 registers are rarely used and it is thereby }
2863 { achieved that the extra code is being dropped }
2864 { by exchanging not commutative operators }
2865 (p^.right^.registers32<=4) then
2866 begin
2867 hp:=p^.left;
2868 p^.left:=p^.right;
2869 p^.right:=hp;
2870 p^.swaped:=not p^.swaped;
2871 end;
2872 {else
2873 p^.swaped:=false; do not modify }
2874 end;
2877 {*****************************************************************************
2878 Entry/Exit Code Functions
2879 *****************************************************************************}
2881 procedure genprofilecode;
2883 pl : pasmlabel;
2884 begin
2885 if (po_assembler in aktprocsym^.definition^.procoptions) then
2886 exit;
2887 case target_info.target of
2888 target_i386_freebsd,
2889 target_i386_linux:
2890 begin
2891 getlabel(pl);
2892 emitinsertcall('mcount');
2893 usedinproc:=usedinproc or ($80 shr byte(R_EDX));
2894 exprasmlist^.insert(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX)));
2895 exprasmlist^.insert(new(pai_section,init(sec_code)));
2896 exprasmlist^.insert(new(pai_const,init_32bit(0)));
2897 exprasmlist^.insert(new(pai_label,init(pl)));
2898 exprasmlist^.insert(new(pai_align,init(4)));
2899 exprasmlist^.insert(new(pai_section,init(sec_data)));
2900 end;
2902 target_i386_go32v2:
2903 begin
2904 emitinsertcall('MCOUNT');
2905 end;
2906 end;
2907 end;
2910 procedure generate_interrupt_stackframe_entry;
2911 begin
2912 { save the registers of an interrupt procedure }
2913 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EAX)));
2914 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
2915 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
2916 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDX)));
2917 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
2918 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
2920 { .... also the segment registers }
2921 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_DS)));
2922 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_ES)));
2923 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_FS)));
2924 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_GS)));
2925 end;
2928 procedure generate_interrupt_stackframe_exit;
2929 begin
2930 { restore the registers of an interrupt procedure }
2931 { this was all with entrycode instead of exitcode !!}
2932 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EAX)));
2933 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
2934 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
2935 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDX)));
2936 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
2937 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
2939 { .... also the segment registers }
2940 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_DS)));
2941 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_ES)));
2942 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_FS)));
2943 procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_GS)));
2945 { this restores the flags }
2946 procinfo^.aktexitcode^.concat(new(paicpu,op_none(A_IRET,S_NO)));
2947 end;
2950 { generates the code for threadvar initialisation }
2951 procedure initialize_threadvar(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
2954 hr : treference;
2956 begin
2957 if (psym(p)^.typ=varsym) and
2958 (vo_is_thread_var in pvarsym(p)^.varoptions) then
2959 begin
2960 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,pvarsym(p)^.getsize)));
2961 reset_reference(hr);
2962 hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
2963 emitpushreferenceaddr(hr);
2964 emitcall('FPC_INIT_THREADVAR');
2965 end;
2966 end;
2968 { initilizes data of type t }
2969 { if is_already_ref is true then the routines assumes }
2970 { that r points to the data to initialize }
2971 procedure initialize(t : pdef;const ref : treference;is_already_ref : boolean);
2974 hr : treference;
2976 begin
2977 if is_ansistring(t) or
2978 is_widestring(t) then
2979 begin
2980 emit_const_ref(A_MOV,S_L,0,
2981 newreference(ref));
2983 else
2984 begin
2985 reset_reference(hr);
2986 hr.symbol:=t^.get_inittable_label;
2987 emitpushreferenceaddr(hr);
2988 if is_already_ref then
2989 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
2990 newreference(ref))))
2991 else
2992 emitpushreferenceaddr(ref);
2993 emitcall('FPC_INITIALIZE');
2994 end;
2995 end;
2997 { finalizes data of type t }
2998 { if is_already_ref is true then the routines assumes }
2999 { that r points to the data to finalizes }
3000 procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
3003 r : treference;
3005 begin
3006 if is_ansistring(t) or
3007 is_widestring(t) then
3008 begin
3009 decrstringref(t,ref);
3011 else
3012 begin
3013 reset_reference(r);
3014 r.symbol:=t^.get_inittable_label;
3015 emitpushreferenceaddr(r);
3016 if is_already_ref then
3017 exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
3018 newreference(ref))))
3019 else
3020 emitpushreferenceaddr(ref);
3021 emitcall('FPC_FINALIZE');
3022 end;
3023 end;
3026 { generates the code for initialisation of local data }
3027 procedure initialize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
3030 hr : treference;
3032 begin
3033 if (psym(p)^.typ=varsym) and
3034 assigned(pvarsym(p)^.vartype.def) and
3035 not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
3036 pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
3037 pvarsym(p)^.vartype.def^.needs_inittable then
3038 begin
3039 if assigned(procinfo) then
3040 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3041 reset_reference(hr);
3042 if psym(p)^.owner^.symtabletype in [localsymtable,inlinelocalsymtable] then
3043 begin
3044 hr.base:=procinfo^.framepointer;
3045 hr.offset:=-pvarsym(p)^.address+pvarsym(p)^.owner^.address_fixup;
3047 else
3048 begin
3049 hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
3050 end;
3051 initialize(pvarsym(p)^.vartype.def,hr,false);
3052 end;
3053 end;
3055 { generates the code for incrementing the reference count of parameters }
3056 procedure incr_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
3059 hr : treference;
3061 begin
3062 if (psym(p)^.typ=varsym) and
3063 not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
3064 pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
3065 pvarsym(p)^.vartype.def^.needs_inittable and
3066 (not assigned(pvarsym(p)^.localvarsym)) and
3067 ((pvarsym(p)^.varspez=vs_value) {or
3068 (pvarsym(p)^.varspez=vs_const) and
3069 not(dont_copy_const_param(pvarsym(p)^.definition))}) then
3070 begin
3071 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3072 reset_reference(hr);
3073 hr.symbol:=pvarsym(p)^.vartype.def^.get_inittable_label;
3074 emitpushreferenceaddr(hr);
3075 reset_reference(hr);
3076 hr.base:=procinfo^.framepointer;
3077 hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3079 emitpushreferenceaddr(hr);
3080 reset_reference(hr);
3082 emitcall('FPC_ADDREF');
3083 end;
3084 end;
3086 { generates the code for finalisation of local data }
3087 procedure finalize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
3090 hr : treference;
3092 begin
3093 if (psym(p)^.typ=varsym) and
3094 assigned(pvarsym(p)^.vartype.def) and
3095 not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
3096 pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
3097 (not assigned(pvarsym(p)^.localvarsym)) and
3098 pvarsym(p)^.vartype.def^.needs_inittable then
3099 begin
3100 { not all kind of parameters need to be finalized }
3101 if (psym(p)^.owner^.symtabletype=parasymtable) and
3102 ((pvarsym(p)^.varspez=vs_var) or
3103 (pvarsym(p)^.varspez=vs_const) { and
3104 (dont_copy_const_param(pvarsym(p)^.definition)) } ) then
3105 exit;
3106 if assigned(procinfo) then
3107 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3108 reset_reference(hr);
3109 case psym(p)^.owner^.symtabletype of
3110 localsymtable,inlinelocalsymtable:
3111 begin
3112 hr.base:=procinfo^.framepointer;
3113 hr.offset:=-pvarsym(p)^.address+pvarsym(p)^.owner^.address_fixup;
3114 end;
3115 parasymtable,inlineparasymtable:
3116 begin
3117 hr.base:=procinfo^.framepointer;
3118 hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3119 end;
3120 else
3121 hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
3122 end;
3123 finalize(pvarsym(p)^.vartype.def,hr,false);
3124 end;
3125 end;
3128 { generates the code to make local copies of the value parameters }
3129 procedure copyvalueparas(p : pnamedindexobject);{$ifndef fpc}far;{$endif}
3131 href1,href2 : treference;
3132 r : preference;
3133 power,len : longint;
3134 opsize : topsize;
3135 again,ok : pasmlabel;
3136 begin
3137 if (psym(p)^.typ=varsym) and
3138 (pvarsym(p)^.varspez=vs_value) and
3139 (push_addr_param(pvarsym(p)^.vartype.def)) then
3140 begin
3141 if is_open_array(pvarsym(p)^.vartype.def) or
3142 is_array_of_const(pvarsym(p)^.vartype.def) then
3143 begin
3144 { get stack space }
3145 new(r);
3146 reset_reference(r^);
3147 r^.base:=procinfo^.framepointer;
3148 r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
3149 {$ifndef noAllocEdi}
3150 getexplicitregister32(R_EDI);
3151 {$endif noAllocEdi}
3152 exprasmlist^.concat(new(paicpu,
3153 op_ref_reg(A_MOV,S_L,r,R_EDI)));
3155 exprasmlist^.concat(new(paicpu,
3156 op_reg(A_INC,S_L,R_EDI)));
3158 if (parraydef(pvarsym(p)^.vartype.def)^.elesize<>1) then
3159 begin
3160 if ispowerof2(parraydef(pvarsym(p)^.vartype.def)^.elesize, power) then
3161 exprasmlist^.concat(new(paicpu,
3162 op_const_reg(A_SHL,S_L,
3163 power,R_EDI)))
3164 else
3165 exprasmlist^.concat(new(paicpu,
3166 op_const_reg(A_IMUL,S_L,
3167 parraydef(pvarsym(p)^.vartype.def)^.elesize,R_EDI)));
3168 end;
3169 {$ifndef NOTARGETWIN32}
3170 { windows guards only a few pages for stack growing, }
3171 { so we have to access every page first }
3172 if target_os.id=os_i386_win32 then
3173 begin
3174 getlabel(again);
3175 getlabel(ok);
3176 emitlab(again);
3177 exprasmlist^.concat(new(paicpu,
3178 op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI)));
3179 emitjmp(C_C,ok);
3180 exprasmlist^.concat(new(paicpu,
3181 op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
3182 exprasmlist^.concat(new(paicpu,
3183 op_reg(A_PUSH,S_L,R_EAX)));
3184 exprasmlist^.concat(new(paicpu,
3185 op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI)));
3186 emitjmp(C_None,again);
3188 emitlab(ok);
3189 exprasmlist^.concat(new(paicpu,
3190 op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
3191 {$ifndef noAllocEdi}
3192 ungetregister32(R_EDI);
3193 {$endif noAllocEdi}
3194 { now reload EDI }
3195 new(r);
3196 reset_reference(r^);
3197 r^.base:=procinfo^.framepointer;
3198 r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
3199 {$ifndef noAllocEdi}
3200 getexplicitregister32(R_EDI);
3201 {$endif noAllocEdi}
3202 exprasmlist^.concat(new(paicpu,
3203 op_ref_reg(A_MOV,S_L,r,R_EDI)));
3205 exprasmlist^.concat(new(paicpu,
3206 op_reg(A_INC,S_L,R_EDI)));
3208 if (parraydef(pvarsym(p)^.vartype.def)^.elesize<>1) then
3209 begin
3210 if ispowerof2(parraydef(pvarsym(p)^.vartype.def)^.elesize, power) then
3211 exprasmlist^.concat(new(paicpu,
3212 op_const_reg(A_SHL,S_L,
3213 power,R_EDI)))
3214 else
3215 exprasmlist^.concat(new(paicpu,
3216 op_const_reg(A_IMUL,S_L,
3217 parraydef(pvarsym(p)^.vartype.def)^.elesize,R_EDI)));
3218 end;
3220 else
3221 {$endif NOTARGETWIN32}
3222 exprasmlist^.concat(new(paicpu,
3223 op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
3224 { load destination }
3225 exprasmlist^.concat(new(paicpu,
3226 op_reg_reg(A_MOV,S_L,R_ESP,R_EDI)));
3228 { don't destroy the registers! }
3229 exprasmlist^.concat(new(paicpu,
3230 op_reg(A_PUSH,S_L,R_ECX)));
3231 exprasmlist^.concat(new(paicpu,
3232 op_reg(A_PUSH,S_L,R_ESI)));
3234 { load count }
3235 new(r);
3236 reset_reference(r^);
3237 r^.base:=procinfo^.framepointer;
3238 r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
3239 exprasmlist^.concat(new(paicpu,
3240 op_ref_reg(A_MOV,S_L,r,R_ECX)));
3242 { load source }
3243 new(r);
3244 reset_reference(r^);
3245 r^.base:=procinfo^.framepointer;
3246 r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3247 exprasmlist^.concat(new(paicpu,
3248 op_ref_reg(A_MOV,S_L,r,R_ESI)));
3250 { scheduled .... }
3251 exprasmlist^.concat(new(paicpu,
3252 op_reg(A_INC,S_L,R_ECX)));
3254 { calculate size }
3255 len:=parraydef(pvarsym(p)^.vartype.def)^.elesize;
3256 opsize:=S_B;
3257 if (len and 3)=0 then
3258 begin
3259 opsize:=S_L;
3260 len:=len shr 2;
3262 else
3263 if (len and 1)=0 then
3264 begin
3265 opsize:=S_W;
3266 len:=len shr 1;
3267 end;
3269 if ispowerof2(len, power) then
3270 exprasmlist^.concat(new(paicpu,
3271 op_const_reg(A_SHL,S_L,
3272 power,R_ECX)))
3273 else
3274 exprasmlist^.concat(new(paicpu,
3275 op_const_reg(A_IMUL,S_L,len,R_ECX)));
3276 exprasmlist^.concat(new(paicpu,
3277 op_none(A_REP,S_NO)));
3278 case opsize of
3279 S_B : exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
3280 S_W : exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
3281 S_L : exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
3282 end;
3283 {$ifndef noAllocEdi}
3284 ungetregister32(R_EDI);
3285 {$endif noAllocEdi}
3286 exprasmlist^.concat(new(paicpu,
3287 op_reg(A_POP,S_L,R_ESI)));
3288 exprasmlist^.concat(new(paicpu,
3289 op_reg(A_POP,S_L,R_ECX)));
3291 { patch the new address }
3292 new(r);
3293 reset_reference(r^);
3294 r^.base:=procinfo^.framepointer;
3295 r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3296 exprasmlist^.concat(new(paicpu,
3297 op_reg_ref(A_MOV,S_L,R_ESP,r)));
3299 else
3300 if is_shortstring(pvarsym(p)^.vartype.def) then
3301 begin
3302 reset_reference(href1);
3303 href1.base:=procinfo^.framepointer;
3304 href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3305 reset_reference(href2);
3306 href2.base:=procinfo^.framepointer;
3307 href2.offset:=-pvarsym(p)^.localvarsym^.address+pvarsym(p)^.localvarsym^.owner^.address_fixup;
3308 copyshortstring(href2,href1,pstringdef(pvarsym(p)^.vartype.def)^.len,true,false);
3310 else
3311 begin
3312 reset_reference(href1);
3313 href1.base:=procinfo^.framepointer;
3314 href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
3315 reset_reference(href2);
3316 href2.base:=procinfo^.framepointer;
3317 href2.offset:=-pvarsym(p)^.localvarsym^.address+pvarsym(p)^.localvarsym^.owner^.address_fixup;
3318 concatcopy(href1,href2,pvarsym(p)^.vartype.def^.size,true,true);
3319 end;
3320 end;
3321 end;
3323 procedure inittempansistrings;
3326 hp : ptemprecord;
3327 r : preference;
3329 begin
3330 hp:=templist;
3331 while assigned(hp) do
3332 begin
3333 if hp^.temptype in [tt_ansistring,tt_freeansistring] then
3334 begin
3335 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3336 new(r);
3337 reset_reference(r^);
3338 r^.base:=procinfo^.framepointer;
3339 r^.offset:=hp^.pos;
3340 emit_const_ref(A_MOV,S_L,0,r);
3341 end;
3342 hp:=hp^.next;
3343 end;
3344 end;
3346 procedure finalizetempansistrings;
3349 hp : ptemprecord;
3350 hr : treference;
3351 begin
3352 hp:=templist;
3353 while assigned(hp) do
3354 begin
3355 if hp^.temptype in [tt_ansistring,tt_freeansistring] then
3356 begin
3357 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3358 reset_reference(hr);
3359 hr.base:=procinfo^.framepointer;
3360 hr.offset:=hp^.pos;
3361 emitpushreferenceaddr(hr);
3362 emitcall('FPC_ANSISTR_DECR_REF');
3363 end;
3364 hp:=hp^.next;
3365 end;
3366 end;
3369 ls : longint;
3371 procedure largest_size(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
3373 begin
3374 if (psym(p)^.typ=varsym) and
3375 (pvarsym(p)^.getvaluesize>ls) then
3376 ls:=pvarsym(p)^.getvaluesize;
3377 end;
3379 procedure alignstack(alist : paasmoutput);
3381 begin
3382 {$ifdef dummy}
3383 if (cs_optimize in aktglobalswitches) and
3384 (aktoptprocessor in [classp5,classp6]) then
3385 begin
3386 ls:=0;
3387 aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}largest_size);
3388 if ls>=8 then
3389 alist^.insert(new(paicpu,op_const_reg(A_AND,S_L,-8,R_ESP)));
3390 end;
3391 {$endif dummy}
3392 end;
3394 procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
3395 stackframe:longint;
3396 var parasize:longint;var nostackframe:boolean;
3397 inlined : boolean);
3399 Generates the entry code for a procedure
3402 hs : string;
3403 {$ifdef GDB}
3404 stab_function_name : Pai_stab_function_name;
3405 {$endif GDB}
3406 hr : preference;
3407 p : psymtable;
3408 r : treference;
3409 oldlist,
3410 oldexprasmlist : paasmoutput;
3411 again : pasmlabel;
3412 i : longint;
3414 begin
3415 oldexprasmlist:=exprasmlist;
3416 exprasmlist:=alist;
3417 if (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
3418 begin
3419 emitinsertcall('FPC_INITIALIZEUNITS');
3420 if target_info.target=target_I386_WIN32 then
3421 begin
3422 new(hr);
3423 reset_reference(hr^);
3424 hr^.symbol:=newasmsymbol(
3425 'U_SYSWIN32_ISCONSOLE');
3426 if apptype=at_cui then
3427 exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
3428 1,hr)))
3429 else
3430 exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
3431 0,hr)));
3432 end;
3434 oldlist:=exprasmlist;
3435 exprasmlist:=new(paasmoutput,init);
3436 p:=symtablestack;
3437 while assigned(p) do
3438 begin
3439 p^.foreach({$ifndef TP}@{$endif}initialize_threadvar);
3440 p:=p^.next;
3441 end;
3442 oldlist^.insertlist(exprasmlist);
3443 dispose(exprasmlist,done);
3444 exprasmlist:=oldlist;
3445 end;
3447 {$ifdef GDB}
3448 if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
3449 exprasmlist^.insert(new(pai_force_line,init));
3450 {$endif GDB}
3452 { a constructor needs a help procedure }
3453 if (aktprocsym^.definition^.proctypeoption=potype_constructor) then
3454 begin
3455 if procinfo^._class^.is_class then
3456 begin
3457 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3458 exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
3459 emitinsertcall('FPC_NEW_CLASS');
3461 else
3462 begin
3463 exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
3464 emitinsertcall('FPC_HELP_CONSTRUCTOR');
3465 {$ifndef noAllocEdi}
3466 getexplicitregister32(R_EDI);
3467 {$endif noAllocEdi}
3468 exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
3469 end;
3470 end;
3472 { don't load ESI, does the caller }
3473 { we must do it for local function }
3474 { that can be called from a foreach }
3475 { of another object than self !! PM }
3477 if assigned(procinfo^._class) and
3478 (lexlevel>normal_function_level) then
3479 maybe_loadesi;
3481 { When message method contains self as a parameter,
3482 we must load it into ESI }
3483 If (po_containsself in aktprocsym^.definition^.procoptions) then
3484 begin
3485 new(hr);
3486 reset_reference(hr^);
3487 hr^.offset:=procinfo^.selfpointer_offset;
3488 hr^.base:=procinfo^.framepointer;
3489 exprasmlist^.insert(new(paicpu,op_ref_reg(A_MOV,S_L,hr,R_ESI)));
3490 {$ifndef noAllocEdi}
3491 exprasmlist^.insert(new(pairegalloc,alloc(R_ESI)));
3492 {$endif noAllocEdi}
3493 end;
3494 { should we save edi,esi,ebx like C ? }
3495 if (po_savestdregs in aktprocsym^.definition^.procoptions) then
3496 begin
3497 if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
3498 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
3499 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
3500 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
3501 end;
3503 { for the save all registers we can simply use a pusha,popa which
3504 push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
3505 if (po_saveregisters in aktprocsym^.definition^.procoptions) then
3506 begin
3507 exprasmlist^.insert(new(paicpu,op_none(A_PUSHA,S_L)));
3508 end;
3510 { omit stack frame ? }
3511 if not inlined then
3512 if procinfo^.framepointer=stack_pointer then
3513 begin
3514 CGMessage(cg_d_stackframe_omited);
3515 nostackframe:=true;
3516 if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
3517 parasize:=0
3518 else
3519 parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-4;
3520 if stackframe<>0 then
3521 exprasmlist^.insert(new(paicpu,
3522 op_const_reg(A_SUB,S_L,stackframe,R_ESP)));
3524 else
3525 begin
3526 alignstack(alist);
3527 if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
3528 parasize:=0
3529 else
3530 parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-8;
3531 nostackframe:=false;
3532 if stackframe<>0 then
3533 begin
3534 {$ifdef unused}
3535 if (cs_littlesize in aktglobalswitches) and (stackframe<=65535) then
3536 begin
3537 if (cs_check_stack in aktlocalswitches) and
3538 not(target_info.target in [target_386_freebsd,
3539 target_i386_linux,target_i386_win32]) then
3540 begin
3541 emitinsertcall('FPC_STACKCHECK');
3542 exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
3543 end;
3544 if cs_profile in aktmoduleswitches then
3545 genprofilecode;
3547 { %edi is already saved when pocdecl is used
3548 if ((target_info.target=target_linux) or (target_info.target=target_freebsd)) and
3549 ((aktprocsym^.definition^.options and poexports)<>0) then
3550 exprasmlist^.insert(new(Paicpu,op_reg(A_PUSH,S_L,R_EDI))); }
3551 { ATTENTION:
3552 never use ENTER in linux !!! (or freebsd MvdV)
3553 the stack page fault does not support it PM }
3554 exprasmlist^.insert(new(paicpu,op_const_const(A_ENTER,S_NO,stackframe,0)))
3556 else
3557 {$endif unused}
3558 begin
3559 { windows guards only a few pages for stack growing, }
3560 { so we have to access every page first }
3561 if (target_os.id=os_i386_win32) and
3562 (stackframe>=winstackpagesize) then
3563 begin
3564 if stackframe div winstackpagesize<=5 then
3565 begin
3566 exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe-4,R_ESP)));
3567 for i:=1 to stackframe div winstackpagesize do
3568 begin
3569 hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
3570 exprasmlist^.concat(new(paicpu,
3571 op_const_ref(A_MOV,S_L,0,hr)));
3572 end;
3573 exprasmlist^.concat(new(paicpu,
3574 op_reg(A_PUSH,S_L,R_EAX)));
3576 else
3577 begin
3578 getlabel(again);
3579 {$ifndef noAllocEdi}
3580 getexplicitregister32(R_EDI);
3581 {$endif noAllocEdi}
3582 exprasmlist^.concat(new(paicpu,
3583 op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI)));
3584 emitlab(again);
3585 exprasmlist^.concat(new(paicpu,
3586 op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
3587 exprasmlist^.concat(new(paicpu,
3588 op_reg(A_PUSH,S_L,R_EAX)));
3589 exprasmlist^.concat(new(paicpu,
3590 op_reg(A_DEC,S_L,R_EDI)));
3591 emitjmp(C_NZ,again);
3592 {$ifndef noAllocEdi}
3593 ungetregister32(R_EDI);
3594 {$endif noAllocEdi}
3595 exprasmlist^.concat(new(paicpu,
3596 op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP)));
3599 else
3600 exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe,R_ESP)));
3601 if (cs_check_stack in aktlocalswitches) and
3602 not(target_info.target in [target_i386_freebsd,
3603 target_i386_linux,target_i386_win32]) then
3604 begin
3605 emitinsertcall('FPC_STACKCHECK');
3606 exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
3607 end;
3608 if cs_profile in aktmoduleswitches then
3609 genprofilecode;
3610 exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
3611 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
3612 end;
3613 end { endif stackframe <> 0 }
3614 else
3615 begin
3616 if cs_profile in aktmoduleswitches then
3617 genprofilecode;
3618 exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
3619 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
3620 end;
3621 end;
3623 if (po_interrupt in aktprocsym^.definition^.procoptions) then
3624 generate_interrupt_stackframe_entry;
3626 { initialize return value }
3627 if (procinfo^.returntype.def<>pdef(voiddef)) and
3628 (procinfo^.returntype.def^.needs_inittable) and
3629 ((procinfo^.returntype.def^.deftype<>objectdef) or
3630 not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
3631 begin
3632 procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
3633 reset_reference(r);
3634 r.offset:=procinfo^.return_offset;
3635 r.base:=procinfo^.framepointer;
3636 initialize(procinfo^.returntype.def,r,ret_in_param(procinfo^.returntype.def));
3637 end;
3639 { initialisize local data like ansistrings }
3640 case aktprocsym^.definition^.proctypeoption of
3641 potype_unitinit:
3642 begin
3643 { using current_module^.globalsymtable is hopefully }
3644 { more robust than symtablestack and symtablestack^.next }
3645 psymtable(current_module^.globalsymtable)^.foreach({$ifndef TP}@{$endif}initialize_data);
3646 psymtable(current_module^.localsymtable)^.foreach({$ifndef TP}@{$endif}initialize_data);
3647 end;
3648 { units have seperate code for initilization and finalization }
3649 potype_unitfinalize: ;
3650 else
3651 aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}initialize_data);
3652 end;
3654 { generate copies of call by value parameters }
3655 if not(po_assembler in aktprocsym^.definition^.procoptions) and
3656 not (pocall_cdecl in aktprocsym^.definition^.proccalloptions) then
3657 aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}copyvalueparas);
3659 { add a reference to all call by value/const parameters }
3660 aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}incr_data);
3662 { initialisizes temp. ansi/wide string data }
3663 inittempansistrings;
3665 { do we need an exception frame because of ansi/widestrings ? }
3666 if not inlined and
3667 ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
3668 { but it's useless in init/final code of units }
3669 not(aktprocsym^.definition^.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
3670 begin
3671 usedinproc:=usedinproc or ($80 shr byte(R_EAX));
3673 { Type of stack-frame must be pushed}
3674 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
3675 emitcall('FPC_PUSHEXCEPTADDR');
3676 exprasmlist^.concat(new(paicpu,
3677 op_reg(A_PUSH,S_L,R_EAX)));
3678 emitcall('FPC_SETJMP');
3679 exprasmlist^.concat(new(paicpu,
3680 op_reg(A_PUSH,S_L,R_EAX)));
3681 exprasmlist^.concat(new(paicpu,
3682 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
3683 emitjmp(C_NE,aktexitlabel);
3684 { probably we've to reload self here }
3685 maybe_loadesi;
3686 end;
3688 if not inlined then
3689 begin
3690 if (cs_profile in aktmoduleswitches) or
3691 (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
3692 (assigned(procinfo^._class) and (procinfo^._class^.owner^.symtabletype=globalsymtable)) then
3693 make_global:=true;
3695 hs:=proc_names.get;
3697 {$ifdef GDB}
3698 if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
3699 stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
3700 {$EndIf GDB}
3702 while hs<>'' do
3703 begin
3704 if make_global then
3705 exprasmlist^.insert(new(pai_symbol,initname_global(hs,0)))
3706 else
3707 exprasmlist^.insert(new(pai_symbol,initname(hs,0)));
3709 {$ifdef GDB}
3710 if (cs_debuginfo in aktmoduleswitches) and
3711 target_os.use_function_relative_addresses then
3712 exprasmlist^.insert(new(pai_stab_function_name,init(strpnew(hs))));
3713 {$endif GDB}
3715 hs:=proc_names.get;
3716 end;
3718 if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
3719 aktprocsym^.is_global := True;
3721 {$ifdef GDB}
3722 if (cs_debuginfo in aktmoduleswitches) then
3723 begin
3724 if target_os.use_function_relative_addresses then
3725 exprasmlist^.insert(stab_function_name);
3726 exprasmlist^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
3727 aktprocsym^.isstabwritten:=true;
3728 end;
3729 {$endif GDB}
3731 { Align, gprof uses 16 byte granularity }
3732 if (cs_profile in aktmoduleswitches) then
3733 exprasmlist^.insert(new(pai_align,init_op(16,$90)))
3734 else
3735 if not(cs_littlesize in aktglobalswitches) then
3736 exprasmlist^.insert(new(pai_align,init(16)));
3737 end;
3738 exprasmlist:=oldexprasmlist;
3739 end;
3742 procedure handle_return_value(inlined : boolean;var uses_eax,uses_edx : boolean);
3744 hr : preference;
3745 op : Tasmop;
3746 s : Topsize;
3747 begin
3748 uses_eax:=false;
3749 uses_edx:=false;
3750 if procinfo^.returntype.def<>pdef(voiddef) then
3751 begin
3752 {if ((procinfo^.flags and pi_operator)<>0) and
3753 assigned(opsym) then
3754 procinfo^.funcret_is_valid:=
3755 procinfo^.funcret_is_valid or (opsym^.refs>0);}
3756 if (procinfo^.funcret_state<>vs_assigned) and not inlined { and
3757 ((procinfo^.flags and pi_uses_asm)=0)} then
3758 CGMessage(sym_w_function_result_not_set);
3759 hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
3760 if (procinfo^.returntype.def^.deftype in [orddef,enumdef]) then
3761 begin
3762 uses_eax:=true;
3763 case procinfo^.returntype.def^.size of
3765 begin
3766 emit_ref_reg(A_MOV,S_L,hr,R_EAX);
3767 hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
3768 emit_ref_reg(A_MOV,S_L,hr,R_EDX);
3769 uses_edx:=true;
3770 end;
3773 emit_ref_reg(A_MOV,S_L,hr,R_EAX);
3776 emit_ref_reg(A_MOV,S_W,hr,R_AX);
3779 emit_ref_reg(A_MOV,S_B,hr,R_AL);
3780 end;
3782 else
3783 if ret_in_acc(procinfo^.returntype.def) then
3784 begin
3785 uses_eax:=true;
3786 emit_ref_reg(A_MOV,S_L,hr,R_EAX);
3788 else
3789 if (procinfo^.returntype.def^.deftype=floatdef) then
3790 begin
3791 floatloadops(pfloatdef(procinfo^.returntype.def)^.typ,op,s);
3792 exprasmlist^.concat(new(paicpu,op_ref(op,s,hr)))
3794 else
3795 dispose(hr);
3797 end;
3800 procedure genexitcode(alist : paasmoutput;parasize:longint;nostackframe,inlined:boolean);
3803 {$ifdef GDB}
3804 mangled_length : longint;
3805 p : pchar;
3806 st : string[2];
3807 {$endif GDB}
3808 nofinal,okexitlabel,noreraiselabel,nodestroycall : pasmlabel;
3809 hr : treference;
3810 uses_eax,uses_edx,uses_esi : boolean;
3811 oldexprasmlist : paasmoutput;
3812 ai : paicpu;
3813 pd : pprocdef;
3815 begin
3816 oldexprasmlist:=exprasmlist;
3817 exprasmlist:=alist;
3819 if aktexitlabel^.is_used then
3820 exprasmlist^.insert(new(pai_label,init(aktexitlabel)));
3822 { call the destructor help procedure }
3823 if (aktprocsym^.definition^.proctypeoption=potype_destructor) and
3824 assigned(procinfo^._class) then
3825 begin
3826 if procinfo^._class^.is_class then
3827 begin
3828 emitinsertcall('FPC_DISPOSE_CLASS');
3830 else
3831 begin
3832 emitinsertcall('FPC_HELP_DESTRUCTOR');
3833 {$ifndef noAllocEdi}
3834 getexplicitregister32(R_EDI);
3835 {$endif noAllocEdi}
3836 exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
3837 { must the object be finalized ? }
3838 if procinfo^._class^.needs_inittable then
3839 begin
3840 getlabel(nofinal);
3841 exprasmlist^.insert(new(pai_label,init(nofinal)));
3842 emitinsertcall('FPC_FINALIZE');
3843 {$ifndef noAllocEdi}
3844 ungetregister32(R_EDI);
3845 {$endif noAllocEdi}
3846 exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
3847 exprasmlist^.insert(new(paicpu,op_sym(A_PUSH,S_L,procinfo^._class^.get_inittable_label)));
3848 ai:=new(paicpu,op_sym(A_Jcc,S_NO,nofinal));
3849 ai^.SetCondition(C_Z);
3850 exprasmlist^.insert(ai);
3851 reset_reference(hr);
3852 hr.base:=R_EBP;
3853 hr.offset:=8;
3854 exprasmlist^.insert(new(paicpu,op_const_ref(A_CMP,S_L,0,newreference(hr))));
3855 end;
3856 end;
3857 end;
3859 { finalize temporary data }
3860 finalizetempansistrings;
3862 { finalize local data like ansistrings}
3863 case aktprocsym^.definition^.proctypeoption of
3864 potype_unitfinalize:
3865 begin
3866 { using current_module^.globalsymtable is hopefully }
3867 { more robust than symtablestack and symtablestack^.next }
3868 psymtable(current_module^.globalsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
3869 psymtable(current_module^.localsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
3870 end;
3871 { units have seperate code for initialization and finalization }
3872 potype_unitinit: ;
3873 else
3874 aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}finalize_data);
3875 end;
3877 { finalize paras data }
3878 if assigned(aktprocsym^.definition^.parast) then
3879 aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}finalize_data);
3881 { do we need to handle exceptions because of ansi/widestrings ? }
3882 if not inlined and
3883 ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
3884 { but it's useless in init/final code of units }
3885 not(aktprocsym^.definition^.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
3886 begin
3887 { the exception helper routines modify all registers }
3888 aktprocsym^.definition^.usedregisters:=$ff;
3890 getlabel(noreraiselabel);
3891 emitcall('FPC_POPADDRSTACK');
3892 exprasmlist^.concat(new(paicpu,
3893 op_reg(A_POP,S_L,R_EAX)));
3894 exprasmlist^.concat(new(paicpu,
3895 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
3896 emitjmp(C_E,noreraiselabel);
3897 if (aktprocsym^.definition^.proctypeoption=potype_constructor) then
3898 begin
3899 if assigned(procinfo^._class) then
3900 begin
3901 pd:=procinfo^._class^.searchdestructor;
3902 if assigned(pd) then
3903 begin
3904 getlabel(nodestroycall);
3905 emit_const_ref(A_CMP,S_L,0,new_reference(procinfo^.framepointer,
3906 procinfo^.selfpointer_offset));
3907 emitjmp(C_E,nodestroycall);
3908 if procinfo^._class^.is_class then
3909 begin
3910 emit_const(A_PUSH,S_L,1);
3911 emit_reg(A_PUSH,S_L,R_ESI);
3913 else
3914 begin
3915 emit_reg(A_PUSH,S_L,R_ESI);
3916 emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class^.vmt_mangledname));
3917 end;
3918 if (po_virtualmethod in pd^.procoptions) then
3919 begin
3920 emit_ref_reg(A_MOV,S_L,new_reference(R_ESI,0),R_EDI);
3921 emit_ref(A_CALL,S_NO,new_reference(R_EDI,procinfo^._class^.vmtmethodoffset(pd^.extnumber)));
3923 else
3924 emitcall(pd^.mangledname);
3925 { not necessary because the result is never assigned in the
3926 case of an exception (FK)
3927 emit_const_reg(A_MOV,S_L,0,R_ESI);
3928 emit_const_ref(A_MOV,S_L,0,new_reference(procinfo^.framepointer,8));
3930 emitlab(nodestroycall);
3931 end;
3934 else
3935 { must be the return value finalized before reraising the exception? }
3936 if (procinfo^.returntype.def<>pdef(voiddef)) and
3937 (procinfo^.returntype.def^.needs_inittable) and
3938 ((procinfo^.returntype.def^.deftype<>objectdef) or
3939 not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
3940 begin
3941 reset_reference(hr);
3942 hr.offset:=procinfo^.return_offset;
3943 hr.base:=procinfo^.framepointer;
3944 finalize(procinfo^.returntype.def,hr,ret_in_param(procinfo^.returntype.def));
3945 end;
3947 emitcall('FPC_RERAISE');
3948 emitlab(noreraiselabel);
3949 end;
3951 { call __EXIT for main program }
3952 if (not DLLsource) and (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
3953 begin
3954 emitcall('FPC_DO_EXIT');
3955 end;
3957 { handle return value }
3958 uses_eax:=false;
3959 uses_edx:=false;
3960 uses_esi:=false;
3961 if not(po_assembler in aktprocsym^.definition^.procoptions) then
3962 if (aktprocsym^.definition^.proctypeoption<>potype_constructor) then
3963 handle_return_value(inlined,uses_eax,uses_edx)
3964 else
3965 begin
3966 { successful constructor deletes the zero flag }
3967 { and returns self in eax }
3968 { eax must be set to zero if the allocation failed !!! }
3969 getlabel(okexitlabel);
3970 emitjmp(C_NONE,okexitlabel);
3971 emitlab(faillabel);
3972 if procinfo^._class^.is_class then
3973 begin
3974 emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
3975 emitcall('FPC_HELP_FAIL_CLASS');
3977 else
3978 begin
3979 emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
3980 {$ifndef noAllocEdi}
3981 getexplicitregister32(R_EDI);
3982 {$endif noAllocEdi}
3983 emit_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI);
3984 emitcall('FPC_HELP_FAIL');
3985 {$ifndef noAllocEdi}
3986 ungetregister32(R_EDI);
3987 {$endif noAllocEdi}
3988 end;
3989 emitlab(okexitlabel);
3991 emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
3992 emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
3993 uses_eax:=true;
3994 uses_esi:=true;
3995 end;
3997 { stabs uses the label also ! }
3998 if aktexit2label^.is_used or
3999 ((cs_debuginfo in aktmoduleswitches) and not inlined) then
4000 emitlab(aktexit2label);
4001 { gives problems for long mangled names }
4002 {list^.concat(new(pai_symbol,init(aktprocsym^.definition^.mangledname+'_end')));}
4004 { should we restore edi ? }
4005 { for all i386 gcc implementations }
4006 if (po_savestdregs in aktprocsym^.definition^.procoptions) then
4007 begin
4008 if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
4009 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
4010 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
4011 exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
4012 { here we could reset R_EBX
4013 but that is risky because it only works
4014 if genexitcode is called after genentrycode
4015 so lets skip this for the moment PM
4016 aktprocsym^.definition^.usedregisters:=
4017 aktprocsym^.definition^.usedregisters or not ($80 shr byte(R_EBX));
4019 end;
4021 { for the save all registers we can simply use a pusha,popa which
4022 push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
4023 if (po_saveregisters in aktprocsym^.definition^.procoptions) then
4024 begin
4025 if uses_esi then
4026 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,4))));
4027 if uses_edx then
4028 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,20))));
4029 if uses_eax then
4030 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,28))));
4031 exprasmlist^.concat(new(paicpu,op_none(A_POPA,S_L)))
4032 end;
4033 if not(nostackframe) then
4034 begin
4035 if not inlined then
4036 exprasmlist^.concat(new(paicpu,op_none(A_LEAVE,S_NO)));
4038 else
4039 begin
4040 if (gettempsize<>0) and not inlined then
4041 exprasmlist^.insert(new(paicpu,
4042 op_const_reg(A_ADD,S_L,gettempsize,R_ESP)));
4043 end;
4045 { parameters are limited to 65535 bytes because }
4046 { ret allows only imm16 }
4047 if (parasize>65535) and not(pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
4048 CGMessage(cg_e_parasize_too_big);
4050 { at last, the return is generated }
4052 if not inlined then
4053 if (po_interrupt in aktprocsym^.definition^.procoptions) then
4054 begin
4055 if uses_esi then
4056 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,16))));
4057 if uses_edx then
4058 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,12))));
4059 if uses_eax then
4060 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,0))));
4061 generate_interrupt_stackframe_exit;
4063 else
4064 begin
4065 {Routines with the poclearstack flag set use only a ret.}
4066 { also routines with parasize=0 }
4067 if (pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
4068 begin
4069 {$ifndef OLD_C_STACK}
4070 { complex return values are removed from stack in C code PM }
4071 if ret_in_param(aktprocsym^.definition^.rettype.def) then
4072 exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,4)))
4073 else
4074 {$endif not OLD_C_STACK}
4075 exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)));
4077 else if (parasize=0) then
4078 exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)))
4079 else
4080 exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,parasize)));
4081 end;
4083 if not inlined then
4084 exprasmlist^.concat(new(pai_symbol_end,initname(aktprocsym^.definition^.mangledname)));
4086 {$ifdef GDB}
4087 if (cs_debuginfo in aktmoduleswitches) and not inlined then
4088 begin
4089 aktprocsym^.concatstabto(exprasmlist);
4090 if assigned(procinfo^._class) then
4091 if (not assigned(procinfo^.parent) or
4092 not assigned(procinfo^.parent^._class)) then
4093 begin
4094 if (po_classmethod in aktprocsym^.definition^.procoptions) or
4095 (po_staticmethod in aktprocsym^.definition^.procoptions) then
4096 begin
4097 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4098 '"pvmt:p'+pvmtdef^.numberstring+'",'+
4099 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.selfpointer_offset)))));
4101 else
4102 begin
4103 if not procinfo^._class^.is_class then
4104 st:='v'
4105 else
4106 st:='p';
4107 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4108 '"$t:'+st+procinfo^._class^.numberstring+'",'+
4109 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.selfpointer_offset)))));
4110 end;
4112 else
4113 begin
4114 if not procinfo^._class^.is_class then
4115 st:='*'
4116 else
4117 st:='';
4118 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4119 '"$t:r'+st+procinfo^._class^.numberstring+'",'+
4120 tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI])))));
4121 end;
4122 { define calling EBP as pseudo local var PM }
4123 { this enables test if the function is a local one !! }
4124 if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
4125 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4126 '"parent_ebp:'+voidpointerdef^.numberstring+'",'+
4127 tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset)))));
4129 if (pdef(aktprocsym^.definition^.rettype.def) <> pdef(voiddef)) then
4130 begin
4131 if ret_in_param(aktprocsym^.definition^.rettype.def) then
4132 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4133 '"'+aktprocsym^.name+':X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
4134 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
4135 else
4136 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4137 '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
4138 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
4139 if (m_result in aktmodeswitches) then
4140 if ret_in_param(aktprocsym^.definition^.rettype.def) then
4141 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4142 '"RESULT:X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
4143 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
4144 else
4145 exprasmlist^.concat(new(pai_stabs,init(strpnew(
4146 '"RESULT:X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
4147 tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
4148 end;
4149 mangled_length:=length(aktprocsym^.definition^.mangledname);
4150 getmem(p,2*mangled_length+50);
4151 strpcopy(p,'192,0,0,');
4152 strpcopy(strend(p),aktprocsym^.definition^.mangledname);
4153 if (target_os.use_function_relative_addresses) then
4154 begin
4155 strpcopy(strend(p),'-');
4156 strpcopy(strend(p),aktprocsym^.definition^.mangledname);
4157 end;
4158 exprasmlist^.concat(new(pai_stabn,init(strnew(p))));
4159 {list^.concat(new(pai_stabn,init(strpnew('192,0,0,'
4160 +aktprocsym^.definition^.mangledname))));
4161 p[0]:='2';p[1]:='2';p[2]:='4';
4162 strpcopy(strend(p),'_end');}
4163 strpcopy(p,'224,0,0,'+aktexit2label^.name);
4164 if (target_os.use_function_relative_addresses) then
4165 begin
4166 strpcopy(strend(p),'-');
4167 strpcopy(strend(p),aktprocsym^.definition^.mangledname);
4168 end;
4169 exprasmlist^.concatlist(withdebuglist);
4170 exprasmlist^.concat(new(pai_stabn,init(
4171 strnew(p))));
4172 { strpnew('224,0,0,'
4173 +aktprocsym^.definition^.mangledname+'_end'))));}
4174 freemem(p,2*mangled_length+50);
4175 end;
4176 {$endif GDB}
4177 exprasmlist:=oldexprasmlist;
4178 end;
4180 procedure genimplicitunitfinal(alist : paasmoutput);
4182 begin
4183 { using current_module^.globalsymtable is hopefully }
4184 { more robust than symtablestack and symtablestack^.next }
4185 psymtable(current_module^.globalsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
4186 psymtable(current_module^.localsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
4187 exprasmlist^.insert(new(pai_symbol,initname_global('FINALIZE$$'+current_module^.modulename^,0)));
4188 exprasmlist^.insert(new(pai_symbol,initname_global(target_os.cprefix+current_module^.modulename^+'_finalize',0)));
4189 {$ifdef GDB}
4190 if (cs_debuginfo in aktmoduleswitches) and
4191 target_os.use_function_relative_addresses then
4192 exprasmlist^.insert(new(pai_stab_function_name,init(strpnew('FINALIZE$$'+current_module^.modulename^))));
4193 {$endif GDB}
4194 exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)));
4195 alist^.concatlist(exprasmlist);
4196 end;
4198 procedure genimplicitunitinit(alist : paasmoutput);
4200 begin
4201 { using current_module^.globalsymtable is hopefully }
4202 { more robust than symtablestack and symtablestack^.next }
4203 psymtable(current_module^.globalsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
4204 psymtable(current_module^.localsymtable)^.foreach({$ifndef TP}@{$endif}finalize_data);
4205 exprasmlist^.insert(new(pai_symbol,initname_global('INIT$$'+current_module^.modulename^,0)));
4206 exprasmlist^.insert(new(pai_symbol,initname_global(target_os.cprefix+current_module^.modulename^+'_init',0)));
4207 {$ifdef GDB}
4208 if (cs_debuginfo in aktmoduleswitches) and
4209 target_os.use_function_relative_addresses then
4210 exprasmlist^.insert(new(pai_stab_function_name,init(strpnew('INIT$$'+current_module^.modulename^))));
4211 {$endif GDB}
4212 exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)));
4213 alist^.concatlist(exprasmlist);
4214 end;
4216 {$ifdef test_dest_loc}
4217 procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
4219 begin
4220 if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
4221 begin
4222 emit_reg_reg(A_MOV,s,reg,dest_loc.register);
4223 set_location(p^.location,dest_loc);
4224 in_dest_loc:=true;
4226 else
4227 if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
4228 begin
4229 exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference))));
4230 set_location(p^.location,dest_loc);
4231 in_dest_loc:=true;
4233 else
4234 internalerror(20080);
4235 end;
4237 {$endif test_dest_loc}
4239 end.
4241 $Log$
4242 Revision 1.1 2002/02/19 08:21:56 sasu
4243 Initial revision
4245 Revision 1.1.2.19 2000/12/08 17:03:20 jonas
4246 + added full range checking for 64bit types
4247 * fixed web bug 1144
4249 Revision 1.1.2.18 2000/12/07 17:17:25 jonas
4250 * fixed bug where the original resulttype wasn't restored correctly
4251 after doing a 64bit rangecheck
4253 Revision 1.1.2.17 2000/12/06 16:46:30 jonas
4254 * backported range checking fixes from 1.1 (added range checking for
4255 conversion between cardinal and longint and for conversion from
4256 64bit to 32bit types)
4258 Revision 1.1.2.16 2000/11/20 16:21:53 pierre
4259 * class class method parameter is not a oclass but a vmt pointer
4261 Revision 1.1.2.15 2000/11/17 23:17:07 pierre
4262 * fix static object method and class class method
4264 Revision 1.1.2.14 2000/10/24 22:22:22 peter
4265 * emitcall -> emitinsertcall for profiling
4267 Revision 1.1.2.13 2000/10/23 20:07:02 pierre
4268 * fix web bug 1153
4270 Revision 1.1.2.12 2000/10/14 00:40:45 pierre
4271 * fixes for class debugging
4273 Revision 1.1.2.11 2000/10/13 20:12:21 florian
4274 * fixed my previous commit
4276 Revision 1.1.2.10 2000/10/13 19:50:42 florian
4277 * the warning about the unimplemented int64 range check is now displayed only once
4279 Revision 1.1.2.9 2000/10/10 14:52:38 jonas
4280 * added missing regallocs for edi in emit_mov_ref_reg64
4282 Revision 1.1.2.8 2000/09/13 13:57:40 marco
4283 * FreeBSD compiler support
4285 Revision 1.1.2.7 2000/08/24 19:05:29 peter
4286 * don't initialize if localvarsym is set because that varsym will
4287 already be initialized
4288 * first initialize local data before copy of value para's
4290 Revision 1.1.2.6 2000/08/19 20:06:15 peter
4291 * check size after checking openarray in push_value_para
4293 Revision 1.1.2.5 2000/08/10 18:44:43 peter
4294 * fixed for constants in emit_push_mem_size for go32v2
4296 Revision 1.1.2.4 2000/08/07 11:22:11 jonas
4297 + emit_push_mem_size() which pushes a value in memory of a certain size
4298 * pushsetelement() and pushvaluepara() use this new procedure, because
4299 otherwise they could sometimes try to push data past the end of the
4300 heap, causing a crash
4302 Revision 1.1.2.3 2000/08/02 08:01:08 jonas
4303 * fixed web bug1087
4304 * allocate R_ECX explicitely if it's used
4306 Revision 1.1.2.2 2000/08/02 07:54:49 jonas
4307 *** empty log message ***
4309 Revision 1.1.2.1 2000/07/27 09:21:33 jonas
4310 * moved locflags2reg() procedure from cg386add to cgai386
4311 + added locjump2reg() procedure to cgai386
4312 * fixed internalerror(2002) when the result of a case expression has
4313 LOC_JUMP
4315 Revision 1.1 2000/07/13 06:29:47 michael
4316 + Initial import
4318 Revision 1.109 2000/06/27 12:17:29 jonas
4319 * fix for web bug 1011: no exception stack stuff is generated for
4320 inlined procedures, the entry/exitcode of the parent will do that
4322 Revision 1.108 2000/06/10 17:31:42 jonas
4323 * loadord2reg doesn't generate any "movl %reg1,%reg1" anymore
4325 Revision 1.107 2000/06/05 20:39:05 pierre
4326 * fix for inline bug
4328 Revision 1.106 2000/05/26 20:16:00 jonas
4329 * fixed wrong register deallocations in several ansistring related
4330 procedures. The IDE's now function fine when compiled with -OG3p3r
4332 Revision 1.105 2000/05/23 14:20:49 pierre
4333 * Use stacksize param instead of gettempsize
4335 Revision 1.104 2000/05/18 17:05:15 peter
4336 * fixed size of const parameters in asm readers
4338 Revision 1.103 2000/05/17 11:06:11 pierre
4339 add a comment about ENTER and linux
4341 Revision 1.102 2000/05/14 18:49:04 florian
4342 + Int64/QWord stuff for array of const added
4344 Revision 1.101 2000/05/09 14:17:33 pierre
4345 * handle interrupt function correctly
4347 Revision 1.100 2000/05/04 09:29:31 pierre
4348 * saveregisters now does not overwrite registers used as return value for functions
4350 Revision 1.99 2000/04/28 08:53:47 pierre
4351 * fix my last fix for other targets then win32
4353 Revision 1.98 2000/04/26 10:03:45 pierre
4354 * correct bugs for ts010026 and ts010029 in win32 mode
4355 in copyvaluparas
4356 + use SHL instead of IMUL if constant is a power of 2 in copyvalueparas
4358 Revision 1.97 2000/04/24 12:48:37 peter
4359 * removed unused vars
4361 Revision 1.96 2000/04/10 12:23:18 jonas
4362 * modified copyshortstring so it takes an extra paramter which allows it
4363 to delete the sref itself (so the reg deallocations are put in the
4364 right place for the optimizer)
4366 Revision 1.95 2000/04/10 09:01:15 pierre
4367 * fix for bug 922 in copyvalueparas
4369 Revision 1.94 2000/04/03 20:51:22 florian
4370 * initialize/finalize_data checks if procinfo is assigned else
4371 crashes happend at end of compiling if there were ansistrings in the
4372 interface/implementation part of units: it was the result of the fix
4373 of 701 :(
4375 Revision 1.93 2000/04/02 10:18:18 florian
4376 * bug 701 fixed: ansistrings in interface and implementation part of the units
4377 are now finalized correctly even if there are no explicit initialization/
4378 finalization statements
4380 Revision 1.92 2000/04/01 14:18:45 peter
4381 * use arraydef.elesize instead of elementtype.def.size
4383 Revision 1.91 2000/03/31 22:56:46 pierre
4384 * fix the handling of value parameters in cdecl function
4386 Revision 1.90 2000/03/28 22:31:46 pierre
4387 * fix for problem in tbs0299 for 4 byte stack alignment
4389 Revision 1.89 2000/03/21 23:36:46 pierre
4390 fix for bug 312
4392 Revision 1.88 2000/03/19 11:55:08 peter
4393 * fixed temp ansi handling within array constructor
4395 Revision 1.87 2000/03/19 08:17:36 peter
4396 * tp7 fix
4398 Revision 1.86 2000/03/01 15:36:11 florian
4399 * some new stuff for the new cg
4401 Revision 1.85 2000/03/01 12:35:44 pierre
4402 * fix for bug 855
4404 Revision 1.84 2000/03/01 00:03:12 pierre
4405 * fixes for locals in inlined procedures
4406 fix for bug797
4407 + stabs generation for inlined paras and locals
4409 Revision 1.83 2000/02/18 21:25:48 florian
4410 * fixed a bug in int64/qword handling was a quite ugly one
4412 Revision 1.82 2000/02/18 20:53:14 pierre
4413 * fixes a stabs problem for functions
4414 + includes a stabs local var for with statements
4415 the name is with in lowercase followed by an index
4416 for nested with.
4417 + Withdebuglist added because the stabs declarations of local
4418 var are postponed to end of function.
4420 Revision 1.81 2000/02/10 23:44:43 florian
4421 * big update for exception handling code generation: possible mem holes
4422 fixed, break/continue/exit should work always now as expected
4424 Revision 1.80 2000/02/09 17:36:10 jonas
4425 * added missing regalloc for ecx in range check code
4427 Revision 1.79 2000/02/09 13:22:50 peter
4428 * log truncated
4430 Revision 1.78 2000/02/04 21:00:31 florian
4431 * some (small) problems with register saving fixed
4433 Revision 1.77 2000/02/04 20:00:21 florian
4434 * an exception in a construcor calls now the destructor (this applies only
4435 to classes)
4437 Revision 1.76 2000/02/04 14:29:57 pierre
4438 + add pseudo local var parent_ebp for local procs
4440 Revision 1.75 2000/01/25 08:46:03 pierre
4441 * Range check for int64 produces a warning only
4443 Revision 1.74 2000/01/24 12:17:22 florian
4444 * some improvemenst to cmov support
4445 * disabled excpetion frame generation in cosntructors temporarily
4447 Revision 1.73 2000/01/23 21:29:14 florian
4448 * CMOV support in optimizer (in define USECMOV)
4449 + start of support of exceptions in constructors
4451 Revision 1.72 2000/01/23 11:11:36 michael
4452 + Fixes from Jonas.
4454 Revision 1.71 2000/01/22 16:02:37 jonas
4455 * fixed more regalloc bugs (for set adding and unsigned
4456 multiplication)
4458 Revision 1.70 2000/01/16 22:17:11 peter
4459 * renamed call_offset to para_offset
4461 Revision 1.69 2000/01/12 10:38:17 peter
4462 * smartlinking fixes for binary writer
4463 * release alignreg code and moved instruction writing align to cpuasm,
4464 but it doesn't use the specified register yet
4466 Revision 1.68 2000/01/09 12:35:02 jonas
4467 * changed edi allocation to use getexplicitregister32/ungetregister
4468 (adapted tgeni386 a bit for this) and enabled it by default
4469 * fixed very big and stupid bug of mine in cg386mat that broke the
4470 include() code (and make cycle :( ) if you compiled without
4471 -dnewoptimizations
4473 Revision 1.67 2000/01/09 01:44:21 jonas
4474 + (de)allocation info for EDI to fix reported bug on mailinglist.
4475 Also some (de)allocation info for ESI added. Between -dallocEDI
4476 because at this time of the night bugs could easily slip in ;)
4478 Revision 1.66 2000/01/07 01:14:22 peter
4479 * updated copyright to 2000
4481 Revision 1.65 1999/12/22 01:01:47 peter
4482 - removed freelabel()
4483 * added undefined label detection in internal assembler, this prevents
4484 a lot of ld crashes and wrong .o files
4485 * .o files aren't written anymore if errors have occured
4486 * inlining of assembler labels is now correct
4488 Revision 1.64 1999/12/20 21:42:35 pierre
4489 + dllversion global variable
4490 * FPC_USE_CPREFIX code removed, not necessary anymore
4491 as we use .edata direct writing by default now.
4493 Revision 1.63 1999/12/01 22:45:54 peter
4494 * fixed wrong assembler with in-node
4496 Revision 1.62 1999/11/30 10:40:43 peter
4497 + ttype, tsymlist
4499 Revision 1.61 1999/11/20 01:22:18 pierre
4500 + cond FPC_USE_CPREFIX (needs also some RTL changes)
4501 this allows to use unit global vars as DLL exports
4502 (the underline prefix seems needed by dlltool)
4504 Revision 1.60 1999/11/17 17:04:58 pierre
4505 * Notes/hints changes
4507 Revision 1.59 1999/11/15 14:04:00 pierre
4508 * self pointer stabs for local function was wrong