3 Copyright (c) 1998-2000 by Florian Klaempfl
5 Generate m68k assembler for type converting nodes
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 ****************************************************************************
32 procedure secondtypeconv(var p
: ptree
);
33 procedure secondas(var p
: ptree
);
34 procedure secondis(var p
: ptree
);
40 globtype
,systems
,symconst
,
41 cobjects
,verbose
,globals
,
43 hcodegen
,temp_gen
,pass_2
,
44 cpubase
,cga68k
,tgen68k
;
46 {*****************************************************************************
48 *****************************************************************************}
50 procedure maybe_rangechecking(p
: ptree
;p2
,p1
: pdef
);
54 hregister
: tregister
;
55 neglabel
,poslabel
: pasmlabel
;
58 { convert from p2 to p1 }
59 { range check from enums is not made yet !!}
60 { and its probably not easy }
61 if (p1
^.deftype
<>orddef
) or (p2
^.deftype
<>orddef
) then
63 { range checking is different for u32bit }
64 { lets try to generate it allways }
65 if (cs_check_range
in aktlocalswitches
) and
66 { with $R+ explicit type conversations in TP aren't range checked! }
67 (not(p
^.explizit
) {or not(cs_tp_compatible in aktmoduleswitches)}) and
68 ((porddef(p1
)^.low
>porddef(p2
)^.low
) or
69 (porddef(p1
)^.high
<porddef(p2
)^.high
) or
70 (porddef(p1
)^.typ
=u32bit
) or
71 (porddef(p2
)^.typ
=u32bit
)) then
73 porddef(p1
)^.genrangecheck
;
74 if porddef(p2
)^.typ
=u8bit
then
76 if (p
^.location
.loc
=LOC_REGISTER
) or
77 (p
^.location
.loc
=LOC_CREGISTER
) then
79 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_B
,p
^.location
.register,R_D6
)));
80 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
,$FF,R_D6
)));
84 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_B
,newreference(p
^.location
.reference
),R_D6
)));
85 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
,$FF,R_D6
)));
89 else if porddef(p2
)^.typ
=s8bit
then
91 if (p
^.location
.loc
=LOC_REGISTER
) or
92 (p
^.location
.loc
=LOC_CREGISTER
) then
94 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_B
,p
^.location
.register,R_D6
)));
96 if aktoptprocessor
= MC68020
then
97 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXTB
,S_L
,R_D6
)))
100 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_W
,R_D6
)));
101 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_L
,R_D6
)));
106 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_B
,newreference(p
^.location
.reference
),R_D6
)));
108 if aktoptprocessor
= MC68020
then
109 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXTB
,S_L
,R_D6
)))
112 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_W
,R_D6
)));
113 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_L
,R_D6
)));
115 end; { end outermost else }
118 { rangechecking for u32bit ?? !!!!!!}
120 else if (porddef(p2
)^.typ
=s32bit
) or (porddef(p2
)^.typ
=u32bit
) then
122 if (p
^.location
.loc
=LOC_REGISTER
) or
123 (p
^.location
.loc
=LOC_CREGISTER
) then
124 hregister
:=p
^.location
.register
127 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.location
.reference
),R_D6
)));
131 { rangechecking for u32bit ?? !!!!!!}
132 else if porddef(p2
)^.typ
=u16bit
then
134 if (p
^.location
.loc
=LOC_REGISTER
) or
135 (p
^.location
.loc
=LOC_CREGISTER
) then
136 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_W
,p
^.location
.register,R_D6
)))
138 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.location
.reference
),R_D6
)));
140 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
,$FFFF,R_D6
)));
143 else if porddef(p2
)^.typ
=s16bit
then
145 if (p
^.location
.loc
=LOC_REGISTER
) or
146 (p
^.location
.loc
=LOC_CREGISTER
) then
147 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_W
,p
^.location
.register,R_D6
)))
149 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.location
.reference
),R_D6
)));
151 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_L
,R_D6
)));
154 else internalerror(6);
156 reset_reference(hp
^);
157 hp
^.symbol
:=stringdup('R_'+tostr(porddef(p1
)^.rangenr
));
158 if porddef(p1
)^.low
>porddef(p1
)^.high
then
162 exprasmlist
^.concat(new(paicpu
,op_reg(A_TST
,S_L
,hregister
)));
163 emitl(A_BLT
,neglabel
);
165 emit_bounds_check(hp
^,hregister
);
166 if porddef(p1
)^.low
>porddef(p1
)^.high
then
169 reset_reference(hp
^);
170 hp
^.symbol
:=stringdup('R_'+tostr(porddef(p1
)^.rangenr
+1));
171 emitl(A_JMP
,poslabel
);
172 emitl(A_LABEL
,neglabel
);
173 emit_bounds_check(hp
^,hregister
);
174 emitl(A_LABEL
,poslabel
);
181 tsecondconvproc
= procedure(p
,hp
: ptree
;convtyp
: tconverttype
);
183 procedure second_only_rangecheck(p
,hp
: ptree
;convtyp
: tconverttype
);
186 maybe_rangechecking(p
,hp
^.resulttype
,p
^.resulttype
);
190 procedure second_smaller(p
,hp
: ptree
;convtyp
: tconverttype
);
193 hregister
,destregister
: tregister
;
199 { !!!!!!!! Rangechecking }
201 { problems with enums !! }
202 { with $R+ explicit type conversations in TP aren't range checked! }
203 if (p
^.resulttype
^.deftype
=orddef
) and
204 (hp
^.resulttype
^.deftype
=orddef
) and
205 ((porddef(p
^.resulttype
)^.low
>porddef(hp
^.resulttype
)^.low
) or
206 (porddef(p
^.resulttype
)^.high
<porddef(hp
^.resulttype
)^.high
)) then
208 if (cs_check_range
in aktlocalswitches
) and
209 (not(p
^.explizit
) {or not(cs_tp_compatible in aktmoduleswitches)}) then
210 porddef(p
^.resulttype
)^.genrangecheck
;
211 if porddef(hp
^.resulttype
)^.typ
=s32bit
then
213 if (p
^.location
.loc
=LOC_REGISTER
) or
214 (p
^.location
.loc
=LOC_CREGISTER
) then
215 hregister
:=p
^.location
.register
218 hregister
:=getregister32
;
219 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.location
.reference
),hregister
)));
222 { rangechecking for u32bit ?? !!!!!!}
223 else if porddef(hp
^.resulttype
)^.typ
=u16bit
then
225 hregister
:=getregister32
;
226 if (p
^.location
.loc
=LOC_REGISTER
) or
227 (p
^.location
.loc
=LOC_CREGISTER
) then
229 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_W
,p
^.location
.register,hregister
)));
232 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.location
.reference
),hregister
)));
233 { clear unused bits i.e unsigned extend}
234 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
, $FFFF, hregister
)));
236 else if porddef(hp
^.resulttype
)^.typ
=s16bit
then
238 hregister
:=getregister32
;
239 if (p
^.location
.loc
=LOC_REGISTER
) or
240 (p
^.location
.loc
=LOC_CREGISTER
) then
241 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_W
,p
^.location
.register,hregister
)))
243 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.location
.reference
),hregister
)));
245 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
, S_L
, hregister
)));
247 else internalerror(6);
249 if (cs_check_range
in aktlocalswitches
) and
250 (not(p
^.explizit
) {or not(cs_tp_compatible in aktmoduleswitches)}) then
253 reset_reference(hpp
^);
254 hpp
^.symbol
:=stringdup('R_'+tostr(porddef(p
^.resulttype
)^.rangenr
));
257 emit_bounds_check(hpp
^, hregister
);
259 clear_location(p
^.location
);
260 p
^.location
.loc
:=LOC_REGISTER
;
261 p
^.location
.register:=hregister
;
264 { -------------- endian problems once again --------------------}
265 { If RIGHT enumdef (32-bit) and we do a typecase to a smaller }
266 { type we must absolutely load it into a register first. }
267 { --------------------------------------------------------------}
268 { ------------ supposing enumdef is always 32-bit --------------}
269 { --------------------------------------------------------------}
271 if (hp
^.resulttype
^.deftype
= enumdef
) and (p
^.resulttype
^.deftype
= orddef
) then
273 if (hp
^.location
.loc
=LOC_REGISTER
) or (hp
^.location
.loc
=LOC_CREGISTER
) then
274 hregister
:=hp
^.location
.register
277 hregister
:=getregister32
;
278 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(hp
^.location
.reference
),hregister
)));
280 clear_location(p
^.location
);
281 p
^.location
.loc
:=LOC_REGISTER
;
282 p
^.location
.register:=hregister
;
285 if (p
^.left
^.location
.loc
=LOC_REGISTER
) or
286 (p
^.left
^.location
.loc
=LOC_CREGISTER
) then
288 { handled by secondpas by called routine ??? }
289 p
^.location
.register:=p
^.left
^.location
.register;
294 procedure second_bigger(p
,hp
: ptree
;convtyp
: tconverttype
);
297 hregister
: tregister
;
300 is_register
: boolean;
304 is_register
:=p
^.left
^.location
.loc
=LOC_REGISTER
;
305 if not(is_register
) and (p
^.left
^.location
.loc
<>LOC_CREGISTER
) then
307 del_reference(p
^.left
^.location
.reference
);
308 { we can do this here as we need no temp inside second_bigger }
309 ungetiftemp(p
^.left
^.location
.reference
);
312 gives me movl (%eax),%eax
313 for the length(string !!!
314 use only for constant values }
315 {Constanst cannot be loaded into registers using MOVZX!}
316 if (p
^.left
^.location
.loc
<>LOC_MEM
) or (not p
^.left
^.location
.reference
.isintvalue
) then
321 hregister
:= p
^.left
^.location
.register
323 hregister
:= getregister32
;
325 emit_reg_reg(A_MOVE
,S_B
,p
^.left
^.location
.register, hregister
)
328 if p
^.left
^.location
.loc
= LOC_CREGISTER
then
329 emit_reg_reg(A_MOVE
,S_B
,p
^.left
^.location
.register,hregister
)
331 exprasmlist
^.concat(new(paicpu
, op_ref_reg(A_MOVE
,S_B
,
332 newreference(P
^.left
^.location
.reference
), hregister
)));
337 exprasmlist
^.concat(new(paicpu
, op_const_reg(
338 A_AND
,S_L
,$FF,hregister
)));
342 if aktoptprocessor
= MC68020
then
343 exprasmlist
^.concat(new(paicpu
,op_reg
344 (A_EXTB
,S_L
,hregister
)))
345 else { else if aktoptprocessor }
348 exprasmlist
^.concat(new(paicpu
,op_reg
349 (A_EXT
,S_W
,hregister
)));
351 exprasmlist
^.concat(new(paicpu
,op_reg
352 (A_EXT
,S_L
,hregister
)));
358 exprasmlist
^.concat(new(paicpu
, op_const_reg(
359 A_AND
,S_W
,$FF,hregister
)));
362 exprasmlist
^.concat(new(paicpu
, op_reg(
363 A_EXT
, S_W
, hregister
)));
370 tc_s16bit_2_s32bit
: begin
372 hregister
:= p
^.left
^.location
.register
374 hregister
:= getregister32
;
376 emit_reg_reg(A_MOVE
,S_W
,p
^.left
^.location
.register, hregister
)
379 if p
^.left
^.location
.loc
= LOC_CREGISTER
then
380 emit_reg_reg(A_MOVE
,S_W
,p
^.left
^.location
.register,hregister
)
382 exprasmlist
^.concat(new(paicpu
, op_ref_reg(A_MOVE
,S_W
,
383 newreference(P
^.left
^.location
.reference
), hregister
)));
385 if (convtyp
= tc_u16bit_2_s32bit
) or
386 (convtyp
= tc_u16bit_2_u32bit
) then
387 exprasmlist
^.concat(new(paicpu
, op_const_reg(
388 A_AND
, S_L
, $ffff, hregister
)))
389 else { tc_s16bit_2_s32bit }
390 { tc_s16bit_2_u32bit }
391 exprasmlist
^.concat(new(paicpu
, op_reg(A_EXT
,S_L
,
408 hregister
:=getregister32
;
417 hregister
:=getregister32
;
424 emit_reg_reg(op
,opsize
,p
^.left
^.location
.register,hregister
);
428 if p
^.left
^.location
.loc
=LOC_CREGISTER
then
429 emit_reg_reg(op
,opsize
,p
^.left
^.location
.register,hregister
)
430 else exprasmlist
^.concat(new(paicpu
,op_ref_reg(op
,opsize
,
431 newreference(p
^.left
^.location
.reference
),hregister
)));
435 clear_location(p
^.location
);
436 p
^.location
.loc
:=LOC_REGISTER
;
437 p
^.location
.register:=hregister
;
438 maybe_rangechecking(p
,p
^.left
^.resulttype
,p
^.resulttype
);
443 procedure second_string_string(p
,hp
: ptree
;convtyp
: tconverttype
);
449 { does anybody know a better solution than this big case statement ? }
450 { ok, a proc table would do the job }
451 case pstringdef(p
)^.string_typ
of
454 case pstringdef(p
^.left
)^.string_typ
of
457 stringdispose(p
^.location
.reference
.symbol
);
458 gettempofsizereference(p
^.resulttype
^.size
,p
^.location
.reference
);
459 del_reference(p
^.left
^.location
.reference
);
460 copystring(p
^.location
.reference
,p
^.left
^.location
.reference
,pstringdef(p
^.resulttype
)^.len
);
461 ungetiftemp(p
^.left
^.location
.reference
);
481 case pstringdef(p
^.left
)^.string_typ
of
500 case pstringdef(p
^.left
)^.string_typ
of
503 pushusedregisters(pushed
,$ff);
504 push_int(p
^.resulttype
^.size
-1);
505 gettempofsizereference(p
^.resulttype
^.size
,p
^.location
.reference
);
506 emitpushreferenceaddr(exprasmlist
,p
^.location
.reference
);
507 case p
^.right
^.location
.loc
of
508 LOC_REGISTER
,LOC_CREGISTER
:
510 { !!!!! exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register))); }
511 ungetregister32(p
^.left
^.location
.register);
513 LOC_REFERENCE
,LOC_MEM
:
515 emit_push_mem(p
^.left
^.location
.reference
);
516 del_reference(p
^.left
^.location
.reference
);
519 emitcall('FPC_ANSI_TO_SHORTSTRING',true);
521 popusedregisters(pushed
);
536 case pstringdef(p
^.left
)^.string_typ
of
561 procedure second_cstring_charpointer(p
,hp
: ptree
;convtyp
: tconverttype
);
564 clear_location(p
^.location
);
565 p
^.location
.loc
:=LOC_REGISTER
;
566 p
^.location
.register:=getregister32
;
567 inc(p
^.left
^.location
.reference
.offset
);
568 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_LEA
,S_L
,newreference(p
^.left
^.location
.reference
),
570 emit_reg_reg(A_MOVE
, S_L
, R_A0
, p
^.location
.register);
573 procedure second_string_chararray(p
,hp
: ptree
;convtyp
: tconverttype
);
576 inc(p
^.location
.reference
.offset
);
579 procedure second_array_to_pointer(p
,hp
: ptree
;convtyp
: tconverttype
);
582 del_reference(p
^.left
^.location
.reference
);
583 clear_location(p
^.location
);
584 p
^.location
.loc
:=LOC_REGISTER
;
585 p
^.location
.register:=getregister32
;
586 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_LEA
,S_L
,newreference(p
^.left
^.location
.reference
),
588 emit_reg_reg(A_MOVE
,S_L
,R_A0
, P
^.location
.register);
591 procedure second_pointer_to_array(p
,hp
: ptree
;convtyp
: tconverttype
);
595 clear_location(p
^.location
);
596 p
^.location
.loc
:=LOC_REFERENCE
;
597 clear_reference(p
^.location
.reference
);
598 { here, after doing some arithmetic on the pointer }
599 { we put it back in an address register }
600 if p
^.left
^.location
.loc
=LOC_REGISTER
then
602 reg
:= getaddressreg
;
603 { move the pointer in a data register back into }
604 { an address register. }
605 emit_reg_reg(A_MOVE
, S_L
, p
^.left
^.location
.register,reg
);
607 p
^.location
.reference
.base
:=reg
;
608 ungetregister32(p
^.left
^.location
.register);
612 if p
^.left
^.location
.loc
=LOC_CREGISTER
then
614 p
^.location
.reference
.base
:=getaddressreg
;
615 emit_reg_reg(A_MOVE
,S_L
,p
^.left
^.location
.register,
616 p
^.location
.reference
.base
);
620 del_reference(p
^.left
^.location
.reference
);
621 p
^.location
.reference
.base
:=getaddressreg
;
622 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.left
^.location
.reference
),
623 p
^.location
.reference
.base
)));
628 { generates the code for the type conversion from an array of char }
630 procedure second_chararray_to_string(p
,hp
: ptree
;convtyp
: tconverttype
);
636 { this is a type conversion which copies the data, so we can't }
637 { return a reference }
638 clear_location(p
^.location
);
639 p
^.location
.loc
:=LOC_MEM
;
641 { first get the memory for the string }
642 stringdispose(p
^.location
.reference
.symbol
);
643 gettempofsizereference(256,p
^.location
.reference
);
645 { calc the length of the array }
646 l
:=parraydef(p
^.left
^.resulttype
)^.highrange
-
647 parraydef(p
^.left
^.resulttype
)^.lowrange
+1;
650 CGMessage(type_e_mismatch
);
653 exprasmlist
^.concat(new(paicpu
,op_const_ref(A_MOVE
,S_B
,l
,
654 newreference(p
^.location
.reference
))));
656 { copy to first char of string }
657 inc(p
^.location
.reference
.offset
);
659 { generates the copy code }
660 { and we need the source never }
661 concatcopy(p
^.left
^.location
.reference
,p
^.location
.reference
,l
,true);
663 { correct the string location }
664 dec(p
^.location
.reference
.offset
);
667 procedure second_char_to_string(p
,hp
: ptree
;convtyp
: tconverttype
);
670 stringdispose(p
^.location
.reference
.symbol
);
671 gettempofsizereference(256,p
^.location
.reference
);
672 { call loadstring with correct left and right }
676 p
^.left
:=nil; { reset left tree, which is empty }
677 { p^.right is not disposed for typeconv !! PM }
678 disposetree(p
^.right
);
682 procedure second_int_real(p
,hp
: ptree
;convtyp
: tconverttype
);
688 emitloadord2reg(p
^.left
^.location
, porddef(p
^.left
^.resulttype
), R_D6
, true);
689 ungetiftemp(p
^.left
^.location
.reference
);
690 if porddef(p
^.left
^.resulttype
)^.typ
=u32bit
then
693 emit_reg_reg(A_MOVE
, S_L
, R_D6
, R_SPPUSH
);
698 { for u32bit a solution would be to push $0 and to load a
700 + if porddef(p^.left^.resulttype)^.typ=u32bit then
701 + exprasmlist^.concat(new(paicpu,op_ref(A_FILD,S_IQ,r)))
703 clear_location(p
^.location
);
704 p
^.location
.loc
:= LOC_FPU
;
705 { get floating point register. }
706 if (cs_fp_emulation
in aktmoduleswitches
) then
708 p
^.location
.fpureg
:= getregister32
;
709 exprasmlist
^.concat(new(paicpu
, op_ref_reg(A_MOVE
, S_L
, r
, R_D0
)));
710 emitcall('FPC_LONG2SINGLE',true);
711 emit_reg_reg(A_MOVE
,S_L
,R_D0
,p
^.location
.fpureg
);
715 p
^.location
.fpureg
:= getfloatreg
;
716 exprasmlist
^.concat(new(paicpu
, op_ref_reg(A_FMOVE
, S_L
, r
, p
^.location
.fpureg
)))
718 if porddef(p
^.left
^.resulttype
)^.typ
=u32bit
then
719 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ADD
,S_L
,8,R_SP
)))
721 { restore the stack to the previous address }
722 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_ADDQ
, S_L
, 4, R_SP
)));
725 procedure second_real_fix(p
,hp
: ptree
;convtyp
: tconverttype
);
731 { Are we in a LOC_FPU, if not then use scratch registers }
732 { instead of allocating reserved registers. }
733 if (p
^.left
^.location
.loc
<>LOC_FPU
) then
735 if (cs_fp_emulation
in aktmoduleswitches
) then
737 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.left
^.location
.reference
),R_D0
)));
738 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_L
,65536,R_D1
)));
739 emitcall('FPC_LONGMUL',true);
740 emit_reg_reg(A_MOVE
,S_L
,R_D0
,rreg
);
744 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_FMOVE
,S_L
,newreference(p
^.left
^.location
.reference
),R_FP0
)));
745 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_FMUL
,S_L
,65536,R_FP0
)));
746 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_FMOVE
,S_L
,R_FP0
,rreg
)));
751 if (cs_fp_emulation
in aktmoduleswitches
) then
753 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,p
^.left
^.location
.fpureg
,R_D0
)));
754 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_L
,65536,R_D1
)));
755 emitcall('FPC_LONGMUL',true);
756 emit_reg_reg(A_MOVE
,S_L
,R_D0
,rreg
);
760 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_FMUL
,S_L
,65536,p
^.left
^.location
.fpureg
)));
761 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_FMOVE
,S_L
,p
^.left
^.location
.fpureg
,rreg
)));
764 clear_location(p
^.location
);
765 p
^.location
.loc
:=LOC_REGISTER
;
766 p
^.location
.register:=rreg
;
770 procedure second_float_float(p
,hp
: ptree
;convtyp
: tconverttype
);
773 case p
^.left
^.location
.loc
of
776 clear_location(p
^.location
);
777 p
^.location
.loc
:= LOC_FPU
;
778 p
^.location
.fpureg
:= p
^.left
^.location
.fpureg
;
781 LOC_REFERENCE
: floatload(pfloatdef(p
^.left
^.resulttype
)^.typ
,
782 p
^.left
^.location
.reference
,p
^.location
);
784 { ALREADY HANDLED BY FLOATLOAD }
785 { p^.location.loc:=LOC_FPU; }
788 procedure second_fix_real(p
,hp
: ptree
;convtyp
: tconverttype
);
790 startreg
: tregister
;
794 hl1
,hl2
,hl3
,hl4
,hl5
,hl6
,hl7
,hl8
,hl9
: pasmlabel
;
796 if (p
^.left
^.location
.loc
=LOC_REGISTER
) or
797 (p
^.left
^.location
.loc
=LOC_CREGISTER
) then
799 startreg
:=p
^.left
^.location
.register;
800 ungetregister(startreg
);
801 { move d0,d0 is removed by emit_reg_reg }
802 emit_reg_reg(A_MOVE
,S_L
,startreg
,R_D0
);
806 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(
807 p
^.left
^.location
.reference
),R_D0
)));
808 del_reference(p
^.left
^.location
.reference
);
812 reg1
:= getregister32
;
814 { Motorola 68000 equivalent of CDQ }
815 { we choose d1:d0 pair for quad word }
816 exprasmlist
^.concat(new(paicpu
,op_reg(A_TST
,S_L
,R_D0
)));
819 { we copy all bits (-ve number) }
820 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_L
,$ffffffff,R_D1
)));
824 exprasmlist
^.concat(new(paicpu
,op_reg(A_CLR
,S_L
,R_D0
)));
828 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_EOR
,S_L
,R_D1
,R_D0
)));
829 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D0
,reg1
)));
833 { Motorola 68000 equivalent of RCL }
836 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_LSL
,S_L
,1,reg1
)));
837 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_OR
,S_L
,1,reg1
)));
841 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_LSL
,S_L
,1,reg1
)));
845 { Motorola 68000 equivalent of BSR }
847 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D0
,R_D6
)));
848 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_B
,31,R_D0
)));
851 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_BTST
,S_L
,R_D0
,R_D1
)));
854 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_SUBQ
,S_B
,1,R_D0
)));
857 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D6
,R_D0
)));
861 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_B
,32,R_D6
)));
862 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_SUB
,S_B
,R_D1
,R_D6
)));
863 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_LSL
,S_L
,R_D6
,R_D0
)));
864 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ADD
,S_W
,1007,R_D1
)));
865 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_LSL
,S_L
,5,R_D1
)));
867 { Motorola 68000 equivalent of SHLD }
868 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_W
,11,R_D6
)));
870 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D1
,R_A0
)));
873 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ROXL
,S_W
,1,R_D1
)));
874 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ROXL
,S_W
,1,reg1
)));
875 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_SUBQ
,S_B
,1,R_D6
)));
878 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_A0
,R_D1
)));
879 { end Motorola equivalent of SHLD }
881 { Motorola 68000 equivalent of SHLD }
882 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_W
,20,R_D6
)));
884 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D0
,R_A0
)));
887 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ROXL
,S_W
,1,R_D0
)));
888 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ROXL
,S_W
,1,reg1
)));
889 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_SUBQ
,S_B
,1,R_D6
)));
892 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_A0
,R_D0
)));
893 { end Motorola equivalent of SHLD }
895 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_B
,20,R_D6
)));
896 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_SUB
,S_L
,R_D6
,R_D0
)));
899 { create temp values and put on stack }
900 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,reg1
,R_SPPUSH
)));
901 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,R_D0
,R_SPPUSH
)));
907 if (cs_fp_emulation
in aktmoduleswitches
) then
909 clear_location(p
^.location
);
910 p
^.location
.loc
:=LOC_FPU
;
911 p
^.location
.fpureg
:= getregister32
;
912 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(r
),
913 p
^.left
^.location
.fpureg
)))
917 clear_location(p
^.location
);
918 p
^.location
.loc
:=LOC_FPU
;
919 p
^.location
.fpureg
:= getfloatreg
;
920 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_FMOVE
,S_L
,newreference(r
),
921 p
^.left
^.location
.fpureg
)))
923 { clear temporary space }
924 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_ADDQ
,S_L
,8,R_SP
)));
925 ungetregister32(reg1
);
926 { Alreadu handled above... }
927 { p^.location.loc:=LOC_FPU; }
930 procedure second_int_fix(p
,hp
: ptree
;convtyp
: tconverttype
);
934 hregister
: tregister
;
937 if (p
^.left
^.location
.loc
=LOC_REGISTER
) then
938 hregister
:=p
^.left
^.location
.register
939 else if (p
^.left
^.location
.loc
=LOC_CREGISTER
) then
940 hregister
:=getregister32
943 del_reference(p
^.left
^.location
.reference
);
944 hregister
:=getregister32
;
945 case porddef(p
^.left
^.resulttype
)^.typ
of
947 exprasmlist
^.concat(new(paicpu
, op_ref_reg(A_MOVE
,S_B
,
948 newreference(p
^.left
^.location
.reference
),hregister
)));
949 if aktoptprocessor
= MC68020
then
950 exprasmlist
^.concat(new(paicpu
, op_reg(A_EXTB
,S_L
,hregister
)))
953 exprasmlist
^.concat(new(paicpu
, op_reg(A_EXT
,S_W
,hregister
)));
954 exprasmlist
^.concat(new(paicpu
, op_reg(A_EXT
,S_L
,hregister
)));
958 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_B
,newreference(p
^.left
^.location
.reference
),
960 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
,$ff,hregister
)));
963 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.left
^.location
.reference
),
965 exprasmlist
^.concat(new(paicpu
,op_reg(A_EXT
,S_L
,hregister
)));
968 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_W
,newreference(p
^.left
^.location
.reference
),
970 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_AND
,S_L
,$ffff,hregister
)));
972 s32bit
,u32bit
: exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.left
^.location
.reference
),
977 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVEQ
,S_L
,16,R_D1
)));
978 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_LSL
,S_L
,R_D1
,hregister
)));
980 clear_location(p
^.location
);
981 p
^.location
.loc
:=LOC_REGISTER
;
982 p
^.location
.register:=hregister
;
986 procedure second_proc_to_procvar(p
,hp
: ptree
;convtyp
: tconverttype
);
989 { secondpass(hp); already done in secondtypeconv PM }
990 clear_location(p
^.location
);
991 p
^.location
.loc
:=LOC_REGISTER
;
992 del_reference(hp
^.location
.reference
);
993 p
^.location
.register:=getregister32
;
994 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_LEA
,S_L
,
995 newreference(hp
^.location
.reference
),R_A0
)));
997 emit_reg_reg(A_MOVE
, S_L
, R_A0
, P
^.location
.register);
1000 procedure second_bool_to_int(p
,hp
: ptree
;convtyp
: tconverttype
);
1003 oldtruelabel
,oldfalselabel
,hlabel
: pasmlabel
;
1004 hregister
: tregister
;
1009 oldtruelabel
:=truelabel
;
1010 oldfalselabel
:=falselabel
;
1011 getlabel(truelabel
);
1012 getlabel(falselabel
);
1014 clear_location(p
^.location
);
1015 p
^.location
.loc
:=LOC_REGISTER
;
1016 del_reference(hp
^.location
.reference
);
1017 hregister
:=getregister32
;
1018 case porddef(hp
^.resulttype
)^.typ
of
1020 case porddef(p
^.resulttype
)^.typ
of
1022 bool8bit
: opsize
:=S_B
;
1024 bool16bit
: opsize
:=S_BW
;
1026 bool32bit
: opsize
:=S_BL
;
1030 case porddef(p
^.resulttype
)^.typ
of
1032 bool8bit
: opsize
:=S_B
;
1034 bool16bit
: opsize
:=S_W
;
1036 bool32bit
: opsize
:=S_WL
;
1040 case porddef(p
^.resulttype
)^.typ
of
1042 bool8bit
: opsize
:=S_B
;
1044 bool16bit
: opsize
:=S_W
;
1046 bool32bit
: opsize
:=S_L
;
1051 { if opsize in [S_B,S_W,S_L] then
1054 if (porddef(p^.resulttype)^.typ in [s8bit,s16bit,s32bit]) then
1058 case porddef(p
^.resulttype
)^.typ
of
1059 bool8bit
,u8bit
,s8bit
: begin
1060 p
^.location
.register:=hregister
;
1063 bool16bit
,u16bit
,s16bit
: begin
1064 p
^.location
.register:=hregister
;
1067 bool32bit
,u32bit
,s32bit
: begin
1068 p
^.location
.register:=hregister
;
1072 internalerror(10060);
1075 case hp
^.location
.loc
of
1077 LOC_REFERENCE
: exprasmlist
^.concat(new(paicpu
,op_ref_reg(op
,opsize
,
1078 newreference(hp
^.location
.reference
),p
^.location
.register)));
1080 LOC_CREGISTER
: exprasmlist
^.concat(new(paicpu
,op_reg_reg(op
,opsize
,
1081 hp
^.location
.register,p
^.location
.register)));
1083 { hregister:=reg32toreg8(hregister); }
1084 exprasmlist
^.concat(new(paicpu
,op_reg(flag_2_set
[hp
^.location
.resflags
],S_B
,hregister
)));
1086 case porddef(p^.resulttype)^.typ of
1088 u16bit,s16bit : exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVZX,S_BW,hregister,p^.location.register)));
1090 u32bit,s32bit : exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVZX,S_BL,hregister,p^.location.register)));
1095 emitl(A_LABEL
,truelabel
);
1096 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,newsize
,1,hregister
)));
1097 emitl(A_JMP
,hlabel
);
1098 emitl(A_LABEL
,falselabel
);
1099 exprasmlist
^.concat(new(paicpu
,op_reg(A_CLR
,newsize
,hregister
)));
1100 emitl(A_LABEL
,hlabel
);
1103 internalerror(10061);
1105 truelabel
:=oldtruelabel
;
1106 falselabel
:=oldfalselabel
;
1110 procedure second_int_to_bool(p
,hp
: ptree
;convtyp
: tconverttype
);
1112 hregister
: tregister
;
1114 clear_location(p
^.location
);
1115 p
^.location
.loc
:=LOC_REGISTER
;
1116 del_reference(hp
^.location
.reference
);
1117 case hp
^.location
.loc
of
1118 LOC_MEM
,LOC_REFERENCE
:
1120 hregister
:=getregister32
;
1121 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,
1122 newreference(hp
^.location
.reference
),hregister
)));
1124 LOC_REGISTER
,LOC_CREGISTER
:
1126 hregister
:=hp
^.location
.register;
1129 internalerror(10062);
1131 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_OR
,S_L
,hregister
,hregister
)));
1132 { hregister:=reg32toreg8(hregister); }
1133 exprasmlist
^.concat(new(paicpu
,op_reg(flag_2_set
[hp
^.location
.resflags
],S_B
,hregister
)));
1134 case porddef(p
^.resulttype
)^.typ
of
1135 bool8bit
: p
^.location
.register:=hregister
;
1139 p^.location.register:=reg8toreg16(hregister);
1140 exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVZX,S_BW,hregister,p^.location.register)));
1143 p^.location.register:=reg16toreg32(hregister);
1144 exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVZX,S_BL,hregister,p^.location.register)));
1147 internalerror(10064);
1151 procedure second_load_smallset(p
,hp
: ptree
;convtyp
: tconverttype
);
1154 pushedregs
: tpushed
;
1157 pushusedregisters(pushedregs
,$ff);
1158 gettempofsizereference(32,href
);
1159 emitpushreferenceaddr(exprasmlist
,p
^.left
^.location
.reference
);
1160 emitpushreferenceaddr(exprasmlist
,href
);
1161 emitcall('FPC_SET_LOAD_SMALL',true);
1163 popusedregisters(pushedregs
);
1164 clear_location(p
^.location
);
1165 p
^.location
.loc
:=LOC_MEM
;
1166 stringdispose(p
^.location
.reference
.symbol
);
1167 p
^.location
.reference
:=href
;
1170 procedure second_ansistring_to_pchar(p
,hp
: ptree
;convtyp
: tconverttype
);
1177 InternalError(342132);
1180 clear_location(p^.location);
1181 p^.location.loc:=LOC_REGISTER;
1184 case hp^.location.loc of
1185 LOC_CREGISTER,LOC_REGISTER:
1186 exprasmlist^.concat(new(paicpu,op_const_reg(A_CMP,S_L,0,
1187 hp^.location.register)));
1188 LOC_MEM,LOC_REFERENCE:
1190 exprasmlist^.concat(new(paicpu,op_const_ref(A_CMP,S_L,0,
1191 newreference(hp^.location.reference))));
1192 del_reference(hp^.location.reference);
1193 p^.location.register:=getregister32;
1197 if hp^.location.loc in [LOC_MEM,LOC_REFERENCE] then
1198 exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOV,S_L,newreference(
1199 hp^.location.reference),
1200 p^.location.register)));
1204 reset_reference(hr^);
1205 hr^.symbol:=stringdup('FPC_EMPTYCHAR');
1206 exprasmlist^.concat(new(paicpu,op_ref_reg(A_LEA,S_L,hr,
1207 p^.location.register)));
1208 emitl(A_LABEL,l2); }
1211 procedure second_pchar_to_string(p
,hp
: ptree
;convtyp
: tconverttype
);
1213 internalerror(12121);
1216 procedure second_nothing(p
,hp
: ptree
;convtyp
: tconverttype
);
1220 {****************************************************************************
1222 ****************************************************************************}
1224 procedure secondtypeconv(var p
: ptree
);
1226 secondconvert
: array[tconverttype
] of
1227 tsecondconvproc
= (second_nothing
,second_nothing
,
1228 second_bigger
,second_only_rangecheck
,
1229 second_bigger
,second_bigger
,second_bigger
,
1230 second_smaller
,second_smaller
,
1231 second_smaller
,second_string_string
,
1232 second_cstring_charpointer
,second_string_chararray
,
1233 second_array_to_pointer
,second_pointer_to_array
,
1234 second_char_to_string
,second_bigger
,
1235 second_bigger
,second_bigger
,
1236 second_smaller
,second_smaller
,
1237 second_smaller
,second_smaller
,
1242 second_only_rangecheck
,second_bigger
,
1243 second_bigger
,second_bigger
,
1244 second_bigger
,second_only_rangecheck
,
1245 second_smaller
,second_smaller
,
1246 second_smaller
,second_smaller
,
1247 second_bool_to_int
,second_int_to_bool
,
1248 second_int_real
,second_real_fix
,
1249 second_fix_real
,second_int_fix
,second_float_float
,
1250 second_chararray_to_string
,
1251 second_proc_to_procvar
,
1252 { is constant char to pchar, is done by firstpass }
1254 second_load_smallset
,
1255 second_ansistring_to_pchar
,
1256 second_pchar_to_string
,
1261 { this isn't good coding, I think tc_bool_2_int, shouldn't be }
1262 { type conversion (FK) }
1264 { this is necessary, because second_bool_byte, have to change }
1265 { true- and false label before calling secondpass }
1266 if p
^.convtyp
<>tc_bool_2_int
then
1268 secondpass(p
^.left
);
1269 set_location(p
^.location
,p
^.left
^.location
);
1270 if codegenerror
then
1274 if not(p
^.convtyp
in [tc_equal
,tc_not_possible
]) then
1275 {the second argument only is for maybe_range_checking !}
1276 secondconvert
[p
^.convtyp
](p
,p
^.left
,p
^.convtyp
)
1280 {*****************************************************************************
1282 *****************************************************************************}
1284 procedure secondis(var p
: ptree
);
1290 { save all used registers }
1291 pushusedregisters(pushed
,$ffff);
1292 secondpass(p
^.left
);
1293 clear_location(p
^.location
);
1294 p
^.location
.loc
:=LOC_FLAGS
;
1295 p
^.location
.resflags
:=F_NE
;
1297 { push instance to check: }
1298 case p
^.left
^.location
.loc
of
1299 LOC_REGISTER
,LOC_CREGISTER
:
1301 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,
1302 S_L
,p
^.left
^.location
.register,R_SPPUSH
)));
1303 ungetregister32(p
^.left
^.location
.register);
1305 LOC_MEM
,LOC_REFERENCE
:
1307 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,
1308 S_L
,newreference(p
^.left
^.location
.reference
),R_SPPUSH
)));
1309 del_reference(p
^.left
^.location
.reference
);
1311 else internalerror(100);
1314 { generate type checking }
1315 secondpass(p
^.right
);
1316 case p
^.right
^.location
.loc
of
1317 LOC_REGISTER
,LOC_CREGISTER
:
1319 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,
1320 S_L
,p
^.right
^.location
.register,R_SPPUSH
)));
1321 ungetregister32(p
^.right
^.location
.register);
1323 LOC_MEM
,LOC_REFERENCE
:
1325 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,
1326 S_L
,newreference(p
^.right
^.location
.reference
),R_SPPUSH
)));
1327 del_reference(p
^.right
^.location
.reference
);
1329 else internalerror(100);
1331 emitcall('FPC_DO_IS',true);
1332 exprasmlist
^.concat(new(paicpu
,op_reg(A_TST
,S_B
,R_D0
)));
1333 popusedregisters(pushed
);
1337 {*****************************************************************************
1339 *****************************************************************************}
1341 procedure secondas(var p
: ptree
);
1347 set_location(p
^.location
,p
^.left
^.location
);
1348 { save all used registers }
1349 pushusedregisters(pushed
,$ffff);
1350 { push the vmt of the class }
1351 exprasmlist
^.concat(new(paicpu
,op_csymbol_reg(A_MOVE
,
1352 S_L
,newcsymbol(pobjectdef(p
^.right
^.resulttype
)^.vmt_mangledname
,0),R_SPPUSH
)));
1353 emitpushreferenceaddr(exprasmlist
,p
^.location
.reference
);
1354 emitcall('FPC_DO_AS',true);
1355 popusedregisters(pushed
);
1362 Revision 1.1 2002/02/19 08:21:46 sasu
1365 Revision 1.1 2000/07/13 06:29:46 michael
1368 Revision 1.17 2000/02/09 13:22:48 peter
1371 Revision 1.16 2000/01/07 01:14:21 peter
1372 * updated copyright to 2000
1374 Revision 1.15 1999/12/22 01:01:47 peter
1375 - removed freelabel()
1376 * added undefined label detection in internal assembler, this prevents
1377 a lot of ld crashes and wrong .o files
1378 * .o files aren't written anymore if errors have occured
1379 * inlining of assembler labels is now correct
1381 Revision 1.14 1999/09/16 23:05:51 florian
1382 * m68k compiler is again compilable (only gas writer, no assembler reader)
1384 Revision 1.13 1999/08/25 11:59:48 jonas
1385 * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)