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 ****************************************************************************}
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;
138 var parasize
:longint;var nostackframe
: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}
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}
167 strings
,globtype
,systems
,globals
,verbose
,files
,types
,pbase
,
168 tgeni386
,temp_gen
,hcodegen
,ppu
172 {$ifndef NOTARGETWIN32}
178 {*****************************************************************************
180 *****************************************************************************}
182 function def_opsize(p1
:pdef
):topsize
;
194 function def2def_opsize(p1
,p2
:pdef
):topsize
;
202 { I don't know if we need it (FK) }
230 function def_getreg(p1
:pdef
):tregister
;
233 1 : def_getreg
:=reg32toreg8(getregister32
);
234 2 : def_getreg
:=reg32toreg16(getregister32
);
235 4 : def_getreg
:=getregister32
;
242 function makereg8(r
:tregister
):tregister
;
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
:
255 function makereg16(r
:tregister
):tregister
;
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
:
262 R_AL
,R_BL
,R_CL
,R_DL
:
263 makereg16
:=reg8toreg16(r
);
268 function makereg32(r
:tregister
):tregister
;
271 R_EAX
,R_EBX
,R_ECX
,R_EDX
,R_EDI
,R_ESI
,R_ESP
:
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
);
281 procedure locflags2reg(var l
:tlocation
;opsize
:topsize
);
283 hregister
: tregister
;
285 if (l
.loc
=LOC_FLAGS
) then
287 hregister
:=getregister32
;
289 S_W
: hregister
:=reg32toreg16(hregister
);
290 S_B
: hregister
:=reg32toreg8(hregister
);
292 emit_flag2reg(l
.resflags
,hregister
);
294 l
.register:=hregister
;
296 else internalerror(270720001);
300 procedure locjump2reg(var l
:tlocation
;opsize
:topsize
; otl
, ofl
: pasmlabel
);
302 hregister
: tregister
;
305 if l
.loc
= LOC_JUMP
then
307 hregister
:=getregister32
;
309 S_W
: hregister
:=reg32toreg16(hregister
);
310 S_B
: hregister
:=reg32toreg8(hregister
);
313 l
.register:=hregister
;
316 emit_const_reg(A_MOV
,opsize
,1,hregister
);
321 emit_reg_reg(A_XOR
,S_L
,makereg32(hregister
),
322 makereg32(hregister
));
325 else internalerror(270720002);
329 {*****************************************************************************
331 *****************************************************************************}
333 procedure emitlab(var l
: pasmlabel
);
335 if not l
^.is_set
then
336 exprasmlist
^.concat(new(pai_label
,init(l
)))
338 internalerror(7453984);
342 procedure emitjmp(c
: tasmcond
;var l
: pasmlabel
);
347 exprasmlist
^.concat(new(paicpu
,op_sym(A_JMP
,S_NO
,l
)))
350 ai
:=new(paicpu
,op_sym(A_Jcc
,S_NO
,l
));
353 exprasmlist
^.concat(ai
);
357 procedure emitjmp(c
: tasmcond
;var l
: pasmlabel
);
362 ai
:= new(paicpu
,op_sym(A_JMP
,S_NO
,l
))
365 ai
:=new(paicpu
,op_sym(A_Jcc
,S_NO
,l
));
369 exprasmlist
^.concat(ai
);
373 procedure emit_flag2reg(flag
:tresflags
;hregister
:tregister
);
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
384 if hregister
in regset16bit
then
392 procedure emit_none(i
: tasmop
;s
: topsize
);
394 exprasmlist
^.concat(new(paicpu
,op_none(i
,s
)));
397 procedure emit_reg(i
: tasmop
;s
: topsize
;reg
: tregister
);
399 exprasmlist
^.concat(new(paicpu
,op_reg(i
,s
,reg
)));
402 procedure emit_ref(i
: tasmop
;s
: topsize
;ref
: preference
);
404 exprasmlist
^.concat(new(paicpu
,op_ref(i
,s
,ref
)));
407 procedure emit_const(i
: tasmop
;s
: topsize
;c
: longint);
409 exprasmlist
^.concat(new(paicpu
,op_const(i
,s
,c
)));
412 procedure emit_const_reg(i
: tasmop
;s
: topsize
;c
: longint;reg
: tregister
);
414 exprasmlist
^.concat(new(paicpu
,op_const_reg(i
,s
,c
,reg
)));
417 procedure emit_const_ref(i
: tasmop
;s
: topsize
;c
: longint;ref
: preference
);
419 exprasmlist
^.concat(new(paicpu
,op_const_ref(i
,s
,c
,ref
)));
422 procedure emit_ref_reg(i
: tasmop
;s
: topsize
;ref
: preference
;reg
: tregister
);
424 exprasmlist
^.concat(new(paicpu
,op_ref_reg(i
,s
,ref
,reg
)));
427 procedure emit_reg_ref(i
: tasmop
;s
: topsize
;reg
: tregister
;ref
: preference
);
429 exprasmlist
^.concat(new(paicpu
,op_reg_ref(i
,s
,reg
,ref
)));
432 procedure emit_reg_reg(i
: tasmop
;s
: topsize
;reg1
,reg2
: tregister
);
434 if (reg1
<>reg2
) or (i
<>A_MOV
) then
435 exprasmlist
^.concat(new(paicpu
,op_reg_reg(i
,s
,reg1
,reg2
)));
438 procedure emit_const_reg_reg(i
: tasmop
;s
: topsize
;c
: longint;reg1
,reg2
: tregister
);
440 exprasmlist
^.concat(new(paicpu
,op_const_reg_reg(i
,s
,c
,reg1
,reg2
)));
443 procedure emit_reg_reg_reg(i
: tasmop
;s
: topsize
;reg1
,reg2
,reg3
: tregister
);
445 exprasmlist
^.concat(new(paicpu
,op_reg_reg_reg(i
,s
,reg1
,reg2
,reg3
)));
448 procedure emit_sym(i
: tasmop
;s
: topsize
;op
: pasmsymbol
);
450 exprasmlist
^.concat(new(paicpu
,op_sym(i
,s
,op
)));
453 procedure emit_sym_ofs(i
: tasmop
;s
: topsize
;op
: pasmsymbol
;ofs
: longint);
455 exprasmlist
^.concat(new(paicpu
,op_sym_ofs(i
,s
,op
,ofs
)));
458 procedure emit_sym_ofs_reg(i
: tasmop
;s
: topsize
;op
: pasmsymbol
;ofs
:longint;reg
: tregister
);
460 exprasmlist
^.concat(new(paicpu
,op_sym_ofs_reg(i
,s
,op
,ofs
,reg
)));
463 procedure emit_sym_ofs_ref(i
: tasmop
;s
: topsize
;op
: pasmsymbol
;ofs
:longint;ref
: preference
);
465 exprasmlist
^.concat(new(paicpu
,op_sym_ofs_ref(i
,s
,op
,ofs
,ref
)));
468 procedure emitcall(const routine
:string);
470 exprasmlist
^.concat(new(paicpu
,op_sym(A_CALL
,S_NO
,newasmsymbol(routine
))));
473 { only usefull in startup code }
474 procedure emitinsertcall(const routine
:string);
476 exprasmlist
^.insert(new(paicpu
,op_sym(A_CALL
,S_NO
,newasmsymbol(routine
))));
480 procedure emit_mov_loc_ref(const t
:tlocation
;const ref
:treference
;siz
:topsize
;freetemp
:boolean);
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 }
495 LOC_REFERENCE
: begin
496 if t
.reference
.is_immediate
then
497 emit_const_ref(A_MOV
,siz
,
498 t
.reference
.offset
,newreference(ref
))
503 { we can't do a getregister in the code generator }
504 { without problems!!! }
505 if usablereg32
>0 then
506 hreg
:=reg32toreg8(getregister32
)
509 emit_reg(A_PUSH
,S_L
,R_EAX
);
518 if hreg
in [R_DI
,R_EDI
] then
519 getexplicitregister32(R_EDI
);
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
))));
529 emit_reg(A_POP
,S_L
,R_EAX
)
534 if hreg
in [R_DI
,R_EDI
] then
535 ungetregister32(R_EDI
);
537 { we can release the registers }
538 { but only AFTER the MOV! Important for the optimizer!
543 ungetiftemp(t
.reference
);
551 procedure emit_mov_loc_reg(const t
:tlocation
;reg
:tregister
);
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 }
560 LOC_REFERENCE
: begin
561 if t
.reference
.is_immediate
then
562 emit_const_reg(A_MOV
,S_L
,
563 t
.reference
.offset
,reg
)
566 emit_ref_reg(A_MOV
,S_L
,
567 newreference(t
.reference
),reg
);
575 procedure emit_mov_reg_loc(reg
: TRegister
; const t
:tlocation
);
579 LOC_CREGISTER
: begin
580 emit_reg_reg(A_MOV
,RegSize(Reg
),
584 LOC_REFERENCE
: begin
585 if t
.reference
.is_immediate
then
589 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,RegSize(Reg
),
590 Reg
,newreference(t
.reference
))));
599 procedure emit_lea_loc_reg(const t
:tlocation
;reg
:tregister
;freetemp
:boolean);
603 LOC_REFERENCE
: begin
604 if t
.reference
.is_immediate
then
608 emit_ref_reg(A_LEA
,S_L
,
609 newreference(t
.reference
),reg
);
612 ungetiftemp(t
.reference
);
620 procedure emit_movq_reg_loc(reghigh
,reglow
: TRegister
;t
:tlocation
);
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
);
631 LOC_REFERENCE
: begin
632 if t
.reference
.is_immediate
then
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
))));
649 procedure emit_pushq_loc(const t
: tlocation
);
659 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,
661 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,
667 hr
:=newreference(t
.reference
);
669 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,S_L
,
671 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,S_L
,
672 newreference(t
.reference
))));
673 ungetiftemp(t
.reference
);
675 else internalerror(331);
679 procedure remove_non_regvars_from_loc(const t
: tlocation
; var regs
: byte);
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
:
687 if not(cs_regalloc
in aktglobalswitches
) or
688 (t
.reference
.base
in usableregs
) then
690 not($80 shr byte(t
.reference
.base
));
691 if not(cs_regalloc
in aktglobalswitches
) or
692 (t
.reference
.index
in usableregs
) then
694 not($80 shr byte(t
.reference
.index
));
700 procedure release_loc(const t
: tlocation
);
707 ungetregister32(t
.register);
711 del_reference(t
.reference
);
712 else internalerror(332);
716 procedure release_qword_loc(const t
: tlocation
);
722 ungetregister32(t
.registerhigh
);
723 ungetregister32(t
.registerlow
);
727 del_reference(t
.reference
);
728 else internalerror(331);
733 procedure emit_push_loc(const t
:tlocation
);
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 }
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
)))
746 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,S_L
,newreference(t
.reference
))));
747 del_reference(t
.reference
);
748 ungetiftemp(t
.reference
);
756 procedure emit_pushw_loc(const t
:tlocation
);
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))))
766 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_W
,makereg16(t
.register))));
767 ungetregister(t
.register); { the register is not needed anymore }
770 LOC_REFERENCE
: begin
771 if target_os
.stackalignment
=4 then
775 if t
.reference
.is_immediate
then
776 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,opsize
,t
.reference
.offset
)))
778 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,opsize
,newreference(t
.reference
))));
779 del_reference(t
.reference
);
780 ungetiftemp(t
.reference
);
788 procedure emit_lea_loc_ref(const t
:tlocation
;const ref
:treference
;freetemp
:boolean);
792 LOC_REFERENCE
: begin
793 if t
.reference
.is_immediate
then
798 getexplicitregister32(R_EDI
);
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
))));
805 ungetregister32(R_EDI
);
808 { release the registers }
809 del_reference(t
.reference
);
811 ungetiftemp(t
.reference
);
819 procedure emit_push_lea_loc(const t
:tlocation
;freetemp
:boolean);
823 LOC_REFERENCE
: begin
824 if t
.reference
.is_immediate
then
829 getexplicitregister32(R_EDI
);
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
)));
835 ungetregister32(R_EDI
);
839 ungetiftemp(t
.reference
);
846 procedure emit_push_mem_size(const t
: treference
; size
: longint);
852 if t
.is_immediate
then
855 (target_os
.stackalignment
=4) then
856 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,S_L
,t
.offset
)))
858 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,S_W
,t
.offset
)));
863 getexplicitregister32(R_EDI
);
867 else internalerror(200008071);
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
)))
874 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_W
,R_DI
)));
875 ungetregister32(R_EDI
);
881 internalerror(200008072);
885 procedure emit_to_mem(var p
:ptree
);
891 case p
^.location
.loc
of
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; }
901 if is_64bitint(p
^.resulttype
) then
903 gettempofsizereference(8,r
);
904 emit_reg_ref(A_MOV
,S_L
,p
^.location
.registerlow
,
907 emit_reg_ref(A_MOV
,S_L
,p
^.location
.registerhigh
,
910 p
^.location
.reference
:=r
;
913 internalerror(1405001);
917 LOC_CFPUREGISTER
: begin
918 emit_reg(A_FLD
,S_NO
,correct_fpuregister(p
^.location
.register,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; }
929 p
^.location
.loc
:=LOC_MEM
;
933 procedure emit_to_reg16(var hr
:tregister
);
935 { ranges are a little bit bug sensitive ! }
937 R_EAX
,R_EBX
,R_ECX
,R_EDX
,R_EDI
,R_ESI
,R_ESP
,R_EBP
:
939 hr
:=reg32toreg16(hr
);
944 emit_const_reg(A_AND
,S_W
,$ff,hr
);
949 emit_const_reg(A_AND
,S_W
,$ff00,hr
);
955 procedure emit_to_reg32(var hr
:tregister
);
957 { ranges are a little bit bug sensitive ! }
959 R_AX
,R_BX
,R_CX
,R_DX
,R_DI
,R_SI
,R_SP
,R_BP
:
961 hr
:=reg16toreg32(hr
);
962 emit_const_reg(A_AND
,S_L
,$ffff,hr
);
967 emit_const_reg(A_AND
,S_L
,$ff,hr
);
972 emit_const_reg(A_AND
,S_L
,$ff00,hr
);
977 procedure emit_mov_ref_reg64(r
: treference
;rl
,rh
: tregister
);
983 { if we load a 64 bit reference, we must be careful because }
984 { we could overwrite the registers of the reference by }
986 getexplicitregister32(R_EDI
);
989 emit_reg_reg(A_MOV
,S_L
,r
.base
,
993 else if r
.index
=rl
then
995 emit_reg_reg(A_MOV
,S_L
,r
.index
,
999 emit_ref_reg(A_MOV
,S_L
,
1000 newreference(r
),rl
);
1001 hr
:=newreference(r
);
1003 emit_ref_reg(A_MOV
,S_L
,
1005 ungetregister32(R_EDI
);
1008 {*****************************************************************************
1009 Emit String Functions
1010 *****************************************************************************}
1012 procedure copyshortstring(const dref
,sref
: treference
;len
: byte;
1013 loadref
, del_sref
: boolean);
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) }
1019 del_reference(sref
);
1023 emitpushreferenceaddr(sref
);
1025 emitcall('FPC_SHORTSTR_COPY');
1029 procedure copylongstring(const dref
,sref
: treference
;len
: longint;loadref
:boolean);
1031 emitpushreferenceaddr(dref
);
1035 emitpushreferenceaddr(sref
);
1037 emitcall('FPC_LONGSTR_COPY');
1042 procedure incrstringref(t
: pdef
;const ref
: treference
);
1045 pushedregs
: tpushed
;
1048 pushusedregisters(pushedregs
,$ff);
1049 emitpushreferenceaddr(ref
);
1050 if is_ansistring(t
) then
1052 emitcall('FPC_ANSISTR_INCR_REF');
1054 else if is_widestring(t
) then
1056 emitcall('FPC_WIDESTR_INCR_REF');
1058 else internalerror(1859);
1059 popusedregisters(pushedregs
);
1063 procedure decrstringref(t
: pdef
;const ref
: treference
);
1066 pushedregs
: tpushed
;
1069 pushusedregisters(pushedregs
,$ff);
1070 emitpushreferenceaddr(ref
);
1071 if is_ansistring(t
) then
1073 emitcall('FPC_ANSISTR_DECR_REF');
1075 else if is_widestring(t
) then
1077 emitcall('FPC_WIDESTR_DECR_REF');
1079 else internalerror(1859);
1080 popusedregisters(pushedregs
);
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
1092 ungettemp
: boolean;
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
);
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
:
1112 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,p
^.right
^.location
.register)));
1113 ungetregister32(p
^.right
^.location
.register);
1115 LOC_REFERENCE
,LOC_MEM
:
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
);
1126 emitpushreferenceaddr(p
^.left
^.location
.reference
);
1127 del_reference(p
^.left
^.location
.reference
);
1128 emitcall('FPC_ANSISTR_ASSIGN');
1130 popusedregisters(pushed
);
1132 ungetiftemp(p
^.right
^.location
.reference
);
1136 {*****************************************************************************
1138 *****************************************************************************}
1140 function maybe_push(needed
: byte;p
: ptree
;isint64
: boolean) : boolean;
1143 {hregister : tregister; }
1144 {$ifdef TEMPS_NOT_PUSH}
1146 {$endif TEMPS_NOT_PUSH}
1148 if needed
>usablereg32
then
1150 if (p
^.location
.loc
=LOC_REGISTER
) then
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}
1168 gettempofsizereference(href
,4);
1169 p
^.temp_offset
:=href
.offset
;
1171 {$endif TEMPS_NOT_PUSH}
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
)
1186 del_reference(p
^.location
.reference
);
1187 {$ifndef noAllocEdi}
1188 getexplicitregister32(R_EDI
);
1190 emit_ref_reg(A_LEA
,S_L
,newreference(p
^.location
.reference
),
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
);
1210 {$ifdef TEMPS_NOT_PUSH}
1211 function maybe_savetotemp(needed
: byte;p
: ptree
;isint64
: boolean) : boolean;
1218 if needed
>usablereg32
then
1220 if (p
^.location
.loc
=LOC_REGISTER
) then
1222 if isint64(p
^.resulttype
) then
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
);
1233 gettempofsizereference(href
,4);
1234 p
^.temp_offset
:=href
.offset
;
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
)
1245 del_reference(p
^.location
.reference
);
1246 {$ifndef noAllocEdi}
1247 getexplicitregister32(R_EDI
);
1249 emit_ref_reg(A_LEA
,S_L
,newreference(p
^.location
.reference
),
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
);
1256 p
^.temp_offset
:=href
.offset
;
1264 {$endif TEMPS_NOT_PUSH}
1267 procedure push_int(l
: longint);
1270 not(aktoptprocessor
in [Class386
, ClassP6
]) and
1271 not(cs_littlesize
in aktglobalswitches
)
1274 {$ifndef noAllocEdi}
1275 getexplicitregister32(R_EDI
);
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
);
1284 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,S_L
,l
)));
1287 procedure emit_push_mem(const ref
: treference
);
1290 if ref
.is_immediate
then
1291 push_int(ref
.offset
)
1294 if not(aktoptprocessor
in [Class386
, ClassP6
]) and
1295 not(cs_littlesize
in aktglobalswitches
)
1298 {$ifndef noAllocEdi}
1299 getexplicitregister32(R_EDI
);
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
);
1307 else exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,S_L
,newreference(ref
))));
1312 procedure emitpushreferenceaddr(const ref
: treference
);
1316 { this will fail for references to other segments !!! }
1317 if ref
.is_immediate
then
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
);
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
)))
1340 {$ifndef noAllocEdi}
1341 getexplicitregister32(R_EDI
);
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
);
1353 procedure pushsetelement(p
: ptree
);
1355 copies p a set element on the stack
1358 hr
,hr16
,hr32
: tregister
;
1360 { copy the element on the stack, slightly complicated }
1361 if p
^.treetype
=ordconstn
then
1363 if target_os
.stackalignment
=4 then
1364 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,S_L
,p
^.value
)))
1366 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,S_W
,p
^.value
)));
1370 case p
^.location
.loc
of
1374 hr
:=p
^.location
.register;
1376 R_EAX
,R_EBX
,R_ECX
,R_EDX
,R_EDI
,R_ESI
,R_ESP
:
1378 hr16
:=reg32toreg16(hr
);
1381 R_AX
,R_BX
,R_CX
,R_DX
,R_DI
,R_SI
,R_SP
:
1384 hr32
:=reg16toreg32(hr
);
1386 R_AL
,R_BL
,R_CL
,R_DL
:
1388 hr16
:=reg8toreg16(hr
);
1389 hr32
:=reg8toreg32(hr
);
1392 if target_os
.stackalignment
=4 then
1393 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,hr32
)))
1395 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_W
,hr16
)));
1396 ungetregister32(hr32
);
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 }
1403 emit_push_mem_size(p
^.location
.reference
,1);
1404 del_reference(p
^.location
.reference
);
1411 procedure restore(p
: ptree
;isint64
: boolean);
1413 hregister
: tregister
;
1414 {$ifdef TEMPS_NOT_PUSH}
1416 {$endif TEMPS_NOT_PUSH}
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
1429 p
^.location
.register:=hregister
;
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}
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);}
1453 {$ifdef TEMPS_NOT_PUSH}
1455 {$endif TEMPS_NOT_PUSH}
1458 {$ifdef TEMPS_NOT_PUSH}
1459 procedure restorefromtemp(p
: ptree
;isint64
: boolean);
1461 hregister
: tregister
;
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
1472 p
^.location
.register:=hregister
;
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
;
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);}
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
;
1505 case p
^.location
.loc
of
1509 case p
^.location
.register of
1510 R_EAX
,R_EBX
,R_ECX
,R_EDX
,R_ESI
,
1513 if p
^.resulttype
^.size
=8 then
1515 inc(pushedparasize
,8);
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
)));
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
);
1533 inc(pushedparasize
,4);
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
)));
1541 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,p
^.location
.register)));
1542 ungetregister32(p
^.location
.register);
1545 R_AX
,R_BX
,R_CX
,R_DX
,R_SI
,R_DI
:
1550 hreg
:=reg16toreg32(p
^.location
.register);
1551 inc(pushedparasize
,4);
1556 hreg
:=p
^.location
.register;
1557 inc(pushedparasize
,2);
1561 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1562 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,opsize
,hreg
,r
)));
1565 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,opsize
,hreg
)));
1566 ungetregister32(reg16toreg32(p
^.location
.register));
1568 R_AL
,R_BL
,R_CL
,R_DL
:
1573 hreg
:=reg8toreg32(p
^.location
.register);
1574 inc(pushedparasize
,4);
1579 hreg
:=reg8toreg16(p
^.location
.register);
1580 inc(pushedparasize
,2);
1582 { we must push always 16 bit }
1585 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1586 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,opsize
,hreg
,r
)));
1589 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,opsize
,hreg
)));
1590 ungetregister32(reg8toreg32(p
^.location
.register));
1592 else internalerror(1899);
1597 size
:=align(pfloatdef(p
^.resulttype
)^.size
,alignment
);
1598 inc(pushedparasize
,size
);
1600 emit_const_reg(A_SUB
,S_L
,size
,R_ESP
);
1602 if (cs_debuginfo
in aktmoduleswitches
) and
1603 (exprasmlist
^.first
=exprasmlist
^.last
) then
1604 exprasmlist
^.concat(new(pai_force_line
,init
));
1606 r
:=new_reference(R_ESP
,0);
1607 floatstoreops(pfloatdef(p
^.resulttype
)^.typ
,op
,opsize
);
1608 { this is the easiest case for inlined !! }
1611 r
^.base
:=procinfo
^.framepointer
;
1612 r
^.offset
:=para_offset
-pushedparasize
;
1614 exprasmlist
^.concat(new(paicpu
,op_ref(op
,opsize
,r
)));
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
);
1624 emit_const_reg(A_SUB
,S_L
,size
,R_ESP
);
1626 if (cs_debuginfo
in aktmoduleswitches
) and
1627 (exprasmlist
^.first
=exprasmlist
^.last
) then
1628 exprasmlist
^.concat(new(pai_force_line
,init
));
1630 r
:=new_reference(R_ESP
,0);
1631 floatstoreops(pfloatdef(p
^.resulttype
)^.typ
,op
,opsize
);
1632 { this is the easiest case for inlined !! }
1635 r
^.base
:=procinfo
^.framepointer
;
1636 r
^.offset
:=para_offset
-pushedparasize
;
1638 exprasmlist
^.concat(new(paicpu
,op_ref(op
,opsize
,r
)));
1640 LOC_REFERENCE
,LOC_MEM
:
1642 tempreference
:=p
^.location
.reference
;
1643 del_reference(p
^.location
.reference
);
1644 case p
^.resulttype
^.deftype
of
1648 case p
^.resulttype
^.size
of
1650 inc(pushedparasize
,8);
1653 {$ifndef noAllocEdi}
1654 getexplicitregister32(R_EDI
);
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
);
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
);
1675 inc(tempreference
.offset
,4);
1676 emit_push_mem(tempreference
);
1677 dec(tempreference
.offset
,4);
1678 emit_push_mem(tempreference
);
1682 inc(pushedparasize
,4);
1685 {$ifndef noAllocEdi}
1686 getexplicitregister32(R_EDI
);
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
);
1697 emit_push_mem(tempreference
);
1704 inc(pushedparasize
,4);
1710 inc(pushedparasize
,2);
1714 {$ifndef noAllocEdi}
1715 getexplicitregister32(R_EDI
);
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
);
1726 emit_push_mem_size(tempreference
,p
^.resulttype
^.size
);
1729 internalerror(234231);
1734 case pfloatdef(p
^.resulttype
)^.typ
of
1738 inc(pushedparasize
,4);
1741 {$ifndef noAllocEdi}
1742 getexplicitregister32(R_EDI
);
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
);
1753 emit_push_mem(tempreference
);
1758 inc(pushedparasize
,4);
1759 inc(tempreference
.offset
,4);
1762 {$ifndef noAllocEdi}
1763 getexplicitregister32(R_EDI
);
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
);
1774 emit_push_mem(tempreference
);
1775 inc(pushedparasize
,4);
1776 dec(tempreference
.offset
,4);
1779 {$ifndef noAllocEdi}
1780 getexplicitregister32(R_EDI
);
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
);
1791 emit_push_mem(tempreference
);
1795 inc(pushedparasize
,4);
1797 inc(tempreference
.offset
,8)
1799 inc(tempreference
.offset
,6);
1802 {$ifndef noAllocEdi}
1803 getexplicitregister32(R_EDI
);
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
);
1814 emit_push_mem(tempreference
);
1815 dec(tempreference
.offset
,4);
1816 inc(pushedparasize
,4);
1819 {$ifndef noAllocEdi}
1820 getexplicitregister32(R_EDI
);
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
);
1831 emit_push_mem(tempreference
);
1836 inc(pushedparasize
,4);
1837 dec(tempreference
.offset
,4);
1843 inc(pushedparasize
,2);
1844 dec(tempreference
.offset
,2);
1848 {$ifndef noAllocEdi}
1849 getexplicitregister32(R_EDI
);
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
);
1860 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,opsize
,
1861 newreference(tempreference
))));
1869 inc(pushedparasize
,4);
1872 {$ifndef noAllocEdi}
1873 getexplicitregister32(R_EDI
);
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
);
1884 emit_push_mem(tempreference
);
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
))
1903 (p
^.resulttype
^.size
<=4)
1905 ((p
^.resulttype
^.deftype
=objectdef
) and
1906 pobjectdef(p
^.resulttype
)^.is_class
) then
1908 if (p
^.resulttype
^.size
>2) or
1909 ((alignment
=4) and (p
^.resulttype
^.size
>0)) then
1911 inc(pushedparasize
,4);
1914 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1915 concatcopy(tempreference
,r
^,4,false,false);
1918 emit_push_mem(tempreference
);
1922 if p
^.resulttype
^.size
>0 then
1924 inc(pushedparasize
,2);
1927 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1928 concatcopy(tempreference
,r
^,2,false,false);
1931 exprasmlist
^.concat(new(paicpu
,op_ref(A_PUSH
,S_W
,newreference(tempreference
))));
1935 { call by value open array ? }
1936 else if is_cdecl
then
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);
1946 internalerror(8954);
1949 CGMessage(cg_e_illegal_expression
);
1958 inc(pushedparasize
,4);
1963 inc(pushedparasize
,2);
1968 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1969 emit_const_ref(A_MOV
,opsize
,1,r
);
1972 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,opsize
,1)));
1973 emitjmp(C_None
,hlabel
);
1974 emitlab(falselabel
);
1977 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
1978 emit_const_ref(A_MOV
,opsize
,0,r
);
1981 exprasmlist
^.concat(new(paicpu
,op_const(A_PUSH
,opsize
,0)));
1986 if not(R_EAX
in unused
) then
1988 {$ifndef noAllocEdi}
1989 getexplicitregister32(R_EDI
);
1991 emit_reg_reg(A_MOV
,S_L
,R_EAX
,R_EDI
);
1993 emit_flag2reg(p
^.location
.resflags
,R_AL
);
1994 emit_reg_reg(A_MOVZX
,S_BW
,R_AL
,R_AX
);
1999 inc(pushedparasize
,4);
2005 inc(pushedparasize
,2);
2009 r
:=new_reference(procinfo
^.framepointer
,para_offset
-pushedparasize
);
2010 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,opsize
,hreg
,r
)));
2013 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,opsize
,hreg
)));
2014 if not(R_EAX
in unused
) then
2016 emit_reg_reg(A_MOV
,S_L
,R_EDI
,R_EAX
);
2017 {$ifndef noAllocEdi}
2018 ungetregister32(R_EDI
);
2022 {$ifdef SUPPORT_MMX}
2026 inc(pushedparasize
,8); { was missing !!! (PM) }
2030 if (cs_debuginfo
in aktmoduleswitches
) and
2031 (exprasmlist
^.first
=exprasmlist
^.last
) then
2032 exprasmlist
^.concat(new(pai_force_line
,init
));
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
)));
2042 r
:=new_reference(R_ESP
,0);
2043 exprasmlist
^.concat(new(paicpu
,op_reg_ref(
2044 A_MOVQ
,S_NO
,p
^.location
.register,r
)));
2047 {$endif SUPPORT_MMX}
2053 {*****************************************************************************
2054 Emit Float Functions
2055 *****************************************************************************}
2057 procedure floatloadops(t
: tfloattype
;var op
: tasmop
;var s
: topsize
);
2077 else internalerror(17);
2082 procedure floatload(t
: tfloattype
;const ref
: treference
);
2087 floatloadops(t
,op
,s
);
2088 exprasmlist
^.concat(new(paicpu
,op_ref(op
,s
,
2089 newreference(ref
))));
2094 procedure floatstoreops(t
: tfloattype
;var op
: tasmop
;var s
: topsize
);
2119 procedure floatstore(t
: tfloattype
;const ref
: treference
);
2124 floatstoreops(t
,op
,s
);
2125 exprasmlist
^.concat(new(paicpu
,op_ref(op
,s
,
2126 newreference(ref
))));
2131 {*****************************************************************************
2133 *****************************************************************************}
2135 procedure maketojumpbool(p
: ptree
);
2137 produces jumps to true respectively false labels using boolean expressions
2141 storepos
: tfileposinfo
;
2145 storepos
:=aktfilepos
;
2146 aktfilepos
:=p
^.fileinfo
;
2147 if is_boolean(p
^.resulttype
) then
2149 if is_constboolnode(p
) then
2152 emitjmp(C_None
,truelabel
)
2154 emitjmp(C_None
,falselabel
);
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
);
2167 LOC_MEM
,LOC_REFERENCE
: begin
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
);
2175 emitjmp(flag_2_cond
[p
^.location
.resflags
],truelabel
);
2176 emitjmp(C_None
,falselabel
);
2182 CGMessage(type_e_mismatch
);
2183 aktfilepos
:=storepos
;
2187 { produces if necessary overflowcode }
2188 procedure emitoverflowcheck(p
:ptree
);
2192 if not(cs_check_overflow
in aktlocalswitches
) then
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
2202 emitcall('FPC_OVERFLOW');
2206 { produces range check code, while one of the operands is a 64 bit
2208 procedure emitrangecheck64(p
: ptree
;todef
: pdef
);
2213 endlabel
: pasmlabel
;
2220 oldregisterdef
: boolean;
2221 from_signed
,to_signed
: boolean;
2224 fromdef
:=p
^.resulttype
;
2225 from_signed
:= is_signed(fromdef
);
2226 to_signed
:= is_signed(todef
);
2228 if not is_64bitint(todef
) then
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
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
);
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
2253 emit_const_reg(A_CMP
,S_L
,$ffffffff,hreg
);
2254 emitjmp(C_E
,neglabel
);
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 }
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
);
2269 { restore original resulttype }
2270 p
^.resulttype
:= todef
;
2272 if from_signed
and to_signed
then
2275 emitjmp(C_NO
,endlabel
);
2276 { if the high dword = $ffffffff, then the low dword (when }
2277 { considered as a longint) must be < 0 }
2279 if p
^.location
.loc
in [LOC_REGISTER
,LOC_CREGISTER
] then
2280 hreg
:= p
^.location
.registerlow
2283 hreg
:= getexplicitregister32(R_EDI
);
2284 emit_ref_reg(A_MOV
,S_L
,
2285 newreference(p
^.location
.reference
),hreg
);
2287 { get a new neglabel (JM) }
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) }
2299 new(hdef
,init(s32bit
,$80000000,-1));
2300 p
^.resulttype
:= hdef
;
2301 emitrangecheck(p
,todef
);
2305 registerdef
:= oldregisterdef
;
2306 p
^.resulttype
:= fromdef
;
2307 { restore p's resulttype }
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) }
2318 (porddef(fromdef
)^.typ
= u64bit
)) then
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
2325 hreg
:= p
^.location
.register
2328 hreg
:= getexplicitregister32(R_EDI
);
2329 case p
^.resulttype
^.size
of
2334 if opsize
in [S_BL
,S_WL
] then
2337 else opcode
:= A_MOVZX
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
);
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');
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)
2365 poslabel
: pasmlabel
;
2373 lfrom
,hfrom
: longint;
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
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
2387 emitrangecheck64(p
,todef
);
2390 {we also need lto and hto when checking if we need to use doublebound!
2392 getrange(todef
,lto
,hto
);
2393 if todef
<>fromdef
then
2395 getrange(p
^.resulttype
,lfrom
,hfrom
);
2396 { first check for not being u32bit, then if the to is bigger than
2398 if (lto
<hto
) and (lfrom
<hfrom
) and
2399 (lto
<=lfrom
) and (hto
>=hfrom
) then
2402 { generate the rangecheck code for the def where we are going to
2405 case todef
^.deftype
of
2408 porddef(todef
)^.genrangecheck
;
2409 rstr
:=porddef(todef
)^.getrangecheckstring
;
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
));
2417 penumdef(todef
)^.genrangecheck
;
2418 rstr
:=penumdef(todef
)^.getrangecheckstring
;
2422 parraydef(todef
)^.genrangecheck
;
2423 rstr
:=parraydef(todef
)^.getrangecheckstring
;
2424 doublebound
:=(lto
>hto
);
2427 { get op and opsize }
2428 opsize
:=def2def_opsize(fromdef
,u32bitdef
);
2429 if opsize
in [S_B
,S_W
,S_L
] then
2432 if is_signed(fromdef
) then
2436 is_reg
:=(p
^.location
.loc
in [LOC_REGISTER
,LOC_CREGISTER
]);
2438 hreg
:=p
^.location
.register;
2439 if not target_os
.use_bound_instruction
then
2441 { FPC_BOUNDCHECK needs to be called with
2443 %edi - pointer to the ranges }
2446 (p
^.location
.register<>R_ECX
) then
2448 if not(R_ECX
in unused
) then
2450 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,R_ECX
)));
2453 else exprasmlist
^.concat(new(pairegalloc
,alloc(R_ECX
)));
2455 emit_reg_reg(op
,opsize
,p
^.location
.register,R_ECX
)
2457 emit_ref_reg(op
,opsize
,newreference(p
^.location
.reference
),R_ECX
);
2463 emit_reg_reg(A_OR
,S_L
,R_ECX
,R_ECX
);
2464 emitjmp(C_L
,neglabel
);
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 }
2474 emitjmp(C_None
,poslabel
);
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')
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
);
2496 exprasmlist
^.concat(new(paicpu
,op_reg(A_POP
,S_L
,R_ECX
)))
2497 else exprasmlist
^.concat(new(pairegalloc
,dealloc(R_ECX
)));
2501 reset_reference(href
);
2502 href
.symbol
:=newasmsymbol(rstr
);
2503 { load the value in a register }
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
2511 getexplicitregister32(R_EDI
);
2512 emit_reg_reg(op
,opsize
,p
^.location
.register,R_EDI
);
2518 getexplicitregister32(R_EDI
);
2519 emit_ref_reg(op
,opsize
,newreference(p
^.location
.reference
),R_EDI
);
2526 emit_reg_reg(A_TEST
,S_L
,hreg
,hreg
);
2527 emitjmp(C_L
,neglabel
);
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 }
2535 emitjmp(C_None
,poslabel
);
2537 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_BOUND
,S_L
,hreg
,newreference(href
))));
2540 if hreg
= R_EDI
then
2541 ungetregister32(R_EDI
);
2546 procedure concatcopy(source
,dest
: treference
;size
: longint;delsource
,loadref
: boolean);
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;
2556 reg8
,reg32
: tregister
;
2559 procedure maybepushecx
;
2561 if not(R_ECX
in unused
) then
2563 exprasmlist
^.concat(new(paicpu
,op_reg(A_PUSH
,S_L
,R_ECX
)));
2566 else getexplicitregister32(R_ECX
);
2570 {$IfNDef regallocfix}
2572 del_reference(source
);
2573 {$EndIf regallocfix}
2574 if (not loadref
) and
2576 (not(cs_littlesize
in aktglobalswitches
) and (size
<=12))) then
2578 helpsize
:=size
shr 2;
2579 {$ifndef noAllocEdi}
2580 getexplicitregister32(R_EDI
);
2582 for i
:=1 to helpsize
do
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);
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);
2606 {$ifndef noAllocEdi}
2607 ungetregister32(R_EDI
);
2611 { and now look for an 8 bit register }
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
))
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
2627 else if (dest
.base
<>R_EBX
) and (dest
.index
<>R_EBX
) then
2632 else if (dest
.base
<>R_ECX
) and (dest
.index
<>R_ECX
) then
2639 { was earlier XCHG, of course nonsense }
2641 {$ifndef noAllocEdi}
2642 getexplicitregister32(R_EDI
);
2644 emit_reg_reg(A_MOV
,S_L
,reg32
,R_EDI
);
2646 emit_ref_reg(A_MOV
,S_B
,newreference(source
),reg8
);
2647 {$ifdef regallocfix}
2649 del_reference(source
);
2650 {$endif regallocfix}
2651 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_B
,reg8
,newreference(dest
))));
2654 emit_reg_reg(A_MOV
,S_L
,R_EDI
,reg32
);
2655 {$ifndef noAllocEdi}
2656 ungetregister32(R_EDI
);
2660 ungetregister(reg8
);
2665 {$ifndef noAllocEdi}
2666 getexplicitregister32(R_EDI
);
2668 emit_ref_reg(A_LEA
,S_L
,newreference(dest
),R_EDI
);
2669 {$ifdef regallocfix}
2671 del_reference(dest
);
2672 {$endif regallocfix}
2673 {$ifndef noAllocEdi}
2674 exprasmlist
^.concat(new(pairegalloc
,alloc(R_ESI
)));
2677 emit_ref_reg(A_MOV
,S_L
,newreference(source
),R_ESI
)
2680 emit_ref_reg(A_LEA
,S_L
,newreference(source
),R_ESI
);
2681 {$ifdef regallocfix}
2683 del_reference(source
);
2684 {$endif regallocfix}
2687 exprasmlist
^.concat(new(paicpu
,op_none(A_CLD
,S_NO
)));
2689 if cs_littlesize
in aktglobalswitches
then
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
)));
2698 helpsize
:=size
shr 2;
2703 emit_const_reg(A_MOV
,S_L
,helpsize
,R_ECX
);
2704 exprasmlist
^.concat(new(paicpu
,op_none(A_REP
,S_NO
)));
2707 exprasmlist
^.concat(new(paicpu
,op_none(A_MOVSD
,S_NO
)));
2711 exprasmlist
^.concat(new(paicpu
,op_none(A_MOVSW
,S_NO
)));
2714 exprasmlist
^.concat(new(paicpu
,op_none(A_MOVSB
,S_NO
)));
2716 {$ifndef noAllocEdi}
2717 ungetregister32(R_EDI
);
2718 exprasmlist
^.concat(new(pairegalloc
,dealloc(R_ESI
)));
2721 exprasmlist
^.concat(new(paicpu
,op_reg(A_POP
,S_L
,R_ECX
)))
2723 ungetregister32(R_ECX
);
2725 { loading SELF-reference again }
2729 ungetiftemp(source
);
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.}
2743 case location
.loc
of
2744 LOC_REGISTER
,LOC_CREGISTER
:
2748 tai
:=new(paicpu
,op_reg_reg(A_MOVZX
,S_BL
,location
.register,destreg
));
2750 tai
:=new(paicpu
,op_reg_reg(A_MOVSX
,S_BL
,location
.register,destreg
));
2752 tai
:=new(paicpu
,op_reg_reg(A_MOVZX
,S_WL
,location
.register,destreg
));
2754 tai
:=new(paicpu
,op_reg_reg(A_MOVSX
,S_WL
,location
.register,destreg
));
2756 if location
.register <> destreg
then
2757 tai
:=new(paicpu
,op_reg_reg(A_MOV
,S_L
,location
.register,destreg
));
2760 ungetregister(location
.register);
2765 if location
.reference
.is_immediate
then
2766 tai
:=new(paicpu
,op_const_reg(A_MOV
,S_L
,location
.reference
.offset
,destreg
))
2769 r
:=newreference(location
.reference
);
2772 tai
:=new(paicpu
,op_ref_reg(A_MOVZX
,S_BL
,r
,destreg
));
2774 tai
:=new(paicpu
,op_ref_reg(A_MOVSX
,S_BL
,r
,destreg
));
2776 tai
:=new(paicpu
,op_ref_reg(A_MOVZX
,S_WL
,r
,destreg
));
2778 tai
:=new(paicpu
,op_ref_reg(A_MOVSX
,S_WL
,r
,destreg
));
2780 tai
:=new(paicpu
,op_ref_reg(A_MOV
,S_L
,r
,destreg
));
2782 tai
:=new(paicpu
,op_ref_reg(A_MOV
,S_L
,r
,destreg
));
2786 del_reference(location
.reference
);
2791 if assigned(tai
) then
2792 exprasmlist
^.concat(tai
);
2795 { if necessary ESI is reloaded after a call}
2796 procedure maybe_loadesi
;
2804 if assigned(procinfo
^._class
) then
2806 {$ifndef noAllocEdi}
2807 exprasmlist
^.concat(new(pairegalloc
,alloc(R_ESI
)));
2809 if lexlevel
>normal_function_level
then
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
2820 reset_reference(hp
^);
2821 hp
^.offset
:=p
^.framepointer_offset
;
2823 emit_ref_reg(A_MOV
,S_L
,hp
,R_ESI
);
2827 reset_reference(hp
^);
2828 hp
^.offset
:=p
^.selfpointer_offset
;
2830 emit_ref_reg(A_MOV
,S_L
,hp
,R_ESI
);
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
);
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
);
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
2857 internalerror(234234);
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
2870 p
^.swaped
:=not p
^.swaped
;
2873 p^.swaped:=false; do not modify }
2877 {*****************************************************************************
2878 Entry/Exit Code Functions
2879 *****************************************************************************}
2881 procedure genprofilecode
;
2885 if (po_assembler
in aktprocsym
^.definition
^.procoptions
) then
2887 case target_info
.target
of
2888 target_i386_freebsd
,
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
)));
2904 emitinsertcall('MCOUNT');
2910 procedure generate_interrupt_stackframe_entry
;
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
)));
2928 procedure generate_interrupt_stackframe_exit
;
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
)));
2950 { generates the code for threadvar initialisation }
2951 procedure initialize_threadvar(p
: pnamedindexobject
);{$ifndef FPC}far;{$endif}
2957 if (psym(p
)^.typ
=varsym
) and
2958 (vo_is_thread_var
in pvarsym(p
)^.varoptions
) then
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');
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);
2977 if is_ansistring(t
) or
2978 is_widestring(t
) then
2980 emit_const_ref(A_MOV
,S_L
,0,
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
))))
2992 emitpushreferenceaddr(ref
);
2993 emitcall('FPC_INITIALIZE');
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);
3006 if is_ansistring(t
) or
3007 is_widestring(t
) then
3009 decrstringref(t
,ref
);
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
))))
3020 emitpushreferenceaddr(ref
);
3021 emitcall('FPC_FINALIZE');
3026 { generates the code for initialisation of local data }
3027 procedure initialize_data(p
: pnamedindexobject
);{$ifndef FPC}far;{$endif}
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
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
3044 hr
.base
:=procinfo
^.framepointer
;
3045 hr
.offset
:=-pvarsym(p
)^.address
+pvarsym(p
)^.owner
^.address_fixup
;
3049 hr
.symbol
:=newasmsymbol(pvarsym(p
)^.mangledname
);
3051 initialize(pvarsym(p
)^.vartype
.def
,hr
,false);
3055 { generates the code for incrementing the reference count of parameters }
3056 procedure incr_data(p
: pnamedindexobject
);{$ifndef FPC}far;{$endif}
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
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');
3086 { generates the code for finalisation of local data }
3087 procedure finalize_data(p
: pnamedindexobject
);{$ifndef FPC}far;{$endif}
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
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
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
:
3112 hr
.base
:=procinfo
^.framepointer
;
3113 hr
.offset
:=-pvarsym(p
)^.address
+pvarsym(p
)^.owner
^.address_fixup
;
3115 parasymtable
,inlineparasymtable
:
3117 hr
.base
:=procinfo
^.framepointer
;
3118 hr
.offset
:=pvarsym(p
)^.address
+procinfo
^.para_offset
;
3121 hr
.symbol
:=newasmsymbol(pvarsym(p
)^.mangledname
);
3123 finalize(pvarsym(p
)^.vartype
.def
,hr
,false);
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
;
3133 power
,len
: longint;
3135 again
,ok
: pasmlabel
;
3137 if (psym(p
)^.typ
=varsym
) and
3138 (pvarsym(p
)^.varspez
=vs_value
) and
3139 (push_addr_param(pvarsym(p
)^.vartype
.def
)) then
3141 if is_open_array(pvarsym(p
)^.vartype
.def
) or
3142 is_array_of_const(pvarsym(p
)^.vartype
.def
) then
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
);
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
3160 if ispowerof2(parraydef(pvarsym(p
)^.vartype
.def
)^.elesize
, power
) then
3161 exprasmlist
^.concat(new(paicpu
,
3162 op_const_reg(A_SHL
,S_L
,
3165 exprasmlist
^.concat(new(paicpu
,
3166 op_const_reg(A_IMUL
,S_L
,
3167 parraydef(pvarsym(p
)^.vartype
.def
)^.elesize
,R_EDI
)));
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
3177 exprasmlist
^.concat(new(paicpu
,
3178 op_const_reg(A_CMP
,S_L
,winstackpagesize
,R_EDI
)));
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
);
3189 exprasmlist
^.concat(new(paicpu
,
3190 op_reg_reg(A_SUB
,S_L
,R_EDI
,R_ESP
)));
3191 {$ifndef noAllocEdi}
3192 ungetregister32(R_EDI
);
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
);
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
3210 if ispowerof2(parraydef(pvarsym(p
)^.vartype
.def
)^.elesize
, power
) then
3211 exprasmlist
^.concat(new(paicpu
,
3212 op_const_reg(A_SHL
,S_L
,
3215 exprasmlist
^.concat(new(paicpu
,
3216 op_const_reg(A_IMUL
,S_L
,
3217 parraydef(pvarsym(p
)^.vartype
.def
)^.elesize
,R_EDI
)));
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
)));
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
)));
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
)));
3251 exprasmlist
^.concat(new(paicpu
,
3252 op_reg(A_INC
,S_L
,R_ECX
)));
3255 len
:=parraydef(pvarsym(p
)^.vartype
.def
)^.elesize
;
3257 if (len
and 3)=0 then
3263 if (len
and 1)=0 then
3269 if ispowerof2(len
, power
) then
3270 exprasmlist
^.concat(new(paicpu
,
3271 op_const_reg(A_SHL
,S_L
,
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
)));
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
)));
3283 {$ifndef noAllocEdi}
3284 ungetregister32(R_EDI
);
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 }
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
)));
3300 if is_shortstring(pvarsym(p
)^.vartype
.def
) then
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);
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);
3323 procedure inittempansistrings
;
3331 while assigned(hp
) do
3333 if hp
^.temptype
in [tt_ansistring
,tt_freeansistring
] then
3335 procinfo
^.flags
:=procinfo
^.flags
or pi_needs_implicit_finally
;
3337 reset_reference(r
^);
3338 r
^.base
:=procinfo
^.framepointer
;
3340 emit_const_ref(A_MOV
,S_L
,0,r
);
3346 procedure finalizetempansistrings
;
3353 while assigned(hp
) do
3355 if hp
^.temptype
in [tt_ansistring
,tt_freeansistring
] then
3357 procinfo
^.flags
:=procinfo
^.flags
or pi_needs_implicit_finally
;
3358 reset_reference(hr
);
3359 hr
.base
:=procinfo
^.framepointer
;
3361 emitpushreferenceaddr(hr
);
3362 emitcall('FPC_ANSISTR_DECR_REF');
3371 procedure largest_size(p
: pnamedindexobject
);{$ifndef FPC}far;{$endif}
3374 if (psym(p
)^.typ
=varsym
) and
3375 (pvarsym(p
)^.getvaluesize
>ls
) then
3376 ls
:=pvarsym(p
)^.getvaluesize
;
3379 procedure alignstack(alist
: paasmoutput
);
3383 if (cs_optimize
in aktglobalswitches
) and
3384 (aktoptprocessor
in [classp5
,classp6
]) then
3387 aktprocsym
^.definition
^.localst
^.foreach({$ifndef TP}@{$endif}largest_size
);
3389 alist
^.insert(new(paicpu
,op_const_reg(A_AND
,S_L
,-8,R_ESP
)));
3394 procedure genentrycode(alist
: paasmoutput
;const proc_names
:Tstringcontainer
;make_global
:boolean;
3396 var parasize
:longint;var nostackframe
:boolean;
3399 Generates the entry code for a procedure
3404 stab_function_name
: Pai_stab_function_name
;
3410 oldexprasmlist
: paasmoutput
;
3415 oldexprasmlist
:=exprasmlist
;
3417 if (not inlined
) and (aktprocsym
^.definition
^.proctypeoption
=potype_proginit
) then
3419 emitinsertcall('FPC_INITIALIZEUNITS');
3420 if target_info
.target
=target_I386_WIN32
then
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
,
3430 exprasmlist
^.insert(new(paicpu
,op_const_ref(A_MOV
,S_B
,
3434 oldlist
:=exprasmlist
;
3435 exprasmlist
:=new(paasmoutput
,init
);
3437 while assigned(p
) do
3439 p
^.foreach({$ifndef TP}@{$endif}initialize_threadvar
);
3442 oldlist
^.insertlist(exprasmlist
);
3443 dispose(exprasmlist
,done
);
3444 exprasmlist
:=oldlist
;
3448 if (not inlined
) and (cs_debuginfo
in aktmoduleswitches
) then
3449 exprasmlist
^.insert(new(pai_force_line
,init
));
3452 { a constructor needs a help procedure }
3453 if (aktprocsym
^.definition
^.proctypeoption
=potype_constructor
) then
3455 if procinfo
^._class
^.is_class
then
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');
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
);
3468 exprasmlist
^.insert(new(paicpu
,op_const_reg(A_MOV
,S_L
,procinfo
^._class
^.vmt_offset
,R_EDI
)));
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
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
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
)));
3494 { should we save edi,esi,ebx like C ? }
3495 if (po_savestdregs
in aktprocsym
^.definition
^.procoptions
) then
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
)));
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
3507 exprasmlist
^.insert(new(paicpu
,op_none(A_PUSHA
,S_L
)));
3510 { omit stack frame ? }
3512 if procinfo
^.framepointer
=stack_pointer
then
3514 CGMessage(cg_d_stackframe_omited
);
3516 if (aktprocsym
^.definition
^.proctypeoption
in [potype_unitinit
,potype_proginit
,potype_unitfinalize
]) then
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
)));
3527 if (aktprocsym
^.definition
^.proctypeoption
in [potype_unitinit
,potype_proginit
,potype_unitfinalize
]) then
3530 parasize
:=aktprocsym
^.definition
^.parast
^.datasize
+procinfo
^.para_offset
-8;
3531 nostackframe
:=false;
3532 if stackframe
<>0 then
3535 if (cs_littlesize
in aktglobalswitches
) and (stackframe
<=65535) then
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
3541 emitinsertcall('FPC_STACKCHECK');
3542 exprasmlist
^.insert(new(paicpu
,op_const(A_PUSH
,S_L
,stackframe
)));
3544 if cs_profile
in aktmoduleswitches
then
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))); }
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)))
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
3564 if stackframe
div winstackpagesize
<=5 then
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
3569 hr
:=new_reference(R_ESP
,stackframe
-i
*winstackpagesize
);
3570 exprasmlist
^.concat(new(paicpu
,
3571 op_const_ref(A_MOV
,S_L
,0,hr
)));
3573 exprasmlist
^.concat(new(paicpu
,
3574 op_reg(A_PUSH
,S_L
,R_EAX
)));
3579 {$ifndef noAllocEdi}
3580 getexplicitregister32(R_EDI
);
3582 exprasmlist
^.concat(new(paicpu
,
3583 op_const_reg(A_MOV
,S_L
,stackframe
div winstackpagesize
,R_EDI
)));
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
);
3595 exprasmlist
^.concat(new(paicpu
,
3596 op_const_reg(A_SUB
,S_L
,stackframe
mod winstackpagesize
,R_ESP
)));
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
3605 emitinsertcall('FPC_STACKCHECK');
3606 exprasmlist
^.insert(new(paicpu
,op_const(A_PUSH
,S_L
,stackframe
)));
3608 if cs_profile
in aktmoduleswitches
then
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
)));
3613 end { endif stackframe <> 0 }
3616 if cs_profile
in aktmoduleswitches
then
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
)));
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
3632 procinfo
^.flags
:=procinfo
^.flags
or pi_needs_implicit_finally
;
3634 r
.offset
:=procinfo
^.return_offset
;
3635 r
.base
:=procinfo
^.framepointer
;
3636 initialize(procinfo
^.returntype
.def
,r
,ret_in_param(procinfo
^.returntype
.def
));
3639 { initialisize local data like ansistrings }
3640 case aktprocsym
^.definition
^.proctypeoption
of
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
);
3648 { units have seperate code for initilization and finalization }
3649 potype_unitfinalize
: ;
3651 aktprocsym
^.definition
^.localst
^.foreach({$ifndef TP}@{$endif}initialize_data
);
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 ? }
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
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 }
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
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
)));
3705 exprasmlist
^.insert(new(pai_symbol
,initname_global(hs
,0)))
3707 exprasmlist
^.insert(new(pai_symbol
,initname(hs
,0)));
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
))));
3718 if make_global
or ((procinfo
^.flags
and pi_is_global
) <> 0) then
3719 aktprocsym
^.is_global
:= True;
3722 if (cs_debuginfo
in aktmoduleswitches
) then
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;
3731 { Align, gprof uses 16 byte granularity }
3732 if (cs_profile
in aktmoduleswitches
) then
3733 exprasmlist
^.insert(new(pai_align
,init_op(16,$90)))
3735 if not(cs_littlesize
in aktglobalswitches
) then
3736 exprasmlist
^.insert(new(pai_align
,init(16)));
3738 exprasmlist
:=oldexprasmlist
;
3742 procedure handle_return_value(inlined
: boolean;var uses_eax
,uses_edx
: boolean);
3750 if procinfo
^.returntype
.def
<>pdef(voiddef
) then
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
3763 case procinfo
^.returntype
.def
^.size
of
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
);
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
);
3783 if ret_in_acc(procinfo
^.returntype
.def
) then
3786 emit_ref_reg(A_MOV
,S_L
,hr
,R_EAX
);
3789 if (procinfo
^.returntype
.def
^.deftype
=floatdef
) then
3791 floatloadops(pfloatdef(procinfo
^.returntype
.def
)^.typ
,op
,s
);
3792 exprasmlist
^.concat(new(paicpu
,op_ref(op
,s
,hr
)))
3800 procedure genexitcode(alist
: paasmoutput
;parasize
:longint;nostackframe
,inlined
:boolean);
3804 mangled_length
: longint;
3808 nofinal
,okexitlabel
,noreraiselabel
,nodestroycall
: pasmlabel
;
3810 uses_eax
,uses_edx
,uses_esi
: boolean;
3811 oldexprasmlist
: paasmoutput
;
3816 oldexprasmlist
:=exprasmlist
;
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
3826 if procinfo
^._class
^.is_class
then
3828 emitinsertcall('FPC_DISPOSE_CLASS');
3832 emitinsertcall('FPC_HELP_DESTRUCTOR');
3833 {$ifndef noAllocEdi}
3834 getexplicitregister32(R_EDI
);
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
3841 exprasmlist
^.insert(new(pai_label
,init(nofinal
)));
3842 emitinsertcall('FPC_FINALIZE');
3843 {$ifndef noAllocEdi}
3844 ungetregister32(R_EDI
);
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
);
3854 exprasmlist
^.insert(new(paicpu
,op_const_ref(A_CMP
,S_L
,0,newreference(hr
))));
3859 { finalize temporary data }
3860 finalizetempansistrings
;
3862 { finalize local data like ansistrings}
3863 case aktprocsym
^.definition
^.proctypeoption
of
3864 potype_unitfinalize
:
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
);
3871 { units have seperate code for initialization and finalization }
3874 aktprocsym
^.definition
^.localst
^.foreach({$ifndef TP}@{$endif}finalize_data
);
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 ? }
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
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
3899 if assigned(procinfo
^._class
) then
3901 pd
:=procinfo
^._class
^.searchdestructor
;
3902 if assigned(pd
) then
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
3910 emit_const(A_PUSH
,S_L
,1);
3911 emit_reg(A_PUSH
,S_L
,R_ESI
);
3915 emit_reg(A_PUSH
,S_L
,R_ESI
);
3916 emit_sym(A_PUSH
,S_L
,newasmsymbol(procinfo
^._class
^.vmt_mangledname
));
3918 if (po_virtualmethod
in pd
^.procoptions
) then
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
)));
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
);
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
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
));
3947 emitcall('FPC_RERAISE');
3948 emitlab(noreraiselabel
);
3951 { call __EXIT for main program }
3952 if (not DLLsource
) and (not inlined
) and (aktprocsym
^.definition
^.proctypeoption
=potype_proginit
) then
3954 emitcall('FPC_DO_EXIT');
3957 { handle return value }
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
)
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
);
3972 if procinfo
^._class
^.is_class
then
3974 emit_ref_reg(A_MOV
,S_L
,new_reference(procinfo
^.framepointer
,8),R_ESI
);
3975 emitcall('FPC_HELP_FAIL_CLASS');
3979 emit_ref_reg(A_MOV
,S_L
,new_reference(procinfo
^.framepointer
,12),R_ESI
);
3980 {$ifndef noAllocEdi}
3981 getexplicitregister32(R_EDI
);
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
);
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
);
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
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));
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
4026 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_L
,R_ESI
,new_reference(R_ESP
,4))));
4028 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_L
,R_EDX
,new_reference(R_ESP
,20))));
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
)))
4033 if not(nostackframe
) then
4036 exprasmlist
^.concat(new(paicpu
,op_none(A_LEAVE
,S_NO
)));
4040 if (gettempsize
<>0) and not inlined
then
4041 exprasmlist
^.insert(new(paicpu
,
4042 op_const_reg(A_ADD
,S_L
,gettempsize
,R_ESP
)));
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 }
4053 if (po_interrupt
in aktprocsym
^.definition
^.procoptions
) then
4056 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_L
,R_ESI
,new_reference(R_ESP
,16))));
4058 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_L
,R_EDX
,new_reference(R_ESP
,12))));
4060 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,S_L
,R_EAX
,new_reference(R_ESP
,0))));
4061 generate_interrupt_stackframe_exit
;
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
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)))
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
)))
4080 exprasmlist
^.concat(new(paicpu
,op_const(A_RET
,S_NO
,parasize
)));
4084 exprasmlist
^.concat(new(pai_symbol_end
,initname(aktprocsym
^.definition
^.mangledname
)));
4087 if (cs_debuginfo
in aktmoduleswitches
) and not inlined
then
4089 aktprocsym
^.concatstabto(exprasmlist
);
4090 if assigned(procinfo
^._class
) then
4091 if (not assigned(procinfo
^.parent
) or
4092 not assigned(procinfo
^.parent
^._class
)) then
4094 if (po_classmethod
in aktprocsym
^.definition
^.procoptions
) or
4095 (po_staticmethod
in aktprocsym
^.definition
^.procoptions
) then
4097 exprasmlist
^.concat(new(pai_stabs
,init(strpnew(
4098 '"pvmt:p'+pvmtdef
^.numberstring
+'",'+
4099 tostr(N_PSYM
)+',0,0,'+tostr(procinfo
^.selfpointer_offset
)))));
4103 if not procinfo
^._class
^.is_class
then
4107 exprasmlist
^.concat(new(pai_stabs
,init(strpnew(
4108 '"$t:'+st
+procinfo
^._class
^.numberstring
+'",'+
4109 tostr(N_PSYM
)+',0,0,'+tostr(procinfo
^.selfpointer_offset
)))));
4114 if not procinfo
^._class
^.is_class
then
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
])))));
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
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
)))))
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
)))))
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
)))));
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
4155 strpcopy(strend(p
),'-');
4156 strpcopy(strend(p
),aktprocsym
^.definition
^.mangledname
);
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
4166 strpcopy(strend(p
),'-');
4167 strpcopy(strend(p
),aktprocsym
^.definition
^.mangledname
);
4169 exprasmlist
^.concatlist(withdebuglist
);
4170 exprasmlist
^.concat(new(pai_stabn
,init(
4172 { strpnew('224,0,0,'
4173 +aktprocsym^.definition^.mangledname+'_end'))));}
4174 freemem(p
,2*mangled_length
+50);
4177 exprasmlist
:=oldexprasmlist
;
4180 procedure genimplicitunitfinal(alist
: paasmoutput
);
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)));
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
^))));
4194 exprasmlist
^.concat(new(paicpu
,op_none(A_RET
,S_NO
)));
4195 alist
^.concatlist(exprasmlist
);
4198 procedure genimplicitunitinit(alist
: paasmoutput
);
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)));
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
^))));
4212 exprasmlist
^.concat(new(paicpu
,op_none(A_RET
,S_NO
)));
4213 alist
^.concatlist(exprasmlist
);
4216 {$ifdef test_dest_loc}
4217 procedure mov_reg_to_dest(p
: ptree
; s
: topsize
; reg
: tregister
);
4220 if (dest_loc
.loc
=LOC_CREGISTER
) or (dest_loc
.loc
=LOC_REGISTER
) then
4222 emit_reg_reg(A_MOV
,s
,reg
,dest_loc
.register);
4223 set_location(p
^.location
,dest_loc
);
4227 if (dest_loc
.loc
=LOC_REFERENCE
) or (dest_loc
.loc
=LOC_MEM
) then
4229 exprasmlist
^.concat(new(paicpu
,op_reg_ref(A_MOV
,s
,reg
,newreference(dest_loc
.reference
))));
4230 set_location(p
^.location
,dest_loc
);
4234 internalerror(20080);
4237 {$endif test_dest_loc}
4242 Revision 1.1 2002/02/19 08:21:56 sasu
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
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
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
4315 Revision 1.1 2000/07/13 06:29:47 michael
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
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
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
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
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
4404 Revision 1.84 2000/03/01 00:03:12 pierre
4405 * fixes for locals in inlined procedures
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
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
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
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
4454 Revision 1.71 2000/01/22 16:02:37 jonas
4455 * fixed more regalloc bugs (for set adding and unsigned
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
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
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