3 Copyright (c) 1998-2000 by Florian Klaempfl
5 Generate m68k assembler for math 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 ****************************************************************************
29 procedure secondmoddiv(var p
: ptree
);
30 procedure secondshlshr(var p
: ptree
);
31 procedure secondunaryminus(var p
: ptree
);
32 procedure secondnot(var p
: ptree
);
38 globtype
,systems
,symconst
,
39 cobjects
,verbose
,globals
,
41 hcodegen
,temp_gen
,pass_2
,
42 cpubase
,cga68k
,tgen68k
;
44 {*****************************************************************************
46 *****************************************************************************}
48 { D0 and D1 used as temp (ok) }
49 procedure secondmoddiv(var p
: ptree
);
60 set_location(p
^.location
,p
^.left
^.location
);
61 pushed
:=maybe_push(p
^.right
^.registers32
,p
);
63 if pushed
then restore(p
);
65 { put numerator in register }
66 if p
^.left
^.location
.loc
<>LOC_REGISTER
then
68 if p
^.left
^.location
.loc
=LOC_CREGISTER
then
71 emit_reg_reg(A_MOVE
,S_L
,p
^.left
^.location
.register,hreg1
);
75 del_reference(p
^.left
^.location
.reference
);
77 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.left
^.location
.reference
),
80 clear_location(p
^.left
^.location
);
81 p
^.left
^.location
.loc
:=LOC_REGISTER
;
82 p
^.left
^.location
.register:=hreg1
;
84 else hreg1
:=p
^.left
^.location
.register;
86 if (p
^.treetype
=divn
) and (p
^.right
^.treetype
=ordconstn
) and
87 ispowerof2(p
^.right
^.value
,power
) then
89 exprasmlist
^.concat(new(paicpu
, op_reg(A_TST
, S_L
, hreg1
)));
93 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_ADDQ
, S_L
,1, hreg1
)))
96 { optimize using ADDQ if possible! }
97 if (p
^.right
^.value
-1) < 9 then
98 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_ADDQ
, S_L
,p
^.right
^.value
-1, hreg1
)))
100 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_ADD
, S_L
,p
^.right
^.value
-1, hreg1
)));
103 if (power
> 0) and (power
< 9) then
104 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_ASR
, S_L
,power
, hreg1
)))
107 exprasmlist
^.concat(new(paicpu
, op_const_reg(A_MOVE
,S_L
,power
, R_D0
)));
108 exprasmlist
^.concat(new(paicpu
, op_reg_reg(A_ASR
,S_L
,R_D0
, hreg1
)));
113 { bring denominator to D1 }
114 { D1 is always free, it's }
115 { only used for temporary }
117 if (p
^.right
^.location
.loc
<>LOC_REGISTER
) and
118 (p
^.right
^.location
.loc
<>LOC_CREGISTER
) then
120 del_reference(p
^.right
^.location
.reference
);
121 p
^.left
^.location
.loc
:=LOC_REGISTER
;
122 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.right
^.location
.reference
),R_D1
)));
126 ungetregister32(p
^.right
^.location
.register);
127 emit_reg_reg(A_MOVE
,S_L
,p
^.right
^.location
.register,R_D1
);
130 { on entering this section D1 should contain the divisor }
132 if (aktoptprocessor
= MC68020
) then
134 { Check if divisor is ZERO - if so call HALT_ERROR }
135 { with d0 = 200 (Division by zero!) }
137 exprasmlist
^.concat(new(paicpu
,op_reg(A_TST
,S_L
,R_D1
)));
138 { if not zero then simply continue on }
140 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_L
,200,R_D0
)));
141 emitcall('FPC_HALT_ERROR',true);
143 if (p
^.treetype
= modn
) then
145 reg
:= getregister32
;
146 exprasmlist
^.concat(new(paicpu
,op_reg(A_CLR
,S_L
,reg
)));
148 { here what we do is prepare the high register with the }
149 { correct sign. i.e we clear it, check if the low dword reg }
150 { which will participate in the division is signed, if so we}
151 { we extend the sign to the high doword register by inverting }
153 exprasmlist
^.concat(new(paicpu
,op_reg(A_TST
,S_L
,hreg1
)));
155 exprasmlist
^.concat(new(paicpu
,op_reg(A_NOT
,S_L
,reg
)));
158 exprasmlist
^.concat(new(paicpu
,op_reg_reg_reg(A_DIVSL
,S_L
,R_D1
,reg
,hreg1
)));
159 { hreg1 already contains quotient }
160 { looking for remainder }
161 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_MOVE
,S_L
,reg
,hreg1
)));
162 ungetregister32(reg
);
165 { simple division... }
168 exprasmlist
^.concat(new(paicpu
,op_reg_reg(A_DIVS
,S_L
,R_D1
,hreg1
)));
171 else { MC68000 operations }
173 { put numerator in d0 }
174 emit_reg_reg(A_MOVE
,S_L
,hreg1
,R_D0
);
175 { operation to perform on entry to both }
176 { routines... d0/d1 }
177 { return result in d0 }
178 if p
^.treetype
= divn
then
179 emitcall('FPC_LONGDIV',true)
181 emitcall('FPC_LONGMOD',true);
182 emit_reg_reg(A_MOVE
,S_L
,R_D0
,hreg1
);
185 { this registers are always used when div/mod are present }
186 usedinproc
:=usedinproc
or ($800 shr word(R_D1
));
187 usedinproc
:=usedinproc
or ($800 shr word(R_D0
));
188 clear_location(p
^.location
);
189 p
^.location
.loc
:=LOC_REGISTER
;
190 p
^.location
.register:=hreg1
;
194 {*****************************************************************************
196 *****************************************************************************}
198 { D6 used as scratch (ok) }
199 procedure secondshlshr(var p
: ptree
);
202 hregister1
,hregister2
,hregister3
: tregister
;
208 pushed
:=maybe_push(p
^.right
^.registers32
,p
);
209 secondpass(p
^.right
);
210 if pushed
then restore(p
);
212 { load left operators in a register }
213 if p
^.left
^.location
.loc
<>LOC_REGISTER
then
215 if p
^.left
^.location
.loc
=LOC_CREGISTER
then
217 hregister1
:=getregister32
;
218 emit_reg_reg(A_MOVE
,S_L
,p
^.left
^.location
.register,
223 del_reference(p
^.left
^.location
.reference
);
224 hregister1
:=getregister32
;
225 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.left
^.location
.reference
),
229 else hregister1
:=p
^.left
^.location
.register;
231 { determine operator }
232 if p
^.treetype
=shln
then
237 { shifting by a constant directly decode: }
238 if (p
^.right
^.treetype
=ordconstn
) then
240 if (p
^.right
^.location
.reference
.offset
and 31 > 0) and (p
^.right
^.location
.reference
.offset
and 31 < 9) then
241 exprasmlist
^.concat(new(paicpu
,op_const_reg(op
,S_L
,p
^.right
^.location
.reference
.offset
and 31,
245 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_MOVE
,S_L
,p
^.right
^.location
.reference
.offset
and 31,
247 exprasmlist
^.concat(new(paicpu
,op_reg_reg(op
,S_L
,R_D6
,hregister1
)));
249 p
^.location
.loc
:=LOC_REGISTER
;
250 p
^.location
.register:=hregister1
;
254 { load right operators in a register }
255 if p
^.right
^.location
.loc
<>LOC_REGISTER
then
257 if p
^.right
^.location
.loc
=LOC_CREGISTER
then
259 hregister2
:=getregister32
;
260 emit_reg_reg(A_MOVE
,S_L
,p
^.right
^.location
.register,
265 del_reference(p
^.right
^.location
.reference
);
266 hregister2
:=getregister32
;
267 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,newreference(p
^.right
^.location
.reference
),
271 else hregister2
:=p
^.right
^.location
.register;
274 emit_reg_reg(op
,S_L
,hregister2
,hregister1
);
275 p
^.location
.register:=hregister1
;
277 { this register is always used when shl/shr are present }
278 usedinproc
:=usedinproc
or ($800 shr byte(R_D6
));
281 {*****************************************************************************
283 *****************************************************************************}
285 procedure secondunaryminus(var p
: ptree
);
289 p
^.location
.loc
:=LOC_REGISTER
;
290 case p
^.left
^.location
.loc
of
292 p
^.location
.register:=p
^.left
^.location
.register;
293 exprasmlist
^.concat(new(paicpu
,op_reg(A_NEG
,S_L
,p
^.location
.register)));
295 LOC_CREGISTER
: begin
296 p
^.location
.register:=getregister32
;
297 emit_reg_reg(A_MOVE
,S_L
,p
^.location
.register,
298 p
^.location
.register);
299 exprasmlist
^.concat(new(paicpu
,op_reg(A_NEG
,S_L
,p
^.location
.register)));
301 LOC_REFERENCE
,LOC_MEM
:
303 del_reference(p
^.left
^.location
.reference
);
304 { change sign of a floating point }
305 { in the case of emulation, get }
306 { a free register, and change sign }
308 { otherwise simply load into an FPU}
310 if (p
^.left
^.resulttype
^.deftype
=floatdef
) and
311 (pfloatdef(p
^.left
^.resulttype
)^.typ
<>f32bit
) then
314 floatload(pfloatdef(p
^.left
^.resulttype
)^.typ
,
315 p
^.left
^.location
.reference
,p
^.location
);
316 if (cs_fp_emulation
) in aktmoduleswitches
then
317 { if in emulation mode change sign manually }
318 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_BCHG
,S_L
,31,
319 p
^.location
.fpureg
)))
321 exprasmlist
^.concat(new(paicpu
,op_reg(A_FNEG
,S_FX
,
322 p
^.location
.fpureg
)));
326 p
^.location
.register:=getregister32
;
327 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,
328 newreference(p
^.left
^.location
.reference
),
329 p
^.location
.register)));
330 exprasmlist
^.concat(new(paicpu
,op_reg(A_NEG
,S_L
,p
^.location
.register)));
334 p
^.location
.loc
:=LOC_FPU
;
335 p
^.location
.fpureg
:= p
^.left
^.location
.fpureg
;
336 if (cs_fp_emulation
) in aktmoduleswitches
then
337 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_BCHG
,S_L
,31,p
^.location
.fpureg
)))
339 exprasmlist
^.concat(new(paicpu
,op_reg(A_FNEG
,S_FX
,p
^.location
.fpureg
)));
342 { emitoverflowcheck;}
346 {*****************************************************************************
348 *****************************************************************************}
350 procedure secondnot(var p
: ptree
);
353 flagsinvers
: array[F_E
..F_BE
] of tresflags
=
354 (F_NE
,F_E
,F_LE
,F_GE
,F_L
,F_G
,F_NC
,F_C
,
361 if (p
^.resulttype
^.deftype
=orddef
) and
362 (porddef(p
^.resulttype
)^.typ
=bool8bit
) then
364 case p
^.location
.loc
of
367 truelabel
:=falselabel
;
370 maketojumpbool(p
^.left
);
372 truelabel
:=falselabel
;
377 p
^.location
.resflags
:=flagsinvers
[p
^.left
^.location
.resflags
];
381 p
^.location
.register:=p
^.left
^.location
.register;
382 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_EOR
,S_B
,1,p
^.location
.register)));
384 LOC_CREGISTER
: begin
386 p
^.location
.loc
:=LOC_REGISTER
;
387 p
^.location
.register:=getregister32
;
388 emit_reg_reg(A_MOVE
,S_B
,p
^.left
^.location
.register,
389 p
^.location
.register);
390 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_EOR
,S_B
,1,p
^.location
.register)));
392 LOC_REFERENCE
,LOC_MEM
: begin
394 del_reference(p
^.left
^.location
.reference
);
395 p
^.location
.loc
:=LOC_REGISTER
;
396 p
^.location
.register:=getregister32
;
397 if p
^.left
^.location
.loc
=LOC_CREGISTER
then
398 emit_reg_reg(A_MOVE
,S_B
,p
^.left
^.location
.register,
399 p
^.location
.register)
401 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_B
,
402 newreference(p
^.left
^.location
.reference
),
403 p
^.location
.register)));
404 exprasmlist
^.concat(new(paicpu
,op_const_reg(A_EOR
,S_B
,1,p
^.location
.register)));
411 p
^.location
.loc
:=LOC_REGISTER
;
413 case p
^.left
^.location
.loc
of
415 p
^.location
.register:=p
^.left
^.location
.register;
416 exprasmlist
^.concat(new(paicpu
,op_reg(A_NOT
,S_L
,p
^.location
.register)));
418 LOC_CREGISTER
: begin
419 p
^.location
.register:=getregister32
;
420 emit_reg_reg(A_MOVE
,S_L
,p
^.left
^.location
.register,
421 p
^.location
.register);
422 exprasmlist
^.concat(new(paicpu
,op_reg(A_NOT
,S_L
,p
^.location
.register)));
424 LOC_REFERENCE
,LOC_MEM
:
426 del_reference(p
^.left
^.location
.reference
);
427 p
^.location
.register:=getregister32
;
428 exprasmlist
^.concat(new(paicpu
,op_ref_reg(A_MOVE
,S_L
,
429 newreference(p
^.left
^.location
.reference
),
430 p
^.location
.register)));
431 exprasmlist
^.concat(new(paicpu
,op_reg(A_NOT
,S_L
,p
^.location
.register)));
434 {if p^.left^.location.loc=loc_register then
435 p^.location.register:=p^.left^.location.register
438 del_locref(p^.left^.location);
439 p^.location.register:=getregister32;
440 exprasmlist^.concat(new(paicpu,op_loc_reg(A_MOV,S_L,
442 p^.location.register)));
444 exprasmlist^.concat(new(paicpu,op_reg(A_NOT,S_L,p^.location.register)));}
452 Revision 1.1 2002/02/19 08:21:49 sasu
455 Revision 1.1 2000/07/13 06:29:46 michael
458 Revision 1.8 2000/02/09 13:22:49 peter
461 Revision 1.7 2000/01/07 01:14:22 peter
462 * updated copyright to 2000
464 Revision 1.6 1999/11/18 15:34:44 pierre
465 * Notes/Hints for local syms changed to
466 Set_varstate function
468 Revision 1.5 1999/09/16 23:05:51 florian
469 * m68k compiler is again compilable (only gas writer, no assembler reader)