Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / cg386flw.pas
blob14650277fbf5e13424725f13550042f5c053f982
2 $Id$
3 Copyright (c) 1998-2000 by Florian Klaempfl
5 Generate i386 assembler for nodes that influence the flow
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 {$ifdef FPC}
24 {$goto on}
25 {$endif FPC}
26 unit cg386flw;
27 interface
29 uses
30 tree;
32 procedure second_while_repeatn(var p : ptree);
33 procedure secondifn(var p : ptree);
34 procedure secondfor(var p : ptree);
35 procedure secondexitn(var p : ptree);
36 procedure secondbreakn(var p : ptree);
37 procedure secondcontinuen(var p : ptree);
38 procedure secondgoto(var p : ptree);
39 procedure secondlabel(var p : ptree);
40 procedure secondraise(var p : ptree);
41 procedure secondtryexcept(var p : ptree);
42 procedure secondtryfinally(var p : ptree);
43 procedure secondon(var p : ptree);
44 procedure secondfail(var p : ptree);
46 type
47 tenumflowcontrol = (fc_exit,fc_break,fc_continue);
48 tflowcontrol = set of tenumflowcontrol;
50 var
51 flowcontrol : tflowcontrol;
53 implementation
55 uses
56 cobjects,verbose,globtype,globals,systems,
57 symconst,symtable,aasm,types,
58 hcodegen,temp_gen,pass_2,
59 cpubase,cpuasm,
60 cgai386,tgeni386,tcflw;
62 {*****************************************************************************
63 Second_While_RepeatN
64 *****************************************************************************}
66 procedure second_while_repeatn(var p : ptree);
67 var
68 lcont,lbreak,lloop,
69 oldclabel,oldblabel : pasmlabel;
70 otlabel,oflabel : pasmlabel;
72 begin
73 getlabel(lloop);
74 getlabel(lcont);
75 getlabel(lbreak);
76 { arrange continue and breaklabels: }
77 oldclabel:=aktcontinuelabel;
78 oldblabel:=aktbreaklabel;
80 { handling code at the end as it is much more efficient, and makes
81 while equal to repeat loop, only the end true/false is swapped (PFV) }
82 if p^.treetype=whilen then
83 emitjmp(C_None,lcont);
85 emitlab(lloop);
87 aktcontinuelabel:=lcont;
88 aktbreaklabel:=lbreak;
89 cleartempgen;
90 if assigned(p^.right) then
91 secondpass(p^.right);
92 emitlab(lcont);
93 otlabel:=truelabel;
94 oflabel:=falselabel;
95 if p^.treetype=whilen then
96 begin
97 truelabel:=lloop;
98 falselabel:=lbreak;
99 end
100 { repeatn }
101 else
102 begin
103 truelabel:=lbreak;
104 falselabel:=lloop;
105 end;
106 cleartempgen;
107 secondpass(p^.left);
108 maketojumpbool(p^.left);
109 emitlab(lbreak);
110 truelabel:=otlabel;
111 falselabel:=oflabel;
113 aktcontinuelabel:=oldclabel;
114 aktbreaklabel:=oldblabel;
115 { a break/continue in a while/repeat block can't be seen outside }
116 flowcontrol:=flowcontrol-[fc_break,fc_continue];
117 end;
120 {*****************************************************************************
121 SecondIfN
122 *****************************************************************************}
124 procedure secondifn(var p : ptree);
127 hl,otlabel,oflabel : pasmlabel;
129 begin
130 otlabel:=truelabel;
131 oflabel:=falselabel;
132 getlabel(truelabel);
133 getlabel(falselabel);
134 cleartempgen;
135 secondpass(p^.left);
136 maketojumpbool(p^.left);
137 if assigned(p^.right) then
138 begin
139 emitlab(truelabel);
140 cleartempgen;
141 secondpass(p^.right);
142 end;
143 if assigned(p^.t1) then
144 begin
145 if assigned(p^.right) then
146 begin
147 getlabel(hl);
148 { do go back to if line !! }
149 aktfilepos:=exprasmlist^.getlasttaifilepos^;
150 emitjmp(C_None,hl);
151 end;
152 emitlab(falselabel);
153 cleartempgen;
154 secondpass(p^.t1);
155 if assigned(p^.right) then
156 emitlab(hl);
158 else
159 begin
160 emitlab(falselabel);
161 end;
162 if not(assigned(p^.right)) then
163 begin
164 emitlab(truelabel);
165 end;
166 truelabel:=otlabel;
167 falselabel:=oflabel;
168 end;
171 {*****************************************************************************
172 SecondFor
173 *****************************************************************************}
175 procedure secondfor(var p : ptree);
177 l3,oldclabel,oldblabel : pasmlabel;
178 omitfirstcomp,temptovalue : boolean;
179 hs : byte;
180 temp1 : treference;
181 hop : tasmop;
182 hcond : tasmcond;
183 cmpreg,cmp32 : tregister;
184 opsize : topsize;
185 count_var_is_signed : boolean;
187 begin
188 oldclabel:=aktcontinuelabel;
189 oldblabel:=aktbreaklabel;
190 getlabel(aktcontinuelabel);
191 getlabel(aktbreaklabel);
192 getlabel(l3);
194 { could we spare the first comparison ? }
195 omitfirstcomp:=false;
196 if p^.right^.treetype=ordconstn then
197 if p^.left^.right^.treetype=ordconstn then
198 omitfirstcomp:=(p^.backward and (p^.left^.right^.value>=p^.right^.value))
199 or (not(p^.backward) and (p^.left^.right^.value<=p^.right^.value));
201 { only calculate reference }
202 cleartempgen;
203 secondpass(p^.t2);
204 hs:=p^.t2^.resulttype^.size;
205 if p^.t2^.location.loc <> LOC_CREGISTER then
206 cmp32:=getregister32;
207 case hs of
208 1 : begin
209 opsize:=S_B;
210 if p^.t2^.location.loc <> LOC_CREGISTER then
211 cmpreg:=reg32toreg8(cmp32);
212 end;
213 2 : begin
214 opsize:=S_W;
215 if p^.t2^.location.loc <> LOC_CREGISTER then
216 cmpreg:=reg32toreg16(cmp32);
217 end;
218 4 : begin
219 opsize:=S_L;
220 if p^.t2^.location.loc <> LOC_CREGISTER then
221 cmpreg:=cmp32;
222 end;
223 end;
225 { first set the to value
226 because the count var can be in the expression !! }
227 cleartempgen;
228 secondpass(p^.right);
229 { calculate pointer value and check if changeable and if so }
230 { load into temporary variable }
231 if p^.right^.treetype<>ordconstn then
232 begin
233 temp1.symbol:=nil;
234 gettempofsizereference(hs,temp1);
235 temptovalue:=true;
236 if (p^.right^.location.loc=LOC_REGISTER) or
237 (p^.right^.location.loc=LOC_CREGISTER) then
238 begin
239 emit_reg_ref(A_MOV,opsize,p^.right^.location.register,
240 newreference(temp1));
242 else
243 concatcopy(p^.right^.location.reference,temp1,hs,false,false);
245 else
246 temptovalue:=false;
248 { produce start assignment }
249 cleartempgen;
250 secondpass(p^.left);
251 count_var_is_signed:=is_signed(porddef(p^.t2^.resulttype));
252 if temptovalue then
253 begin
254 if p^.t2^.location.loc=LOC_CREGISTER then
255 begin
256 emit_ref_reg(A_CMP,opsize,newreference(temp1),
257 p^.t2^.location.register);
259 else
260 begin
261 emit_ref_reg(A_MOV,opsize,newreference(p^.t2^.location.reference),
262 cmpreg);
263 emit_ref_reg(A_CMP,opsize,newreference(temp1),
264 cmpreg);
265 { temp register not necessary anymore currently (JM) }
266 ungetregister32(cmp32);
267 end;
269 else
270 begin
271 if not(omitfirstcomp) then
272 begin
273 if p^.t2^.location.loc=LOC_CREGISTER then
274 emit_const_reg(A_CMP,opsize,p^.right^.value,
275 p^.t2^.location.register)
276 else
277 emit_const_ref(A_CMP,opsize,p^.right^.value,
278 newreference(p^.t2^.location.reference));
279 end;
280 end;
281 if p^.backward then
282 if count_var_is_signed then
283 hcond:=C_L
284 else
285 hcond:=C_B
286 else
287 if count_var_is_signed then
288 hcond:=C_G
289 else
290 hcond:=C_A;
292 if not(omitfirstcomp) or temptovalue then
293 emitjmp(hcond,aktbreaklabel);
295 { align loop target }
296 if not(cs_littlesize in aktglobalswitches) then
297 exprasmlist^.concat(new(pai_align,init_op(4,$90)));
299 emitlab(l3);
301 { help register must not be in instruction block }
302 cleartempgen;
303 if assigned(p^.t1) then
304 secondpass(p^.t1);
306 emitlab(aktcontinuelabel);
308 { makes no problems there }
309 cleartempgen;
311 if (p^.t2^.location.loc <> LOC_CREGISTER) then
312 begin
313 { demand help register again }
314 cmp32:=getregister32;
315 case hs of
316 1 : cmpreg:=reg32toreg8(cmp32);
317 2 : cmpreg:=reg32toreg16(cmp32);
318 4 : cmpreg:=cmp32;
319 end;
320 end;
322 { produce comparison and the corresponding }
323 { jump }
324 if temptovalue then
325 begin
326 if p^.t2^.location.loc=LOC_CREGISTER then
327 begin
328 emit_ref_reg(A_CMP,opsize,newreference(temp1),
329 p^.t2^.location.register);
331 else
332 begin
333 emit_ref_reg(A_MOV,opsize,newreference(p^.t2^.location.reference),
334 cmpreg);
335 emit_ref_reg(A_CMP,opsize,newreference(temp1),
336 cmpreg);
337 end;
339 else
340 begin
341 if p^.t2^.location.loc=LOC_CREGISTER then
342 emit_const_reg(A_CMP,opsize,p^.right^.value,
343 p^.t2^.location.register)
344 else
345 emit_const_ref(A_CMP,opsize,p^.right^.value,
346 newreference(p^.t2^.location.reference));
347 end;
348 if p^.backward then
349 if count_var_is_signed then
350 hcond:=C_LE
351 else
352 hcond:=C_BE
353 else
354 if count_var_is_signed then
355 hcond:=C_GE
356 else
357 hcond:=C_AE;
358 emitjmp(hcond,aktbreaklabel);
359 { according to count direction DEC or INC... }
360 { must be after the test because of 0to 255 for bytes !! }
361 if p^.backward then
362 hop:=A_DEC
363 else
364 hop:=A_INC;
366 if p^.t2^.location.loc=LOC_CREGISTER then
367 emit_reg(hop,opsize,p^.t2^.location.register)
368 else
369 emit_ref(hop,opsize,newreference(p^.t2^.location.reference));
370 emitjmp(C_None,l3);
372 if (p^.t2^.location.loc <> LOC_CREGISTER) then
373 ungetregister32(cmp32);
374 if temptovalue then
375 ungetiftemp(temp1);
377 { this is the break label: }
378 emitlab(aktbreaklabel);
380 aktcontinuelabel:=oldclabel;
381 aktbreaklabel:=oldblabel;
382 { a break/continue in a for block can't be seen outside }
383 flowcontrol:=flowcontrol-[fc_break,fc_continue];
384 end;
387 {*****************************************************************************
388 SecondExitN
389 *****************************************************************************}
391 procedure secondexitn(var p : ptree);
393 is_mem : boolean;
394 {op : tasmop;
395 s : topsize;}
396 otlabel,oflabel : pasmlabel;
397 r : preference;
399 label
400 do_jmp;
401 begin
402 include(flowcontrol,fc_exit);
403 if assigned(p^.left) then
404 if p^.left^.treetype=assignn then
405 begin
406 { just do a normal assignment followed by exit }
407 secondpass(p^.left);
408 emitjmp(C_None,aktexitlabel);
410 else
411 begin
412 otlabel:=truelabel;
413 oflabel:=falselabel;
414 getlabel(truelabel);
415 getlabel(falselabel);
416 secondpass(p^.left);
417 case p^.left^.location.loc of
418 LOC_FPU : goto do_jmp;
419 LOC_MEM,
420 LOC_REFERENCE : is_mem:=true;
421 LOC_CREGISTER,
422 LOC_REGISTER : is_mem:=false;
423 LOC_FLAGS : begin
424 emit_flag2reg(p^.left^.location.resflags,R_AL);
425 goto do_jmp;
426 end;
427 LOC_JUMP : begin
428 emitlab(truelabel);
429 emit_const_reg(A_MOV,S_B,1,R_AL);
430 emitjmp(C_None,aktexit2label);
431 emitlab(falselabel);
432 emit_reg_reg(A_XOR,S_B,R_AL,R_AL);
433 goto do_jmp;
434 end;
435 else
436 internalerror(2001);
437 end;
438 case procinfo^.returntype.def^.deftype of
439 pointerdef,
440 procvardef : begin
441 if is_mem then
442 emit_ref_reg(A_MOV,S_L,
443 newreference(p^.left^.location.reference),R_EAX)
444 else
445 emit_reg_reg(A_MOV,S_L,
446 p^.left^.location.register,R_EAX);
447 end;
448 floatdef : begin
449 if pfloatdef(procinfo^.returntype.def)^.typ=f32bit then
450 begin
451 if is_mem then
452 emit_ref_reg(A_MOV,S_L,
453 newreference(p^.left^.location.reference),R_EAX)
454 else
455 emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
457 else
458 if is_mem then
459 floatload(pfloatdef(procinfo^.returntype.def)^.typ,p^.left^.location.reference);
460 end;
461 { orddef,
462 enumdef : }
463 else
464 { it can be anything shorter than 4 bytes PM
465 this caused form bug 711 }
466 begin
467 case procinfo^.returntype.def^.size of
468 { it can be a qword/int64 too ... }
469 8 : if is_mem then
470 begin
471 emit_ref_reg(A_MOV,S_L,
472 newreference(p^.left^.location.reference),R_EAX);
473 r:=newreference(p^.left^.location.reference);
474 inc(r^.offset,4);
475 emit_ref_reg(A_MOV,S_L,r,R_EDX);
477 else
478 begin
479 emit_reg_reg(A_MOV,S_L,p^.left^.location.registerlow,R_EAX);
480 emit_reg_reg(A_MOV,S_L,p^.left^.location.registerhigh,R_EDX);
481 end;
482 { if its 3 bytes only we can still
483 copy one of garbage ! PM }
484 4,3 : if is_mem then
485 emit_ref_reg(A_MOV,S_L,
486 newreference(p^.left^.location.reference),R_EAX)
487 else
488 emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
489 2 : if is_mem then
490 emit_ref_reg(A_MOV,S_W,
491 newreference(p^.left^.location.reference),R_AX)
492 else
493 emit_reg_reg(A_MOV,S_W,makereg16(p^.left^.location.register),R_AX);
494 1 : if is_mem then
495 emit_ref_reg(A_MOV,S_B,
496 newreference(p^.left^.location.reference),R_AL)
497 else
498 emit_reg_reg(A_MOV,S_B,makereg8(p^.left^.location.register),R_AL);
499 else internalerror(605001);
500 end;
501 end;
502 end;
503 do_jmp:
504 truelabel:=otlabel;
505 falselabel:=oflabel;
506 emitjmp(C_None,aktexit2label);
508 else
509 begin
510 emitjmp(C_None,aktexitlabel);
511 end;
512 end;
515 {*****************************************************************************
516 SecondBreakN
517 *****************************************************************************}
519 procedure secondbreakn(var p : ptree);
520 begin
521 include(flowcontrol,fc_break);
522 if aktbreaklabel<>nil then
523 emitjmp(C_None,aktbreaklabel)
524 else
525 CGMessage(cg_e_break_not_allowed);
526 end;
529 {*****************************************************************************
530 SecondContinueN
531 *****************************************************************************}
533 procedure secondcontinuen(var p : ptree);
534 begin
535 include(flowcontrol,fc_continue);
536 if aktcontinuelabel<>nil then
537 emitjmp(C_None,aktcontinuelabel)
538 else
539 CGMessage(cg_e_continue_not_allowed);
540 end;
543 {*****************************************************************************
544 SecondGoto
545 *****************************************************************************}
547 procedure secondgoto(var p : ptree);
549 begin
550 emitjmp(C_None,p^.labelnr);
551 { the assigned avoids only crashes if the label isn't defined }
552 if assigned(p^.labsym) and
553 assigned(p^.labsym^.code) and
554 (aktexceptblock<>ptree(p^.labsym^.code)^.exceptionblock) then
555 CGMessage(cg_e_goto_inout_of_exception_block);
556 end;
559 {*****************************************************************************
560 SecondLabel
561 *****************************************************************************}
563 procedure secondlabel(var p : ptree);
564 begin
565 emitlab(p^.labelnr);
566 cleartempgen;
567 secondpass(p^.left);
568 end;
571 {*****************************************************************************
572 SecondRaise
573 *****************************************************************************}
575 procedure secondraise(var p : ptree);
578 a : pasmlabel;
579 begin
580 if assigned(p^.left) then
581 begin
582 { multiple parameters? }
583 if assigned(p^.right) then
584 begin
585 { push frame }
586 if assigned(p^.frametree) then
587 begin
588 secondpass(p^.frametree);
589 if codegenerror then
590 exit;
591 emit_push_loc(p^.frametree^.location);
593 else
594 emit_const(A_PUSH,S_L,0);
595 { push address }
596 secondpass(p^.right);
597 if codegenerror then
598 exit;
599 emit_push_loc(p^.right^.location);
601 else
602 begin
603 getlabel(a);
604 emitlab(a);
605 emit_const(A_PUSH,S_L,0);
606 emit_sym(A_PUSH,S_L,a);
607 end;
608 { push object }
609 secondpass(p^.left);
610 if codegenerror then
611 exit;
612 emit_push_loc(p^.left^.location);
613 emitcall('FPC_RAISEEXCEPTION');
615 else
616 begin
617 emitcall('FPC_POPADDRSTACK');
618 emitcall('FPC_RERAISE');
619 end;
620 end;
623 {*****************************************************************************
624 SecondTryExcept
625 *****************************************************************************}
628 endexceptlabel : pasmlabel;
630 { does the necessary things to clean up the object stack }
631 { in the except block }
632 procedure cleanupobjectstack;
634 begin
635 emitcall('FPC_POPOBJECTSTACK');
636 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
637 emit_reg(A_PUSH,S_L,R_EAX);
638 emitcall('FPC_DESTROYEXCEPTION');
639 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
640 maybe_loadesi;
641 end;
643 { pops one element from the exception address stack }
644 { and removes the flag }
645 procedure cleanupaddrstack;
647 begin
648 emitcall('FPC_POPADDRSTACK');
649 { allocate eax }
650 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
651 emit_reg(A_POP,S_L,R_EAX);
652 { deallocate eax }
653 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
654 end;
656 procedure secondtryexcept(var p : ptree);
659 exceptlabel,doexceptlabel,oldendexceptlabel,
660 lastonlabel,
661 exitexceptlabel,
662 continueexceptlabel,
663 breakexceptlabel,
664 exittrylabel,
665 continuetrylabel,
666 breaktrylabel,
667 doobjectdestroy,
668 doobjectdestroyandreraise,
669 oldaktexitlabel,
670 oldaktexit2label,
671 oldaktcontinuelabel,
672 oldaktbreaklabel : pasmlabel;
673 oldexceptblock : ptree;
676 oldflowcontrol,tryflowcontrol,
677 exceptflowcontrol : tflowcontrol;
678 label
679 errorexit;
680 begin
681 oldflowcontrol:=flowcontrol;
682 flowcontrol:=[];
683 { this can be called recursivly }
684 oldendexceptlabel:=endexceptlabel;
686 { we modify EAX }
687 usedinproc:=usedinproc or ($80 shr byte(R_EAX));
689 { save the old labels for control flow statements }
690 oldaktexitlabel:=aktexitlabel;
691 oldaktexit2label:=aktexit2label;
692 if assigned(aktbreaklabel) then
693 begin
694 oldaktcontinuelabel:=aktcontinuelabel;
695 oldaktbreaklabel:=aktbreaklabel;
696 end;
698 { get new labels for the control flow statements }
699 getlabel(exittrylabel);
700 getlabel(exitexceptlabel);
701 if assigned(aktbreaklabel) then
702 begin
703 getlabel(breaktrylabel);
704 getlabel(continuetrylabel);
705 getlabel(breakexceptlabel);
706 getlabel(continueexceptlabel);
707 end;
709 getlabel(exceptlabel);
710 getlabel(doexceptlabel);
711 getlabel(endexceptlabel);
712 getlabel(lastonlabel);
713 push_int (1); { push type of exceptionframe }
714 emitcall('FPC_PUSHEXCEPTADDR');
715 { allocate eax }
716 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
717 emit_reg(A_PUSH,S_L,R_EAX);
718 emitcall('FPC_SETJMP');
719 emit_reg(A_PUSH,S_L,R_EAX);
720 emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
721 { deallocate eax }
722 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
723 emitjmp(C_NE,exceptlabel);
725 { try block }
726 { set control flow labels for the try block }
727 aktexitlabel:=exittrylabel;
728 aktexit2label:=exittrylabel;
729 if assigned(oldaktbreaklabel) then
730 begin
731 aktcontinuelabel:=continuetrylabel;
732 aktbreaklabel:=breaktrylabel;
733 end;
735 oldexceptblock:=aktexceptblock;
736 aktexceptblock:=p^.left;
737 flowcontrol:=[];
738 secondpass(p^.left);
739 tryflowcontrol:=flowcontrol;
740 aktexceptblock:=oldexceptblock;
741 if codegenerror then
742 goto errorexit;
744 emitlab(exceptlabel);
745 emitcall('FPC_POPADDRSTACK');
747 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
748 emit_reg(A_POP,S_L,R_EAX);
749 emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
750 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
752 emitjmp(C_E,endexceptlabel);
753 emitlab(doexceptlabel);
755 { set control flow labels for the except block }
756 { and the on statements }
757 aktexitlabel:=exitexceptlabel;
758 aktexit2label:=exitexceptlabel;
759 if assigned(oldaktbreaklabel) then
760 begin
761 aktcontinuelabel:=continueexceptlabel;
762 aktbreaklabel:=breakexceptlabel;
763 end;
765 flowcontrol:=[];
766 { on statements }
767 if assigned(p^.right) then
768 begin
769 oldexceptblock:=aktexceptblock;
770 aktexceptblock:=p^.right;
771 secondpass(p^.right);
772 aktexceptblock:=oldexceptblock;
773 end;
775 emitlab(lastonlabel);
776 { default handling except handling }
777 if assigned(p^.t1) then
778 begin
779 { FPC_CATCHES must be called with
780 'default handler' flag (=-1)
782 push_int (-1);
783 emitcall('FPC_CATCHES');
784 maybe_loadesi;
786 { the destruction of the exception object must be also }
787 { guarded by an exception frame }
788 getlabel(doobjectdestroy);
789 getlabel(doobjectdestroyandreraise);
790 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
791 emitcall('FPC_PUSHEXCEPTADDR');
792 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
793 exprasmlist^.concat(new(paicpu,
794 op_reg(A_PUSH,S_L,R_EAX)));
795 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
796 emitcall('FPC_SETJMP');
797 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
798 exprasmlist^.concat(new(paicpu,
799 op_reg(A_PUSH,S_L,R_EAX)));
800 exprasmlist^.concat(new(paicpu,
801 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
802 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
803 emitjmp(C_NE,doobjectdestroyandreraise);
805 oldexceptblock:=aktexceptblock;
806 aktexceptblock:=p^.t1;
807 { here we don't have to reset flowcontrol }
808 { the default and on flowcontrols are handled equal }
809 secondpass(p^.t1);
810 exceptflowcontrol:=flowcontrol;
811 aktexceptblock:=oldexceptblock;
813 emitlab(doobjectdestroyandreraise);
814 emitcall('FPC_POPADDRSTACK');
815 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
816 exprasmlist^.concat(new(paicpu,
817 op_reg(A_POP,S_L,R_EAX)));
818 exprasmlist^.concat(new(paicpu,
819 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
820 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
821 emitjmp(C_E,doobjectdestroy);
822 emitcall('FPC_POPSECONDOBJECTSTACK');
823 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
824 emit_reg(A_PUSH,S_L,R_EAX);
825 emitcall('FPC_DESTROYEXCEPTION');
826 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
827 { we don't need to restore esi here because reraise never }
828 { returns }
829 emitcall('FPC_RERAISE');
831 emitlab(doobjectdestroy);
832 cleanupobjectstack;
833 emitjmp(C_None,endexceptlabel);
835 else
836 begin
837 emitcall('FPC_RERAISE');
838 exceptflowcontrol:=flowcontrol;
839 end;
841 if fc_exit in exceptflowcontrol then
842 begin
843 { do some magic for exit in the try block }
844 emitlab(exitexceptlabel);
845 { we must also destroy the address frame which guards }
846 { exception object }
847 cleanupaddrstack;
848 cleanupobjectstack;
849 emitjmp(C_None,oldaktexitlabel);
850 end;
852 if fc_break in exceptflowcontrol then
853 begin
854 emitlab(breakexceptlabel);
855 { we must also destroy the address frame which guards }
856 { exception object }
857 cleanupaddrstack;
858 cleanupobjectstack;
859 emitjmp(C_None,oldaktbreaklabel);
860 end;
862 if fc_continue in exceptflowcontrol then
863 begin
864 emitlab(continueexceptlabel);
865 { we must also destroy the address frame which guards }
866 { exception object }
867 cleanupaddrstack;
868 cleanupobjectstack;
869 emitjmp(C_None,oldaktcontinuelabel);
870 end;
872 if fc_exit in tryflowcontrol then
873 begin
874 { do some magic for exit in the try block }
875 emitlab(exittrylabel);
876 cleanupaddrstack;
877 emitjmp(C_None,oldaktexitlabel);
878 end;
880 if fc_break in tryflowcontrol then
881 begin
882 emitlab(breaktrylabel);
883 cleanupaddrstack;
884 emitjmp(C_None,oldaktbreaklabel);
885 end;
887 if fc_continue in tryflowcontrol then
888 begin
889 emitlab(continuetrylabel);
890 cleanupaddrstack;
891 emitjmp(C_None,oldaktcontinuelabel);
892 end;
894 emitlab(endexceptlabel);
896 errorexit:
897 { restore all saved labels }
898 endexceptlabel:=oldendexceptlabel;
900 { restore the control flow labels }
901 aktexitlabel:=oldaktexitlabel;
902 aktexit2label:=oldaktexit2label;
903 if assigned(oldaktbreaklabel) then
904 begin
905 aktcontinuelabel:=oldaktcontinuelabel;
906 aktbreaklabel:=oldaktbreaklabel;
907 end;
909 { return all used control flow statements }
910 flowcontrol:=oldflowcontrol+exceptflowcontrol+
911 tryflowcontrol;
912 end;
914 procedure secondon(var p : ptree);
917 nextonlabel,
918 exitonlabel,
919 continueonlabel,
920 breakonlabel,
921 oldaktexitlabel,
922 oldaktexit2label,
923 oldaktcontinuelabel,
924 doobjectdestroyandreraise,
925 doobjectdestroy,
926 oldaktbreaklabel : pasmlabel;
927 ref : treference;
928 oldexceptblock : ptree;
929 oldflowcontrol : tflowcontrol;
931 begin
932 oldflowcontrol:=flowcontrol;
933 flowcontrol:=[];
934 getlabel(nextonlabel);
936 { push the vmt }
937 emit_sym(A_PUSH,S_L,
938 newasmsymbol(p^.excepttype^.vmt_mangledname));
939 emitcall('FPC_CATCHES');
940 { allocate eax }
941 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
942 emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
943 emitjmp(C_E,nextonlabel);
944 ref.symbol:=nil;
945 gettempofsizereference(4,ref);
947 { what a hack ! }
948 if assigned(p^.exceptsymtable) then
949 pvarsym(p^.exceptsymtable^.symindex^.first)^.address:=ref.offset;
951 emit_reg_ref(A_MOV,S_L,
952 R_EAX,newreference(ref));
953 { deallocate eax }
954 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
956 { in the case that another exception is risen }
957 { we've to destroy the old one }
958 getlabel(doobjectdestroyandreraise);
959 exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
960 emitcall('FPC_PUSHEXCEPTADDR');
961 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
962 exprasmlist^.concat(new(paicpu,
963 op_reg(A_PUSH,S_L,R_EAX)));
964 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
965 emitcall('FPC_SETJMP');
966 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
967 exprasmlist^.concat(new(paicpu,
968 op_reg(A_PUSH,S_L,R_EAX)));
969 exprasmlist^.concat(new(paicpu,
970 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
971 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
972 emitjmp(C_NE,doobjectdestroyandreraise);
974 if assigned(p^.right) then
975 begin
976 oldaktexitlabel:=aktexitlabel;
977 oldaktexit2label:=aktexit2label;
978 getlabel(exitonlabel);
979 aktexitlabel:=exitonlabel;
980 aktexit2label:=exitonlabel;
981 if assigned(aktbreaklabel) then
982 begin
983 oldaktcontinuelabel:=aktcontinuelabel;
984 oldaktbreaklabel:=aktbreaklabel;
985 getlabel(breakonlabel);
986 getlabel(continueonlabel);
987 aktcontinuelabel:=continueonlabel;
988 aktbreaklabel:=breakonlabel;
989 end;
991 { esi is destroyed by FPC_CATCHES }
992 maybe_loadesi;
993 oldexceptblock:=aktexceptblock;
994 aktexceptblock:=p^.right;
995 secondpass(p^.right);
996 aktexceptblock:=oldexceptblock;
997 end;
998 getlabel(doobjectdestroy);
999 emitlab(doobjectdestroyandreraise);
1000 emitcall('FPC_POPADDRSTACK');
1001 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1002 exprasmlist^.concat(new(paicpu,
1003 op_reg(A_POP,S_L,R_EAX)));
1004 exprasmlist^.concat(new(paicpu,
1005 op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
1006 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
1007 emitjmp(C_E,doobjectdestroy);
1008 emitcall('FPC_POPSECONDOBJECTSTACK');
1009 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1010 emit_reg(A_PUSH,S_L,R_EAX);
1011 emitcall('FPC_DESTROYEXCEPTION');
1012 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
1013 { we don't need to restore esi here because reraise never }
1014 { returns }
1015 emitcall('FPC_RERAISE');
1017 emitlab(doobjectdestroy);
1018 cleanupobjectstack;
1019 { clear some stuff }
1020 ungetiftemp(ref);
1021 emitjmp(C_None,endexceptlabel);
1023 if assigned(p^.right) then
1024 begin
1025 { special handling for control flow instructions }
1026 if fc_exit in flowcontrol then
1027 begin
1028 { the address and object pop does secondtryexcept }
1029 emitlab(exitonlabel);
1030 emitjmp(C_None,oldaktexitlabel);
1031 end;
1033 if fc_break in flowcontrol then
1034 begin
1035 { the address and object pop does secondtryexcept }
1036 emitlab(breakonlabel);
1037 emitjmp(C_None,oldaktbreaklabel);
1038 end;
1040 if fc_continue in flowcontrol then
1041 begin
1042 { the address and object pop does secondtryexcept }
1043 emitlab(continueonlabel);
1044 emitjmp(C_None,oldaktcontinuelabel);
1045 end;
1047 aktexitlabel:=oldaktexitlabel;
1048 aktexit2label:=oldaktexit2label;
1049 if assigned(oldaktbreaklabel) then
1050 begin
1051 aktcontinuelabel:=oldaktcontinuelabel;
1052 aktbreaklabel:=oldaktbreaklabel;
1053 end;
1054 end;
1056 emitlab(nextonlabel);
1057 flowcontrol:=oldflowcontrol+flowcontrol;
1058 { next on node }
1059 if assigned(p^.left) then
1060 begin
1061 cleartempgen;
1062 secondpass(p^.left);
1063 end;
1064 end;
1066 {*****************************************************************************
1067 SecondTryFinally
1068 *****************************************************************************}
1070 procedure secondtryfinally(var p : ptree);
1073 reraiselabel,
1074 finallylabel,
1075 endfinallylabel,
1076 exitfinallylabel,
1077 continuefinallylabel,
1078 breakfinallylabel,
1079 oldaktexitlabel,
1080 oldaktexit2label,
1081 oldaktcontinuelabel,
1082 oldaktbreaklabel : pasmlabel;
1083 oldexceptblock : ptree;
1084 oldflowcontrol,tryflowcontrol : tflowcontrol;
1085 decconst : longint;
1087 begin
1088 { check if child nodes do a break/continue/exit }
1089 oldflowcontrol:=flowcontrol;
1090 flowcontrol:=[];
1091 { we modify EAX }
1092 usedinproc:=usedinproc or ($80 shr byte(R_EAX));
1093 getlabel(finallylabel);
1094 getlabel(endfinallylabel);
1095 getlabel(reraiselabel);
1097 { the finally block must catch break, continue and exit }
1098 { statements }
1099 oldaktexitlabel:=aktexitlabel;
1100 oldaktexit2label:=aktexit2label;
1101 getlabel(exitfinallylabel);
1102 aktexitlabel:=exitfinallylabel;
1103 aktexit2label:=exitfinallylabel;
1104 if assigned(aktbreaklabel) then
1105 begin
1106 oldaktcontinuelabel:=aktcontinuelabel;
1107 oldaktbreaklabel:=aktbreaklabel;
1108 getlabel(breakfinallylabel);
1109 getlabel(continuefinallylabel);
1110 aktcontinuelabel:=continuefinallylabel;
1111 aktbreaklabel:=breakfinallylabel;
1112 end;
1114 push_int(1); { Type of stack-frame must be pushed}
1115 emitcall('FPC_PUSHEXCEPTADDR');
1116 { allocate eax }
1117 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1118 emit_reg(A_PUSH,S_L,R_EAX);
1119 emitcall('FPC_SETJMP');
1120 emit_reg(A_PUSH,S_L,R_EAX);
1121 emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
1122 { deallocate eax }
1123 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
1124 emitjmp(C_NE,finallylabel);
1126 { try code }
1127 if assigned(p^.left) then
1128 begin
1129 oldexceptblock:=aktexceptblock;
1130 aktexceptblock:=p^.left;
1131 secondpass(p^.left);
1132 tryflowcontrol:=flowcontrol;
1133 if codegenerror then
1134 exit;
1135 aktexceptblock:=oldexceptblock;
1136 end;
1138 emitlab(finallylabel);
1139 emitcall('FPC_POPADDRSTACK');
1140 { finally code }
1141 oldexceptblock:=aktexceptblock;
1142 aktexceptblock:=p^.right;
1143 flowcontrol:=[];
1144 secondpass(p^.right);
1145 if flowcontrol<>[] then
1146 CGMessage(cg_e_control_flow_outside_finally);
1147 aktexceptblock:=oldexceptblock;
1148 if codegenerror then
1149 exit;
1150 { allocate eax }
1151 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1152 emit_reg(A_POP,S_L,R_EAX);
1153 emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
1154 emitjmp(C_E,endfinallylabel);
1155 emit_reg(A_DEC,S_L,R_EAX);
1156 emitjmp(C_Z,reraiselabel);
1157 if fc_exit in tryflowcontrol then
1158 begin
1159 emit_reg(A_DEC,S_L,R_EAX);
1160 emitjmp(C_Z,oldaktexitlabel);
1161 decconst:=1;
1163 else
1164 decconst:=2;
1165 if fc_break in tryflowcontrol then
1166 begin
1167 emit_const_reg(A_SUB,S_L,decconst,R_EAX);
1168 emitjmp(C_Z,oldaktbreaklabel);
1169 decconst:=1;
1171 else
1172 inc(decconst);
1173 if fc_continue in tryflowcontrol then
1174 begin
1175 emit_const_reg(A_SUB,S_L,decconst,R_EAX);
1176 emitjmp(C_Z,oldaktcontinuelabel);
1177 end;
1178 { deallocate eax }
1179 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
1180 emitlab(reraiselabel);
1181 emitcall('FPC_RERAISE');
1182 { do some magic for exit,break,continue in the try block }
1183 if fc_exit in tryflowcontrol then
1184 begin
1185 emitlab(exitfinallylabel);
1186 { allocate eax }
1187 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1188 emit_reg(A_POP,S_L,R_EAX);
1189 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1190 emit_const(A_PUSH,S_L,2);
1191 emitjmp(C_NONE,finallylabel);
1192 end;
1193 if fc_break in tryflowcontrol then
1194 begin
1195 emitlab(breakfinallylabel);
1196 { allocate eax }
1197 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1198 emit_reg(A_POP,S_L,R_EAX);
1199 { deallocate eax }
1200 exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
1201 emit_const(A_PUSH,S_L,3);
1202 emitjmp(C_NONE,finallylabel);
1203 end;
1204 if fc_continue in tryflowcontrol then
1205 begin
1206 emitlab(continuefinallylabel);
1207 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1208 emit_reg(A_POP,S_L,R_EAX);
1209 exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
1210 emit_const(A_PUSH,S_L,4);
1211 emitjmp(C_NONE,finallylabel);
1212 end;
1214 emitlab(endfinallylabel);
1216 aktexitlabel:=oldaktexitlabel;
1217 aktexit2label:=oldaktexit2label;
1218 if assigned(aktbreaklabel) then
1219 begin
1220 aktcontinuelabel:=oldaktcontinuelabel;
1221 aktbreaklabel:=oldaktbreaklabel;
1222 end;
1223 flowcontrol:=oldflowcontrol+tryflowcontrol;
1224 end;
1227 {*****************************************************************************
1228 SecondFail
1229 *****************************************************************************}
1231 procedure secondfail(var p : ptree);
1232 begin
1233 emitjmp(C_None,faillabel);
1234 end;
1237 end.
1239 $Log$
1240 Revision 1.1 2002/02/19 08:21:37 sasu
1241 Initial revision
1243 Revision 1.1.2.1 2000/08/13 08:40:33 peter
1244 * restore labels when error in except block
1246 Revision 1.1 2000/07/13 06:29:45 michael
1247 + Initial import
1249 Revision 1.75 2000/07/06 20:43:44 florian
1250 * the on statement has to clear the temp. gen before calling secondpass for
1251 the next on statement
1253 Revision 1.74 2000/05/09 19:05:56 florian
1254 * fixed a problem when returning int64/qword from a function in -Or: in some
1255 cases a wrong result was returned
1257 Revision 1.73 2000/04/24 11:11:50 peter
1258 * backtraces for exceptions are now only generated from the place of the
1259 exception
1260 * frame is also pushed for exceptions
1261 * raise statement enhanced with [,<frame>]
1263 Revision 1.72 2000/04/22 15:29:26 jonas
1264 * cleaner register (de)allocation in secondfor (for optimizer)
1266 Revision 1.71 2000/04/16 08:08:44 jonas
1267 * release register used in for-loop before end label (for better
1268 optimizations)
1270 Revision 1.70 2000/02/29 23:58:19 pierre
1271 Use $GOTO ON
1273 Revision 1.69 2000/02/10 23:44:42 florian
1274 * big update for exception handling code generation: possible mem holes
1275 fixed, break/continue/exit should work always now as expected
1277 Revision 1.68 2000/02/09 13:22:47 peter
1278 * log truncated
1280 Revision 1.67 2000/01/21 12:17:42 jonas
1281 * regallocation fixes
1283 Revision 1.66 2000/01/07 01:14:20 peter
1284 * updated copyright to 2000
1286 Revision 1.65 1999/12/22 23:30:06 peter
1287 * nested try blocks work again
1289 Revision 1.64 1999/12/22 01:01:46 peter
1290 - removed freelabel()
1291 * added undefined label detection in internal assembler, this prevents
1292 a lot of ld crashes and wrong .o files
1293 * .o files aren't written anymore if errors have occured
1294 * inlining of assembler labels is now correct
1296 Revision 1.63 1999/12/19 17:02:45 peter
1297 * support exit,break,continue in try...except
1298 * support break,continue in try...finally
1300 Revision 1.62 1999/12/17 11:20:06 florian
1301 * made the goto checking for excpetions more fool proof against errors
1303 Revision 1.61 1999/12/14 09:58:41 florian
1304 + compiler checks now if a goto leaves an exception block
1306 Revision 1.60 1999/12/01 12:36:23 peter
1307 * fixed selfpointer after destroyexception
1309 Revision 1.59 1999/11/30 10:40:42 peter
1310 + ttype, tsymlist
1312 Revision 1.58 1999/11/28 23:15:23 pierre
1313 * fix for form bug 721
1315 Revision 1.57 1999/11/15 21:49:09 peter
1316 * push address also for raise at
1318 Revision 1.56 1999/11/06 14:34:17 peter
1319 * truncated log to 20 revs
1321 Revision 1.55 1999/10/30 17:35:26 peter
1322 * fpc_freemem fpc_getmem new callings updated
1324 Revision 1.54 1999/10/21 16:41:37 florian
1325 * problems with readln fixed: esi wasn't restored correctly when
1326 reading ordinal fields of objects futher the register allocation
1327 didn't take care of the extra register when reading ordinal values
1328 * enumerations can now be used in constant indexes of properties
1330 Revision 1.53 1999/10/05 22:01:52 pierre
1331 * bug exit('test') + fail for classes
1333 Revision 1.52 1999/09/27 23:44:46 peter
1334 * procinfo is now a pointer
1335 * support for result setting in sub procedure
1337 Revision 1.51 1999/09/26 13:26:05 florian
1338 * exception patch of Romio nevertheless the excpetion handling
1339 needs some corections regarding register saving
1340 * gettempansistring is again a procedure
1342 Revision 1.50 1999/09/20 16:35:43 peter
1343 * restored old alignment, saves 40k on ppc386
1345 Revision 1.49 1999/09/15 20:35:37 florian
1346 * small fix to operator overloading when in MMX mode
1347 + the compiler uses now fldz and fld1 if possible
1348 + some fixes to floating point registers
1349 + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
1350 * .... ???
1352 Revision 1.48 1999/09/07 07:56:37 peter
1353 * reload esi in except block to allow virtual methods
1355 Revision 1.47 1999/08/25 11:59:42 jonas
1356 * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)