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 ****************************************************************************
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
);
47 tenumflowcontrol
= (fc_exit
,fc_break
,fc_continue
);
48 tflowcontrol
= set of tenumflowcontrol
;
51 flowcontrol
: tflowcontrol
;
56 cobjects
,verbose
,globtype
,globals
,systems
,
57 symconst
,symtable
,aasm
,types
,
58 hcodegen
,temp_gen
,pass_2
,
60 cgai386
,tgeni386
,tcflw
;
62 {*****************************************************************************
64 *****************************************************************************}
66 procedure second_while_repeatn(var p
: ptree
);
69 oldclabel
,oldblabel
: pasmlabel
;
70 otlabel
,oflabel
: pasmlabel
;
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
);
87 aktcontinuelabel
:=lcont
;
88 aktbreaklabel
:=lbreak
;
90 if assigned(p
^.right
) then
95 if p
^.treetype
=whilen
then
108 maketojumpbool(p
^.left
);
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
];
120 {*****************************************************************************
122 *****************************************************************************}
124 procedure secondifn(var p
: ptree
);
127 hl
,otlabel
,oflabel
: pasmlabel
;
133 getlabel(falselabel
);
136 maketojumpbool(p
^.left
);
137 if assigned(p
^.right
) then
141 secondpass(p
^.right
);
143 if assigned(p
^.t1
) then
145 if assigned(p
^.right
) then
148 { do go back to if line !! }
149 aktfilepos
:=exprasmlist
^.getlasttaifilepos
^;
155 if assigned(p
^.right
) then
162 if not(assigned(p
^.right
)) then
171 {*****************************************************************************
173 *****************************************************************************}
175 procedure secondfor(var p
: ptree
);
177 l3
,oldclabel
,oldblabel
: pasmlabel
;
178 omitfirstcomp
,temptovalue
: boolean;
183 cmpreg
,cmp32
: tregister
;
185 count_var_is_signed
: boolean;
188 oldclabel
:=aktcontinuelabel
;
189 oldblabel
:=aktbreaklabel
;
190 getlabel(aktcontinuelabel
);
191 getlabel(aktbreaklabel
);
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 }
204 hs
:=p
^.t2
^.resulttype
^.size
;
205 if p
^.t2
^.location
.loc
<> LOC_CREGISTER
then
206 cmp32
:=getregister32
;
210 if p
^.t2
^.location
.loc
<> LOC_CREGISTER
then
211 cmpreg
:=reg32toreg8(cmp32
);
215 if p
^.t2
^.location
.loc
<> LOC_CREGISTER
then
216 cmpreg
:=reg32toreg16(cmp32
);
220 if p
^.t2
^.location
.loc
<> LOC_CREGISTER
then
225 { first set the to value
226 because the count var can be in the expression !! }
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
234 gettempofsizereference(hs
,temp1
);
236 if (p
^.right
^.location
.loc
=LOC_REGISTER
) or
237 (p
^.right
^.location
.loc
=LOC_CREGISTER
) then
239 emit_reg_ref(A_MOV
,opsize
,p
^.right
^.location
.register,
240 newreference(temp1
));
243 concatcopy(p
^.right
^.location
.reference
,temp1
,hs
,false,false);
248 { produce start assignment }
251 count_var_is_signed
:=is_signed(porddef(p
^.t2
^.resulttype
));
254 if p
^.t2
^.location
.loc
=LOC_CREGISTER
then
256 emit_ref_reg(A_CMP
,opsize
,newreference(temp1
),
257 p
^.t2
^.location
.register);
261 emit_ref_reg(A_MOV
,opsize
,newreference(p
^.t2
^.location
.reference
),
263 emit_ref_reg(A_CMP
,opsize
,newreference(temp1
),
265 { temp register not necessary anymore currently (JM) }
266 ungetregister32(cmp32
);
271 if not(omitfirstcomp
) then
273 if p
^.t2
^.location
.loc
=LOC_CREGISTER
then
274 emit_const_reg(A_CMP
,opsize
,p
^.right
^.value
,
275 p
^.t2
^.location
.register)
277 emit_const_ref(A_CMP
,opsize
,p
^.right
^.value
,
278 newreference(p
^.t2
^.location
.reference
));
282 if count_var_is_signed
then
287 if count_var_is_signed
then
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)));
301 { help register must not be in instruction block }
303 if assigned(p
^.t1
) then
306 emitlab(aktcontinuelabel
);
308 { makes no problems there }
311 if (p
^.t2
^.location
.loc
<> LOC_CREGISTER
) then
313 { demand help register again }
314 cmp32
:=getregister32
;
316 1 : cmpreg
:=reg32toreg8(cmp32
);
317 2 : cmpreg
:=reg32toreg16(cmp32
);
322 { produce comparison and the corresponding }
326 if p
^.t2
^.location
.loc
=LOC_CREGISTER
then
328 emit_ref_reg(A_CMP
,opsize
,newreference(temp1
),
329 p
^.t2
^.location
.register);
333 emit_ref_reg(A_MOV
,opsize
,newreference(p
^.t2
^.location
.reference
),
335 emit_ref_reg(A_CMP
,opsize
,newreference(temp1
),
341 if p
^.t2
^.location
.loc
=LOC_CREGISTER
then
342 emit_const_reg(A_CMP
,opsize
,p
^.right
^.value
,
343 p
^.t2
^.location
.register)
345 emit_const_ref(A_CMP
,opsize
,p
^.right
^.value
,
346 newreference(p
^.t2
^.location
.reference
));
349 if count_var_is_signed
then
354 if count_var_is_signed
then
358 emitjmp(hcond
,aktbreaklabel
);
359 { according to count direction DEC or INC... }
360 { must be after the test because of 0to 255 for bytes !! }
366 if p
^.t2
^.location
.loc
=LOC_CREGISTER
then
367 emit_reg(hop
,opsize
,p
^.t2
^.location
.register)
369 emit_ref(hop
,opsize
,newreference(p
^.t2
^.location
.reference
));
372 if (p
^.t2
^.location
.loc
<> LOC_CREGISTER
) then
373 ungetregister32(cmp32
);
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
];
387 {*****************************************************************************
389 *****************************************************************************}
391 procedure secondexitn(var p
: ptree
);
396 otlabel
,oflabel
: pasmlabel
;
402 include(flowcontrol
,fc_exit
);
403 if assigned(p
^.left
) then
404 if p
^.left
^.treetype
=assignn
then
406 { just do a normal assignment followed by exit }
408 emitjmp(C_None
,aktexitlabel
);
415 getlabel(falselabel
);
417 case p
^.left
^.location
.loc
of
418 LOC_FPU
: goto do_jmp
;
420 LOC_REFERENCE
: is_mem
:=true;
422 LOC_REGISTER
: is_mem
:=false;
424 emit_flag2reg(p
^.left
^.location
.resflags
,R_AL
);
429 emit_const_reg(A_MOV
,S_B
,1,R_AL
);
430 emitjmp(C_None
,aktexit2label
);
432 emit_reg_reg(A_XOR
,S_B
,R_AL
,R_AL
);
438 case procinfo
^.returntype
.def
^.deftype
of
442 emit_ref_reg(A_MOV
,S_L
,
443 newreference(p
^.left
^.location
.reference
),R_EAX
)
445 emit_reg_reg(A_MOV
,S_L
,
446 p
^.left
^.location
.register,R_EAX
);
449 if pfloatdef(procinfo
^.returntype
.def
)^.typ
=f32bit
then
452 emit_ref_reg(A_MOV
,S_L
,
453 newreference(p
^.left
^.location
.reference
),R_EAX
)
455 emit_reg_reg(A_MOV
,S_L
,p
^.left
^.location
.register,R_EAX
);
459 floatload(pfloatdef(procinfo
^.returntype
.def
)^.typ
,p
^.left
^.location
.reference
);
464 { it can be anything shorter than 4 bytes PM
465 this caused form bug 711 }
467 case procinfo
^.returntype
.def
^.size
of
468 { it can be a qword/int64 too ... }
471 emit_ref_reg(A_MOV
,S_L
,
472 newreference(p
^.left
^.location
.reference
),R_EAX
);
473 r
:=newreference(p
^.left
^.location
.reference
);
475 emit_ref_reg(A_MOV
,S_L
,r
,R_EDX
);
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
);
482 { if its 3 bytes only we can still
483 copy one of garbage ! PM }
485 emit_ref_reg(A_MOV
,S_L
,
486 newreference(p
^.left
^.location
.reference
),R_EAX
)
488 emit_reg_reg(A_MOV
,S_L
,p
^.left
^.location
.register,R_EAX
);
490 emit_ref_reg(A_MOV
,S_W
,
491 newreference(p
^.left
^.location
.reference
),R_AX
)
493 emit_reg_reg(A_MOV
,S_W
,makereg16(p
^.left
^.location
.register),R_AX
);
495 emit_ref_reg(A_MOV
,S_B
,
496 newreference(p
^.left
^.location
.reference
),R_AL
)
498 emit_reg_reg(A_MOV
,S_B
,makereg8(p
^.left
^.location
.register),R_AL
);
499 else internalerror(605001);
506 emitjmp(C_None
,aktexit2label
);
510 emitjmp(C_None
,aktexitlabel
);
515 {*****************************************************************************
517 *****************************************************************************}
519 procedure secondbreakn(var p
: ptree
);
521 include(flowcontrol
,fc_break
);
522 if aktbreaklabel
<>nil then
523 emitjmp(C_None
,aktbreaklabel
)
525 CGMessage(cg_e_break_not_allowed
);
529 {*****************************************************************************
531 *****************************************************************************}
533 procedure secondcontinuen(var p
: ptree
);
535 include(flowcontrol
,fc_continue
);
536 if aktcontinuelabel
<>nil then
537 emitjmp(C_None
,aktcontinuelabel
)
539 CGMessage(cg_e_continue_not_allowed
);
543 {*****************************************************************************
545 *****************************************************************************}
547 procedure secondgoto(var p
: ptree
);
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
);
559 {*****************************************************************************
561 *****************************************************************************}
563 procedure secondlabel(var p
: ptree
);
571 {*****************************************************************************
573 *****************************************************************************}
575 procedure secondraise(var p
: ptree
);
580 if assigned(p
^.left
) then
582 { multiple parameters? }
583 if assigned(p
^.right
) then
586 if assigned(p
^.frametree
) then
588 secondpass(p
^.frametree
);
591 emit_push_loc(p
^.frametree
^.location
);
594 emit_const(A_PUSH
,S_L
,0);
596 secondpass(p
^.right
);
599 emit_push_loc(p
^.right
^.location
);
605 emit_const(A_PUSH
,S_L
,0);
606 emit_sym(A_PUSH
,S_L
,a
);
612 emit_push_loc(p
^.left
^.location
);
613 emitcall('FPC_RAISEEXCEPTION');
617 emitcall('FPC_POPADDRSTACK');
618 emitcall('FPC_RERAISE');
623 {*****************************************************************************
625 *****************************************************************************}
628 endexceptlabel
: pasmlabel
;
630 { does the necessary things to clean up the object stack }
631 { in the except block }
632 procedure cleanupobjectstack
;
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
)));
643 { pops one element from the exception address stack }
644 { and removes the flag }
645 procedure cleanupaddrstack
;
648 emitcall('FPC_POPADDRSTACK');
650 exprasmlist
^.concat(new(pairegalloc
,alloc(R_EAX
)));
651 emit_reg(A_POP
,S_L
,R_EAX
);
653 exprasmlist
^.concat(new(pairegalloc
,dealloc(R_EAX
)));
656 procedure secondtryexcept(var p
: ptree
);
659 exceptlabel
,doexceptlabel
,oldendexceptlabel
,
668 doobjectdestroyandreraise
,
672 oldaktbreaklabel
: pasmlabel
;
673 oldexceptblock
: ptree
;
676 oldflowcontrol
,tryflowcontrol
,
677 exceptflowcontrol
: tflowcontrol
;
681 oldflowcontrol
:=flowcontrol
;
683 { this can be called recursivly }
684 oldendexceptlabel
:=endexceptlabel
;
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
694 oldaktcontinuelabel
:=aktcontinuelabel
;
695 oldaktbreaklabel
:=aktbreaklabel
;
698 { get new labels for the control flow statements }
699 getlabel(exittrylabel
);
700 getlabel(exitexceptlabel
);
701 if assigned(aktbreaklabel
) then
703 getlabel(breaktrylabel
);
704 getlabel(continuetrylabel
);
705 getlabel(breakexceptlabel
);
706 getlabel(continueexceptlabel
);
709 getlabel(exceptlabel
);
710 getlabel(doexceptlabel
);
711 getlabel(endexceptlabel
);
712 getlabel(lastonlabel
);
713 push_int (1); { push type of exceptionframe }
714 emitcall('FPC_PUSHEXCEPTADDR');
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
);
722 exprasmlist
^.concat(new(pairegalloc
,dealloc(R_EAX
)));
723 emitjmp(C_NE
,exceptlabel
);
726 { set control flow labels for the try block }
727 aktexitlabel
:=exittrylabel
;
728 aktexit2label
:=exittrylabel
;
729 if assigned(oldaktbreaklabel
) then
731 aktcontinuelabel
:=continuetrylabel
;
732 aktbreaklabel
:=breaktrylabel
;
735 oldexceptblock
:=aktexceptblock
;
736 aktexceptblock
:=p
^.left
;
739 tryflowcontrol
:=flowcontrol
;
740 aktexceptblock
:=oldexceptblock
;
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
761 aktcontinuelabel
:=continueexceptlabel
;
762 aktbreaklabel
:=breakexceptlabel
;
767 if assigned(p
^.right
) then
769 oldexceptblock
:=aktexceptblock
;
770 aktexceptblock
:=p
^.right
;
771 secondpass(p
^.right
);
772 aktexceptblock
:=oldexceptblock
;
775 emitlab(lastonlabel
);
776 { default handling except handling }
777 if assigned(p
^.t1
) then
779 { FPC_CATCHES must be called with
780 'default handler' flag (=-1)
783 emitcall('FPC_CATCHES');
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 }
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 }
829 emitcall('FPC_RERAISE');
831 emitlab(doobjectdestroy
);
833 emitjmp(C_None
,endexceptlabel
);
837 emitcall('FPC_RERAISE');
838 exceptflowcontrol
:=flowcontrol
;
841 if fc_exit
in exceptflowcontrol
then
843 { do some magic for exit in the try block }
844 emitlab(exitexceptlabel
);
845 { we must also destroy the address frame which guards }
849 emitjmp(C_None
,oldaktexitlabel
);
852 if fc_break
in exceptflowcontrol
then
854 emitlab(breakexceptlabel
);
855 { we must also destroy the address frame which guards }
859 emitjmp(C_None
,oldaktbreaklabel
);
862 if fc_continue
in exceptflowcontrol
then
864 emitlab(continueexceptlabel
);
865 { we must also destroy the address frame which guards }
869 emitjmp(C_None
,oldaktcontinuelabel
);
872 if fc_exit
in tryflowcontrol
then
874 { do some magic for exit in the try block }
875 emitlab(exittrylabel
);
877 emitjmp(C_None
,oldaktexitlabel
);
880 if fc_break
in tryflowcontrol
then
882 emitlab(breaktrylabel
);
884 emitjmp(C_None
,oldaktbreaklabel
);
887 if fc_continue
in tryflowcontrol
then
889 emitlab(continuetrylabel
);
891 emitjmp(C_None
,oldaktcontinuelabel
);
894 emitlab(endexceptlabel
);
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
905 aktcontinuelabel
:=oldaktcontinuelabel
;
906 aktbreaklabel
:=oldaktbreaklabel
;
909 { return all used control flow statements }
910 flowcontrol
:=oldflowcontrol
+exceptflowcontrol
+
914 procedure secondon(var p
: ptree
);
924 doobjectdestroyandreraise
,
926 oldaktbreaklabel
: pasmlabel
;
928 oldexceptblock
: ptree
;
929 oldflowcontrol
: tflowcontrol
;
932 oldflowcontrol
:=flowcontrol
;
934 getlabel(nextonlabel
);
938 newasmsymbol(p
^.excepttype
^.vmt_mangledname
));
939 emitcall('FPC_CATCHES');
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
);
945 gettempofsizereference(4,ref
);
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
));
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
976 oldaktexitlabel
:=aktexitlabel
;
977 oldaktexit2label
:=aktexit2label
;
978 getlabel(exitonlabel
);
979 aktexitlabel
:=exitonlabel
;
980 aktexit2label
:=exitonlabel
;
981 if assigned(aktbreaklabel
) then
983 oldaktcontinuelabel
:=aktcontinuelabel
;
984 oldaktbreaklabel
:=aktbreaklabel
;
985 getlabel(breakonlabel
);
986 getlabel(continueonlabel
);
987 aktcontinuelabel
:=continueonlabel
;
988 aktbreaklabel
:=breakonlabel
;
991 { esi is destroyed by FPC_CATCHES }
993 oldexceptblock
:=aktexceptblock
;
994 aktexceptblock
:=p
^.right
;
995 secondpass(p
^.right
);
996 aktexceptblock
:=oldexceptblock
;
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 }
1015 emitcall('FPC_RERAISE');
1017 emitlab(doobjectdestroy
);
1019 { clear some stuff }
1021 emitjmp(C_None
,endexceptlabel
);
1023 if assigned(p
^.right
) then
1025 { special handling for control flow instructions }
1026 if fc_exit
in flowcontrol
then
1028 { the address and object pop does secondtryexcept }
1029 emitlab(exitonlabel
);
1030 emitjmp(C_None
,oldaktexitlabel
);
1033 if fc_break
in flowcontrol
then
1035 { the address and object pop does secondtryexcept }
1036 emitlab(breakonlabel
);
1037 emitjmp(C_None
,oldaktbreaklabel
);
1040 if fc_continue
in flowcontrol
then
1042 { the address and object pop does secondtryexcept }
1043 emitlab(continueonlabel
);
1044 emitjmp(C_None
,oldaktcontinuelabel
);
1047 aktexitlabel
:=oldaktexitlabel
;
1048 aktexit2label
:=oldaktexit2label
;
1049 if assigned(oldaktbreaklabel
) then
1051 aktcontinuelabel
:=oldaktcontinuelabel
;
1052 aktbreaklabel
:=oldaktbreaklabel
;
1056 emitlab(nextonlabel
);
1057 flowcontrol
:=oldflowcontrol
+flowcontrol
;
1059 if assigned(p
^.left
) then
1062 secondpass(p
^.left
);
1066 {*****************************************************************************
1068 *****************************************************************************}
1070 procedure secondtryfinally(var p
: ptree
);
1077 continuefinallylabel
,
1081 oldaktcontinuelabel
,
1082 oldaktbreaklabel
: pasmlabel
;
1083 oldexceptblock
: ptree
;
1084 oldflowcontrol
,tryflowcontrol
: tflowcontrol
;
1088 { check if child nodes do a break/continue/exit }
1089 oldflowcontrol
:=flowcontrol
;
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 }
1099 oldaktexitlabel
:=aktexitlabel
;
1100 oldaktexit2label
:=aktexit2label
;
1101 getlabel(exitfinallylabel
);
1102 aktexitlabel
:=exitfinallylabel
;
1103 aktexit2label
:=exitfinallylabel
;
1104 if assigned(aktbreaklabel
) then
1106 oldaktcontinuelabel
:=aktcontinuelabel
;
1107 oldaktbreaklabel
:=aktbreaklabel
;
1108 getlabel(breakfinallylabel
);
1109 getlabel(continuefinallylabel
);
1110 aktcontinuelabel
:=continuefinallylabel
;
1111 aktbreaklabel
:=breakfinallylabel
;
1114 push_int(1); { Type of stack-frame must be pushed}
1115 emitcall('FPC_PUSHEXCEPTADDR');
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
);
1123 exprasmlist
^.concat(new(pairegalloc
,dealloc(R_EAX
)));
1124 emitjmp(C_NE
,finallylabel
);
1127 if assigned(p
^.left
) then
1129 oldexceptblock
:=aktexceptblock
;
1130 aktexceptblock
:=p
^.left
;
1131 secondpass(p
^.left
);
1132 tryflowcontrol
:=flowcontrol
;
1133 if codegenerror
then
1135 aktexceptblock
:=oldexceptblock
;
1138 emitlab(finallylabel
);
1139 emitcall('FPC_POPADDRSTACK');
1141 oldexceptblock
:=aktexceptblock
;
1142 aktexceptblock
:=p
^.right
;
1144 secondpass(p
^.right
);
1145 if flowcontrol
<>[] then
1146 CGMessage(cg_e_control_flow_outside_finally
);
1147 aktexceptblock
:=oldexceptblock
;
1148 if codegenerror
then
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
1159 emit_reg(A_DEC
,S_L
,R_EAX
);
1160 emitjmp(C_Z
,oldaktexitlabel
);
1165 if fc_break
in tryflowcontrol
then
1167 emit_const_reg(A_SUB
,S_L
,decconst
,R_EAX
);
1168 emitjmp(C_Z
,oldaktbreaklabel
);
1173 if fc_continue
in tryflowcontrol
then
1175 emit_const_reg(A_SUB
,S_L
,decconst
,R_EAX
);
1176 emitjmp(C_Z
,oldaktcontinuelabel
);
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
1185 emitlab(exitfinallylabel
);
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
);
1193 if fc_break
in tryflowcontrol
then
1195 emitlab(breakfinallylabel
);
1197 exprasmlist
^.concat(new(pairegalloc
,alloc(R_EAX
)));
1198 emit_reg(A_POP
,S_L
,R_EAX
);
1200 exprasmlist
^.concat(new(pairegalloc
,dealloc(R_EAX
)));
1201 emit_const(A_PUSH
,S_L
,3);
1202 emitjmp(C_NONE
,finallylabel
);
1204 if fc_continue
in tryflowcontrol
then
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
);
1214 emitlab(endfinallylabel
);
1216 aktexitlabel
:=oldaktexitlabel
;
1217 aktexit2label
:=oldaktexit2label
;
1218 if assigned(aktbreaklabel
) then
1220 aktcontinuelabel
:=oldaktcontinuelabel
;
1221 aktbreaklabel
:=oldaktbreaklabel
;
1223 flowcontrol
:=oldflowcontrol
+tryflowcontrol
;
1227 {*****************************************************************************
1229 *****************************************************************************}
1231 procedure secondfail(var p
: ptree
);
1233 emitjmp(C_None
,faillabel
);
1240 Revision 1.1 2002/02/19 08:21:37 sasu
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
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
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
1270 Revision 1.70 2000/02/29 23:58:19 pierre
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
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
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
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)