* src/vm/exceptions.c (exceptions_handle_exception) [__S390__]: Synchronization objec...
[cacao.git] / src / vm / jit / s390 / emit.c
1 /* src/vm/jit/s390/emit.c - s390 code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: emit.c 8296 2007-08-11 22:38:38Z pm $
26
27 */
28
29 #include "config.h"
30
31 #include <assert.h>
32 #include <stdint.h>
33
34 #include "mm/memory.h"
35 #if defined(ENABLE_THREADS)
36 # include "threads/native/lock.h"
37 #endif
38 #include "vm/builtin.h"
39 #include "vm/exceptions.h"
40 #include "vm/global.h"
41 #include "vm/jit/abi.h"
42 #include "vm/jit/abi-asm.h"
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/codegen-common.h"
45 #include "vm/jit/emit-common.h"
46 #include "vm/jit/jit.h"
47 #include "vm/jit/patcher-common.h"
48 #include "vm/jit/replace.h"
49 #include "vm/jit/s390/codegen.h"
50 #include "vm/jit/s390/emit.h"
51 #include "vm/jit/s390/md-abi.h"
52 #include "vm/types.h"
53 #include "vmcore/options.h"
54
55 /* emit_load *******************************************************************
56
57    Emits a possible load of an operand.
58
59 *******************************************************************************/
60
61 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
62 {
63         codegendata *cd;
64         s4           disp;
65         s4           reg;
66
67         /* get required compiler data */
68
69         cd = jd->cd;
70
71         if (IS_INMEMORY(src->flags)) {
72                 COUNT_SPILLS;
73
74                 disp = src->vv.regoff;
75
76                 if (IS_FLT_DBL_TYPE(src->type)) {
77                         if (IS_2_WORD_TYPE(src->type))
78                                 M_DLD(tempreg, REG_SP, disp);
79                         else
80                                 M_FLD(tempreg, REG_SP, disp);
81                 }
82                 else {
83                         if (IS_2_WORD_TYPE(src->type))
84                                 M_LLD(tempreg, REG_SP, disp);
85                         else
86                                 M_ILD(tempreg, REG_SP, disp);
87                 }
88
89                 reg = tempreg;
90         }
91         else
92                 reg = src->vv.regoff;
93
94         return reg;
95 }
96
97
98 /* emit_store ******************************************************************
99
100    This function generates the code to store the result of an
101    operation back into a spilled pseudo-variable.  If the
102    pseudo-variable has not been spilled in the first place, this
103    function will generate nothing.
104     
105 *******************************************************************************/
106
107 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
108 {
109         codegendata *cd;
110
111         /* get required compiler data */
112
113         cd = jd->cd;
114
115         if (IS_INMEMORY(dst->flags)) {
116                 COUNT_SPILLS;
117
118                 if (IS_FLT_DBL_TYPE(dst->type)) {
119                         if (IS_2_WORD_TYPE(dst->type))
120                                 M_DST(d, REG_SP, dst->vv.regoff);
121                         else
122                                 M_FST(d, REG_SP, dst->vv.regoff);
123                 }
124                 else {
125                         if (IS_2_WORD_TYPE(dst->type))
126                                 M_LST(d, REG_SP, dst->vv.regoff);
127                         else
128                                 M_IST(d, REG_SP, dst->vv.regoff);
129                 }
130         }
131 }
132
133
134 /* emit_copy *******************************************************************
135
136    Generates a register/memory to register/memory copy.
137
138 *******************************************************************************/
139
140 void emit_copy(jitdata *jd, instruction *iptr)
141 {
142         codegendata *cd;
143         varinfo     *src;
144         varinfo     *dst;
145         s4           s1, d;
146
147         /* get required compiler data */
148
149         cd = jd->cd;
150
151         /* get source and destination variables */
152
153         src = VAROP(iptr->s1);
154         dst = VAROP(iptr->dst);
155
156         if ((src->vv.regoff != dst->vv.regoff) ||
157                 ((src->flags ^ dst->flags) & INMEMORY)) {
158
159                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
160                         /* emit nothing, as the value won't be used anyway */
161                         return;
162                 }
163
164                 /* If one of the variables resides in memory, we can eliminate
165                    the register move from/to the temporary register with the
166                    order of getting the destination register and the load. */
167
168                 if (IS_INMEMORY(src->flags)) {
169                         if (IS_FLT_DBL_TYPE(dst->type)) {
170                                 d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
171                         } else {
172                                 if (IS_2_WORD_TYPE(dst->type)) {
173                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
174                                 } else {
175                                         d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
176                                 }
177                         }
178                         s1 = emit_load(jd, iptr, src, d);
179                 }
180                 else {
181                         if (IS_FLT_DBL_TYPE(src->type)) {
182                                 s1 = emit_load(jd, iptr, src, REG_FTMP1);
183                         } else {
184                                 if (IS_2_WORD_TYPE(src->type)) {
185                                         s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
186                                 } else {
187                                         s1 = emit_load(jd, iptr, src, REG_ITMP1);
188                                 }
189                         }
190                         d = codegen_reg_of_var(iptr->opc, dst, s1);
191                 }
192
193                 if (s1 != d) {
194                         if (IS_FLT_DBL_TYPE(src->type)) {
195                                 M_FMOV(s1, d);
196                         } else {
197                                 if (IS_2_WORD_TYPE(src->type)) {
198                                         M_LNGMOVE(s1, d);
199                                 } else {
200                                         M_MOV(s1, d);
201                                 }
202                         }
203                 }
204
205                 emit_store(jd, iptr, dst, d);
206         }
207 }
208
209 /* emit_trap *******************************************************************
210
211    Emit a trap instruction and return the original machine code.
212
213 *******************************************************************************/
214
215 uint32_t emit_trap(codegendata *cd)
216 {
217         uint32_t mcode;
218
219         /* Get machine code which is patched back in later. The
220            trap is 2 bytes long. */
221
222         mcode = *((u2 *) cd->mcodeptr);
223
224         M_ILL(EXCEPTION_HARDWARE_PATCHER);
225
226         return mcode;
227 }
228
229
230 /* emit_verbosecall_enter ******************************************************
231
232    Generates the code for the call trace.
233
234 *******************************************************************************/
235
236 #if !defined(NDEBUG)
237 void emit_verbosecall_enter(jitdata *jd)
238 {
239         
240         methodinfo   *m;
241         codegendata  *cd;
242         methoddesc   *md;
243         s4            i, j, k;
244         s4            stackframesize, off, foff, aoff, doff, t, iargctr, fargctr, disp;
245
246         /* get required compiler data */
247
248         m  = jd->m;
249         cd = jd->cd;
250
251         md = m->parseddesc;
252
253         /* mark trace code */
254
255         M_NOP;
256
257         stackframesize = 
258                 (6 * 8) + /* s8 on stack parameters x 6 */
259                 (1 * 4) + /* methodinfo on stack parameter */
260                 (ARG_CNT * 8) +
261                 (TMP_CNT * 8) 
262                 ;
263
264         M_ASUB_IMM(stackframesize, REG_SP); /* allocate stackframe */
265
266         /* save argument registers */
267
268         off = (6 * 8) + (1 * 4);
269
270         for (i = 0; i < INT_ARG_CNT; i++, off += 8)
271                 M_IST(abi_registers_integer_argument[i], REG_SP, off);
272
273         for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
274                 M_DST(abi_registers_float_argument[i], REG_SP, off);
275
276         /* save temporary registers for leaf methods */
277
278         if (jd->isleafmethod) {
279                 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
280                         M_LST(abi_registers_integer_temporary[i], REG_SP, off);
281
282                 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
283                         M_DST(abi_registers_float_temporary[i], REG_SP, off);
284         }
285
286         /* Load arguments to new locations */
287
288         /* First move all arguments to stack
289          *
290          * (s8) a7
291          * (s8) a2
292          *   ...
293          * (s8) a1 \ Auxilliary stack frame
294          * (s8) a0 /
295          * ------- <---- SP
296          */
297
298         M_ASUB_IMM(2 * 8, REG_SP);
299         
300         /* offset to where first integer arg is saved on stack */
301         off = (2 * 8) + (6 * 8) + (1 * 4); 
302         /* offset to where first float arg is saved on stack */
303         foff = off + (INT_ARG_CNT * 8); 
304         /* offset to where first argument is passed on stack */
305         aoff = (2 * 8) + stackframesize + (cd->stackframesize * 8);
306         /* offset to destination on stack */
307         doff = 0; 
308
309         iargctr = fargctr = 0;
310
311         ICONST(REG_ITMP1, 0);
312
313         for (i = 0; i < md->paramcount && i < 8; i++) {
314                 t = md->paramtypes[i].type;
315
316                 M_IST(REG_ITMP1, REG_SP, doff);
317                 M_IST(REG_ITMP1, REG_SP, doff + 4);
318
319                 if (IS_FLT_DBL_TYPE(t)) {
320                         if (fargctr < 2) { /* passed in register */
321                                 N_STD(abi_registers_float_argument[fargctr], doff, RN, REG_SP);
322                                 fargctr += 1;
323                         } else { /* passed on stack */
324                                 /*
325                                 if (IS_2_WORD_TYPE(t)) {
326                                         N_MVC(doff, 8, REG_SP, aoff, REG_SP);
327                                 } else {
328                                         N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
329                                 }
330                                 */
331                                 N_MVC(doff, 8, REG_SP, aoff, REG_SP);
332                                 aoff += 8;
333                         }
334                 } else {
335                         if (IS_2_WORD_TYPE(t)) {
336                                 if (iargctr < 4) { /* passed in 2 registers */
337                                         N_STM(REG_A0 + iargctr, REG_A0 + iargctr + 1, doff, REG_SP);
338                                         iargctr += 2;
339                                 } else { /* passed on stack */
340                                         N_MVC(doff, 8, REG_SP, aoff, REG_SP);
341                                         aoff += 8;
342                                 }
343                         } else {
344                                 if (iargctr < 5) { /* passed in register */
345                                         N_ST(REG_A0 + iargctr, doff + 4, RN, REG_SP);
346                                         iargctr += 1;
347                                 } else { /* passed on stack */
348                                         N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
349                                         aoff += 8;
350                                 }
351                         }
352                 }
353
354                 doff += 8;
355         }
356
357         /* Now move a0 and a1 to registers
358          *
359          * (s8) a7
360          *   ...
361          * (s8) a2
362          * ------- <- SP
363          * (s8) a0 ==> a0, a1
364          * (s8) a1 ==> a2, a3
365          */
366
367         N_LM(REG_A0, REG_A1, 0, REG_SP);
368         N_LM(REG_A2, REG_A3, 8, REG_SP);
369
370         M_AADD_IMM(2 * 8, REG_SP);
371
372         /* Finally load methodinfo argument */
373
374         disp = dseg_add_address(cd, m);
375         M_ALD_DSEG(REG_ITMP2, disp);    
376         M_AST(REG_ITMP2, REG_SP, 6 * 8);
377
378         /* Call builtin_verbosecall_enter */
379
380         disp = dseg_add_address(cd, builtin_verbosecall_enter);
381         M_ALD_DSEG(REG_ITMP2, disp);
382         M_ASUB_IMM(96, REG_SP);
383         M_CALL(REG_ITMP2);
384         M_AADD_IMM(96, REG_SP);
385
386         /* restore argument registers */
387
388         off = (6 * 8) + (1 * 4);
389
390         for (i = 0; i < INT_ARG_CNT; i++, off += 8)
391                 M_ILD(abi_registers_integer_argument[i], REG_SP, off);
392
393         for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
394                 M_DLD(abi_registers_float_argument[i], REG_SP, off);
395
396         /* restore temporary registers for leaf methods */
397
398         if (jd->isleafmethod) {
399                 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
400                         M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
401
402                 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
403                         M_DLD(abi_registers_float_temporary[i], REG_SP, off);
404         }
405
406         /* remove stackframe */
407
408         M_AADD_IMM(stackframesize, REG_SP);
409
410         /* mark trace code */
411
412         M_NOP;
413 }
414 #endif /* !defined(NDEBUG) */
415
416
417 /* emit_verbosecall_exit *******************************************************
418
419    Generates the code for the call trace.
420
421 *******************************************************************************/
422
423 #if !defined(NDEBUG)
424 void emit_verbosecall_exit(jitdata *jd)
425 {
426         methodinfo   *m;
427         codegendata  *cd;
428         registerdata *rd;
429         s4            disp;
430
431         /* get required compiler data */
432
433         m  = jd->m;
434         cd = jd->cd;
435         rd = jd->rd;
436
437         /* mark trace code */
438
439         M_NOP;
440
441         M_ASUB_IMM(2 * 8, REG_SP);
442
443         N_STM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
444         M_DST(REG_FRESULT, REG_SP, 1 * 8);
445
446         if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) {
447                 /* (REG_A0, REG_A1) == (REG_RESULT, REG_RESULT2), se no need to move */
448         } else {
449                 M_INTMOVE(REG_RESULT, REG_A1);
450                 ICONST(REG_A0, 0);
451         }
452
453         disp = dseg_add_address(cd, m);
454         M_ALD_DSEG(REG_A2, disp);
455
456         /* REG_FRESULT is REG_FA0, so no need to move */
457         M_FLTMOVE(REG_FRESULT, REG_FA1);
458
459         disp = dseg_add_address(cd, builtin_verbosecall_exit);
460         M_ALD_DSEG(REG_ITMP1, disp);
461         M_ASUB_IMM(96, REG_SP);
462         M_CALL(REG_ITMP1);
463         M_AADD_IMM(96, REG_SP);
464
465         N_LM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
466         M_DLD(REG_FRESULT, REG_SP, 1 * 8);
467
468         M_AADD_IMM(2 * 8, REG_SP);
469
470         /* mark trace code */
471
472         M_NOP;
473 }
474 #endif /* !defined(NDEBUG) */
475
476
477 /* emit_load_high **************************************************************
478
479    Emits a possible load of the high 32-bits of an operand.
480
481 *******************************************************************************/
482
483 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
484 {
485         codegendata  *cd;
486         s4            disp;
487         s4            reg;
488
489         assert(src->type == TYPE_LNG);
490
491         /* get required compiler data */
492
493         cd = jd->cd;
494
495         if (IS_INMEMORY(src->flags)) {
496                 COUNT_SPILLS;
497
498                 disp = src->vv.regoff;
499
500                 M_ILD(tempreg, REG_SP, disp);
501
502                 reg = tempreg;
503         }
504         else
505                 reg = GET_HIGH_REG(src->vv.regoff);
506
507         return reg;
508 }
509
510 /* emit_load_low ***************************************************************
511
512    Emits a possible load of the low 32-bits of an operand.
513
514 *******************************************************************************/
515
516 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
517 {
518         codegendata  *cd;
519         s4            disp;
520         s4            reg;
521
522         assert(src->type == TYPE_LNG);
523
524         /* get required compiler data */
525
526         cd = jd->cd;
527
528         if (IS_INMEMORY(src->flags)) {
529                 COUNT_SPILLS;
530
531                 disp = src->vv.regoff;
532
533                 M_ILD(tempreg, REG_SP, disp + 4);
534
535                 reg = tempreg;
536         }
537         else
538                 reg = GET_LOW_REG(src->vv.regoff);
539
540         return reg;
541 }
542
543 s4 emit_load_s1_notzero(jitdata *jd, instruction *iptr, s4 tempreg) {
544         codegendata *cd = jd->cd;
545         s4 reg = emit_load_s1(jd, iptr, tempreg);
546         if (reg == 0) {
547                 M_MOV(reg, tempreg);
548                 return tempreg;
549         } else {
550                 return reg;
551         }
552 }
553
554 s4 emit_load_s2_notzero(jitdata *jd, instruction *iptr, s4 tempreg) {
555         codegendata *cd = jd->cd;
556         s4 reg = emit_load_s2(jd, iptr, tempreg);
557         if (reg == 0) {
558                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
559                         M_FMOV(reg, tempreg);
560                 } else {
561                         M_MOV(reg, tempreg);
562                 }
563                 return tempreg;
564         } else {
565                 return reg;
566         }
567 }
568
569 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
570         codegendata *cd = jd->cd;
571         s4 reg = emit_load_s1(jd, iptr, tempreg);
572         if (reg == notreg) {
573                 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
574                         M_FMOV(reg, tempreg);
575                 } else {
576                         M_MOV(reg, tempreg);
577                 }
578                 return tempreg;
579         } else {
580                 return reg;
581         }
582 }
583
584 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
585         codegendata *cd = jd->cd;
586         s4 reg = emit_load_s2(jd, iptr, tempreg);
587         if (reg == notreg) {
588                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
589                         M_FMOV(reg, tempreg);
590                 } else {
591                         M_MOV(reg, tempreg);
592                 }
593                 return tempreg;
594         } else {
595                 return reg;
596         }
597 }
598
599 s4 emit_alloc_dst_even_odd(jitdata *jd, instruction *iptr, s4 htmpreg, s4 ltmpreg, s4 breg) {
600         codegendata *cd;
601         s4           hr, lr;
602         varinfo     *dst;
603
604         /* (r0, r1)    
605          * (r2, r3)
606          * (r4, r5)
607          * (r6, r7)
608          * (r8, r9)
609          * (r10, r11)
610          * (r12, r13) Illegal, because r13 is PV
611          * (r14, r15) Illegal, because r15 is SP
612          */
613
614         cd = jd->cd;
615         dst = VAROP(iptr->dst);
616
617         if (IS_INMEMORY(dst->flags)) {
618                 if (! IS_REG_ITMP(ltmpreg)) {
619                         M_INTMOVE(ltmpreg, breg);
620                 }
621                 if (! IS_REG_ITMP(htmpreg)) {
622                         M_INTMOVE(htmpreg, breg);
623                 }
624                 return PACK_REGS(ltmpreg, htmpreg);
625         } else {
626                 hr = GET_HIGH_REG(dst->vv.regoff);
627                 lr = GET_LOW_REG(dst->vv.regoff);
628                 if (((hr % 2) == 0) && lr == (hr + 1)) {
629                         /* the result is already in a even-odd pair */
630                         return dst->vv.regoff;                  
631                 } else if (((hr % 2) == 0) && (hr < R12)) {
632                         /* the high register is at a even position */
633                         M_INTMOVE(hr + 1, breg);
634                         return PACK_REGS(hr + 1, hr);
635                 } else if (((lr % 2) == 1) && (lr < R12)) {
636                         /* the low register is at a odd position */
637                         M_INTMOVE(lr - 1, breg);
638                         return PACK_REGS(lr, lr - 1);
639                 } else {
640                         /* no way to create an even-odd pair by 1 copy operation,
641                          * Use the temporary register pair.
642                          */
643                         if (! IS_REG_ITMP(ltmpreg)) {
644                                 M_INTMOVE(ltmpreg, breg);
645                         }
646                         if (! IS_REG_ITMP(htmpreg)) {
647                                 M_INTMOVE(htmpreg, breg);
648                         }
649                         return PACK_REGS(ltmpreg, htmpreg);
650                 }
651         }
652 }
653
654 void emit_restore_dst_even_odd(jitdata *jd, instruction *iptr, s4 htmpreg, s4 ltmpreg, s4 breg) {
655         codegendata *cd;
656         s4           hr, lr;
657         varinfo     *dst;
658
659         cd = jd->cd;
660         dst = VAROP(iptr->dst);
661
662         if (IS_INMEMORY(dst->flags)) {
663                 if (! IS_REG_ITMP(ltmpreg)) {
664                         M_INTMOVE(breg, ltmpreg);
665                 }
666                 if (! IS_REG_ITMP(htmpreg)) {
667                         M_INTMOVE(breg, htmpreg);
668                 }
669         } else {
670                 hr = GET_HIGH_REG(dst->vv.regoff);
671                 lr = GET_LOW_REG(dst->vv.regoff);
672                 if (((hr % 2) == 0) && lr == (hr + 1)) {
673                         return;
674                 } else if (((hr % 2) == 0) && (hr < R12)) {
675                         M_INTMOVE(breg, hr + 1);
676                 } else if (((lr % 2) == 1) && (lr < R12)) {
677                         M_INTMOVE(breg, lr - 1);
678                 } else {
679                         if (! IS_REG_ITMP(ltmpreg)) {
680                                 M_INTMOVE(breg, ltmpreg);
681                         }
682                         if (! IS_REG_ITMP(htmpreg)) {
683                                 M_INTMOVE(breg, htmpreg);
684                         }
685                 }
686         }
687 }
688
689 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
690         codegendata *cd;
691         varinfo *dst;
692         cd = jd->cd;
693         dst = VAROP(iptr->dst);
694         if (! IS_INMEMORY(dst->flags)) {
695                 if (dst->vv.regoff != dtmpreg) {
696                         if (IS_FLT_DBL_TYPE(dst->type)) {
697                                 M_FLTMOVE(dtmpreg, dst->vv.regoff);
698                         } else if (IS_2_WORD_TYPE(dst->type)) {
699                                 M_LNGMOVE(dtmpreg, dst->vv.regoff);
700                         } else {
701                                 M_INTMOVE(dtmpreg, dst->vv.regoff);
702                         }
703                 }
704         }
705 }
706
707 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
708
709         s4 branchdisp = disp;
710         s4 branchmpc;
711         u1 *ref;
712
713         if (N_VALID_BRANCH(branchdisp)) {
714
715                 /* valid displacement */
716
717                 switch (condition) {
718                         case BRANCH_EQ:
719                                 M_BEQ(branchdisp);
720                                 break;
721                         case BRANCH_NE:
722                                 M_BNE(branchdisp);
723                                 break;
724                         case BRANCH_LT:
725                                 M_BLT(branchdisp);
726                                 break;
727                         case BRANCH_GE:
728                                 M_BGE(branchdisp);
729                                 break;
730                         case BRANCH_GT:
731                                 M_BGT(branchdisp);
732                                 break;
733                         case BRANCH_LE:
734                                 M_BLE(branchdisp);
735                                 break;
736                         case BRANCH_UNCONDITIONAL:
737                                 M_BR(branchdisp);
738                                 break;
739                         default:
740                                 vm_abort("emit_branch: unknown condition %d", condition);
741                 }
742         } else {
743
744                 /* If LONGBRANCHES is not set, the flag and the error flag */
745
746                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
747                         cd->flags |= (CODEGENDATA_FLAG_ERROR |
748                                 CODEGENDATA_FLAG_LONGBRANCHES);
749                 }
750
751                 /* If error flag is set, do nothing. The method has to be recompiled. */
752
753                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
754                         return;
755                 }
756
757                 /* Patch the displacement to branch over the actual branch manually
758                  * to not get yet more nops.
759                  */
760
761                 branchmpc = cd->mcodeptr - cd->mcodebase;
762                 ref = cd->mcodeptr;
763
764                 switch (condition) {
765                         case BRANCH_EQ:
766                                 M_BNE(0);
767                                 break;
768                         case BRANCH_NE:
769                                 M_BEQ(0);
770                                 break;
771                         case BRANCH_LT:
772                                 M_BGE(0);
773                                 break;
774                         case BRANCH_GE:
775                                 M_BLT(0);
776                                 break;
777                         case BRANCH_GT:
778                                 M_BLE(0);
779                                 break;
780                         case BRANCH_LE:
781                                 M_BGT(0);
782                                 break;
783                         case BRANCH_UNCONDITIONAL:
784                                 /* fall through, no displacement to patch */
785                                 ref = NULL;
786                                 break;
787                         default:
788                                 vm_abort("emit_branch: unknown condition %d", condition);
789                 }
790
791                 /* The actual long branch */
792
793                 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
794                 M_ILD_DSEG(REG_ITMP3, disp);
795                 M_AADD(REG_PV, REG_ITMP3);
796                 M_JMP(RN, REG_ITMP3);
797
798                 /* Patch back the displacement */
799
800                 if (ref != NULL) {
801                         *(u4 *)ref |= (u4)((cd->mcodeptr - ref) / 2);
802                 }
803         }
804 }
805
806 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) {
807         if (INSTRUCTION_MUST_CHECK(iptr)) {
808                 M_TEST(reg);
809                 M_BNE(SZ_BRC + SZ_ILL);
810                 M_ILL(EXCEPTION_HARDWARE_ARITHMETIC);
811         }
812 }
813
814 /* emit_arrayindexoutofbounds_check ********************************************
815
816    Emit a ArrayIndexOutOfBoundsException check.
817
818 *******************************************************************************/
819
820 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
821 {
822         if (INSTRUCTION_MUST_CHECK(iptr)) {
823                 /* Size is s4, >= 0
824                  * Do unsigned comparison to catch negative indexes.
825                  */
826                 N_CL(s2, OFFSET(java_arrayheader, size), RN, s1);
827         M_BLT(SZ_BRC + SZ_ILL);
828                 M_ILL2(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
829         }
830 }
831
832 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
833         if (INSTRUCTION_MUST_CHECK(iptr)) {
834                 if (reg != RN) {
835                         M_TEST(reg);
836                 }
837                 switch (condition) {
838                         case BRANCH_LE:
839                                 M_BGT(SZ_BRC + SZ_ILL);
840                                 break;
841                         case BRANCH_EQ:
842                                 M_BNE(SZ_BRC + SZ_ILL);
843                                 break;
844                         case BRANCH_GT:
845                                 M_BLE(SZ_BRC + SZ_ILL);
846                                 break;
847                         default:
848                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
849                 }
850                 M_ILL2(s1, EXCEPTION_HARDWARE_CLASSCAST);
851         }
852 }
853
854 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) {
855         if (INSTRUCTION_MUST_CHECK(iptr)) {
856                 M_TEST(reg);
857                 M_BNE(SZ_BRC + SZ_ILL);
858                 M_ILL(EXCEPTION_HARDWARE_NULLPOINTER);
859         }
860 }
861
862 void emit_exception_check(codegendata *cd, instruction *iptr) {
863         if (INSTRUCTION_MUST_CHECK(iptr)) {
864                 M_TEST(REG_RESULT);
865                 M_BNE(SZ_BRC + SZ_ILL);
866                 M_ILL(EXCEPTION_HARDWARE_EXCEPTION);
867         }
868 }
869
870 void emit_restore_pv(codegendata *cd) {
871         s4 offset, offset_imm;
872
873         /*
874         N_BASR(REG_PV, RN);
875         disp = (s4) (cd->mcodeptr - cd->mcodebase);
876         M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
877         */
878
879         /* If the offset from the method start does not fit into an immediate
880          * value, we can't put it into the data segment!
881          */
882
883         /* Displacement from start of method to here */
884
885         offset = (s4) (cd->mcodeptr - cd->mcodebase);
886         offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
887
888         if (N_VALID_IMM(offset_imm)) {
889                 /* Get program counter */
890                 N_BASR(REG_PV, RN);
891                 /* Substract displacement */
892                 M_AADD_IMM(offset_imm, REG_PV);
893         } else {
894                 /* Save program counter and jump over displacement in instruction flow */
895                 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
896                 /* Place displacement here */
897                 /* REG_PV points now exactly to this position */
898                 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
899                 /* Substract *(REG_PV) from REG_PV */
900                 N_A(REG_PV, 0, RN, REG_PV);
901         }
902 }
903
904 /*
905  * These are local overrides for various environment variables in Emacs.
906  * Please do not remove this and leave it at the end of the file, where
907  * Emacs will automagically detect them.
908  * ---------------------------------------------------------------------
909  * Local variables:
910  * mode: c
911  * indent-tabs-mode: t
912  * c-basic-offset: 4
913  * tab-width: 4
914  * End:
915  */