* src/vm/jit/emit-common.c (emit_patcher_traps): Added.
[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 8260 2007-08-06 12:19:01Z michi $
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 /* emit_replacement_stubs ******************************************************
230
231    Generates the code for the replacement stubs.
232
233 *******************************************************************************/
234 #if defined(ENABLE_REPLACEMENT)
235 void emit_replacement_stubs(jitdata *jd)
236 {
237         codegendata *cd;
238         codeinfo    *code;
239         rplpoint    *rplp;
240         s4           disp;
241         s4           i, remain;
242         u1          *savedmcodeptr;
243
244         /* get required compiler data */
245
246         cd   = jd->cd;
247         code = jd->code;
248
249         rplp = code->rplpoints;
250
251         /* store beginning of replacement stubs */
252
253         code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
254
255         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
256                 /* do not generate stubs for non-trappable points */
257
258                 if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
259                         continue;
260
261                 /* check code segment size */
262
263                 MCODECHECK(512);
264
265 #if !defined(NDEBUG)
266                 savedmcodeptr = cd->mcodeptr;
267 #endif
268
269                 /* create stack frame - 8-byte aligned */
270
271                 M_ASUB_IMM(REG_SP, 2 * 4);
272
273                 /* push address of `rplpoint` struct, will be used in asm_replacement_out */
274
275                 disp = dseg_add_address(cd, rplp);
276                 M_ALD_DSEG(REG_ITMP3, disp);
277                 M_AST(REG_ITMP3, REG_SP, 0 * 4);
278
279                 /* jump to replacement function */
280
281                 disp = dseg_add_functionptr(cd, asm_replacement_out);
282                 M_ALD_DSEG(REG_ITMP3, disp);
283                 M_JMP(RN, REG_ITMP3);
284
285                 assert((cd->mcodeptr - savedmcodeptr) <= REPLACEMENT_STUB_SIZE);
286
287                 /* pad with NOPs */
288
289                 for (remain = REPLACEMENT_STUB_SIZE - (cd->mcodeptr - savedmcodeptr); remain > 0;) {
290                         if (remain >= 4) {
291                                 M_NOP;
292                                 remain -= 4;
293                         } else {
294                                 M_NOP2;
295                                 remain -= 2;
296                         }
297                 }
298
299                 assert((cd->mcodeptr - savedmcodeptr) == REPLACEMENT_STUB_SIZE);
300         }
301 }
302 #endif
303
304 /* emit_verbosecall_enter ******************************************************
305
306    Generates the code for the call trace.
307
308 *******************************************************************************/
309
310 #if !defined(NDEBUG)
311 void emit_verbosecall_enter(jitdata *jd)
312 {
313         
314         methodinfo   *m;
315         codegendata  *cd;
316         methoddesc   *md;
317         s4            i, j, k;
318         s4            stackframesize, off, foff, aoff, doff, t, iargctr, fargctr, disp;
319
320         /* get required compiler data */
321
322         m  = jd->m;
323         cd = jd->cd;
324
325         md = m->parseddesc;
326
327         /* mark trace code */
328
329         M_NOP;
330
331         stackframesize = 
332                 (6 * 8) + /* s8 on stack parameters x 6 */
333                 (1 * 4) + /* methodinfo on stack parameter */
334                 (ARG_CNT * 8) +
335                 (TMP_CNT * 8) 
336                 ;
337
338         M_ASUB_IMM(stackframesize, REG_SP); /* allocate stackframe */
339
340         /* save argument registers */
341
342         off = (6 * 8) + (1 * 4);
343
344         for (i = 0; i < INT_ARG_CNT; i++, off += 8)
345                 M_IST(abi_registers_integer_argument[i], REG_SP, off);
346
347         for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
348                 M_DST(abi_registers_float_argument[i], REG_SP, off);
349
350         /* save temporary registers for leaf methods */
351
352         if (jd->isleafmethod) {
353                 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
354                         M_LST(abi_registers_integer_temporary[i], REG_SP, off);
355
356                 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
357                         M_DST(abi_registers_float_temporary[i], REG_SP, off);
358         }
359
360         /* Load arguments to new locations */
361
362         /* First move all arguments to stack
363          *
364          * (s8) a7
365          * (s8) a2
366          *   ...
367          * (s8) a1 \ Auxilliary stack frame
368          * (s8) a0 /
369          * ------- <---- SP
370          */
371
372         M_ASUB_IMM(2 * 8, REG_SP);
373         
374         /* offset to where first integer arg is saved on stack */
375         off = (2 * 8) + (6 * 8) + (1 * 4); 
376         /* offset to where first float arg is saved on stack */
377         foff = off + (INT_ARG_CNT * 8); 
378         /* offset to where first argument is passed on stack */
379         aoff = (2 * 8) + stackframesize + (cd->stackframesize * 4);
380         /* offset to destination on stack */
381         doff = 0; 
382
383         iargctr = fargctr = 0;
384
385         ICONST(REG_ITMP1, 0);
386
387         for (i = 0; i < md->paramcount && i < 8; i++) {
388                 t = md->paramtypes[i].type;
389
390                 M_IST(REG_ITMP1, REG_SP, doff);
391                 M_IST(REG_ITMP1, REG_SP, doff + 4);
392
393                 if (IS_FLT_DBL_TYPE(t)) {
394                         if (fargctr < 2) { /* passed in register */
395                                 N_STD(abi_registers_float_argument[fargctr], doff, RN, REG_SP);
396                                 fargctr += 1;
397                         } else { /* passed on stack */
398                                 if (IS_2_WORD_TYPE(t)) {
399                                         N_MVC(doff, 8, REG_SP, aoff, REG_SP);
400                                         aoff += 8;
401                                 } else {
402                                         N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
403                                         aoff += 4;
404                                 }
405                         }
406                 } else {
407                         if (IS_2_WORD_TYPE(t)) {
408                                 if (iargctr < 4) { /* passed in 2 registers */
409                                         N_STM(REG_A0 + iargctr, REG_A0 + iargctr + 1, doff, REG_SP);
410                                         iargctr += 2;
411                                 } else { /* passed on stack */
412                                         N_MVC(doff, 8, REG_SP, aoff, REG_SP);
413                                         aoff += 8;
414                                 }
415                         } else {
416                                 if (iargctr < 5) { /* passed in register */
417                                         N_ST(REG_A0 + iargctr, doff + 4, RN, REG_SP);
418                                         iargctr += 1;
419                                 } else { /* passed on stack */
420                                         N_MVC(doff + 4, 4, REG_SP, aoff, REG_SP);
421                                         aoff += 4;
422                                 }
423                         }
424                 }
425
426                 doff += 8;
427         }
428
429         /* Now move a0 and a1 to registers
430          *
431          * (s8) a7
432          *   ...
433          * (s8) a2
434          * ------- <- SP
435          * (s8) a0 ==> a0, a1
436          * (s8) a1 ==> a2, a3
437          */
438
439         N_LM(REG_A0, REG_A1, 0, REG_SP);
440         N_LM(REG_A2, REG_A3, 8, REG_SP);
441
442         M_AADD_IMM(2 * 8, REG_SP);
443
444         /* Finally load methodinfo argument */
445
446         disp = dseg_add_address(cd, m);
447         M_ALD_DSEG(REG_ITMP2, disp);    
448         M_AST(REG_ITMP2, REG_SP, 6 * 8);
449
450         /* Call builtin_verbosecall_enter */
451
452         disp = dseg_add_address(cd, builtin_verbosecall_enter);
453         M_ALD_DSEG(REG_ITMP2, disp);
454         M_ASUB_IMM(96, REG_SP);
455         M_CALL(REG_ITMP2);
456         M_AADD_IMM(96, REG_SP);
457
458         /* restore argument registers */
459
460         off = (6 * 8) + (1 * 4);
461
462         for (i = 0; i < INT_ARG_CNT; i++, off += 8)
463                 M_ILD(abi_registers_integer_argument[i], REG_SP, off);
464
465         for (i = 0; i < FLT_ARG_CNT; i++, off += 8)
466                 M_DLD(abi_registers_float_argument[i], REG_SP, off);
467
468         /* restore temporary registers for leaf methods */
469
470         if (jd->isleafmethod) {
471                 for (i = 0; i < INT_TMP_CNT; i++, off += 8)
472                         M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
473
474                 for (i = 0; i < FLT_TMP_CNT; i++, off += 8)
475                         M_DLD(abi_registers_float_temporary[i], REG_SP, off);
476         }
477
478         /* remove stackframe */
479
480         M_AADD_IMM(stackframesize, REG_SP);
481
482         /* mark trace code */
483
484         M_NOP;
485 }
486 #endif /* !defined(NDEBUG) */
487
488
489 /* emit_verbosecall_exit *******************************************************
490
491    Generates the code for the call trace.
492
493 *******************************************************************************/
494
495 #if !defined(NDEBUG)
496 void emit_verbosecall_exit(jitdata *jd)
497 {
498         methodinfo   *m;
499         codegendata  *cd;
500         registerdata *rd;
501         s4            disp;
502
503         /* get required compiler data */
504
505         m  = jd->m;
506         cd = jd->cd;
507         rd = jd->rd;
508
509         /* mark trace code */
510
511         M_NOP;
512
513         M_ASUB_IMM(2 * 8, REG_SP);
514
515         N_STM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
516         M_DST(REG_FRESULT, REG_SP, 1 * 8);
517
518         if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) {
519                 /* (REG_A0, REG_A1) == (REG_RESULT, REG_RESULT2), se no need to move */
520         } else {
521                 M_INTMOVE(REG_RESULT, REG_A1);
522                 ICONST(REG_A0, 0);
523         }
524
525         disp = dseg_add_address(cd, m);
526         M_ALD_DSEG(REG_A2, disp);
527
528         /* REG_FRESULT is REG_FA0, so no need to move */
529         M_FLTMOVE(REG_FRESULT, REG_FA1);
530
531         disp = dseg_add_address(cd, builtin_verbosecall_exit);
532         M_ALD_DSEG(REG_ITMP1, disp);
533         M_ASUB_IMM(96, REG_SP);
534         M_CALL(REG_ITMP1);
535         M_AADD_IMM(96, REG_SP);
536
537         N_LM(REG_RESULT, REG_RESULT2, 0 * 8, REG_SP);
538         M_DLD(REG_FRESULT, REG_SP, 1 * 8);
539
540         M_AADD_IMM(2 * 8, REG_SP);
541
542         /* mark trace code */
543
544         M_NOP;
545 }
546 #endif /* !defined(NDEBUG) */
547
548
549 /* emit_load_high **************************************************************
550
551    Emits a possible load of the high 32-bits of an operand.
552
553 *******************************************************************************/
554
555 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
556 {
557         codegendata  *cd;
558         s4            disp;
559         s4            reg;
560
561         assert(src->type == TYPE_LNG);
562
563         /* get required compiler data */
564
565         cd = jd->cd;
566
567         if (IS_INMEMORY(src->flags)) {
568                 COUNT_SPILLS;
569
570                 disp = src->vv.regoff;
571
572                 M_ILD(tempreg, REG_SP, disp);
573
574                 reg = tempreg;
575         }
576         else
577                 reg = GET_HIGH_REG(src->vv.regoff);
578
579         return reg;
580 }
581
582 /* emit_load_low ***************************************************************
583
584    Emits a possible load of the low 32-bits of an operand.
585
586 *******************************************************************************/
587
588 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
589 {
590         codegendata  *cd;
591         s4            disp;
592         s4            reg;
593
594         assert(src->type == TYPE_LNG);
595
596         /* get required compiler data */
597
598         cd = jd->cd;
599
600         if (IS_INMEMORY(src->flags)) {
601                 COUNT_SPILLS;
602
603                 disp = src->vv.regoff;
604
605                 M_ILD(tempreg, REG_SP, disp + 4);
606
607                 reg = tempreg;
608         }
609         else
610                 reg = GET_LOW_REG(src->vv.regoff);
611
612         return reg;
613 }
614
615 s4 emit_load_s1_notzero(jitdata *jd, instruction *iptr, s4 tempreg) {
616         codegendata *cd = jd->cd;
617         s4 reg = emit_load_s1(jd, iptr, tempreg);
618         if (reg == 0) {
619                 M_MOV(reg, tempreg);
620                 return tempreg;
621         } else {
622                 return reg;
623         }
624 }
625
626 s4 emit_load_s2_notzero(jitdata *jd, instruction *iptr, s4 tempreg) {
627         codegendata *cd = jd->cd;
628         s4 reg = emit_load_s2(jd, iptr, tempreg);
629         if (reg == 0) {
630                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
631                         M_FMOV(reg, tempreg);
632                 } else {
633                         M_MOV(reg, tempreg);
634                 }
635                 return tempreg;
636         } else {
637                 return reg;
638         }
639 }
640
641 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
642         codegendata *cd = jd->cd;
643         s4 reg = emit_load_s1(jd, iptr, tempreg);
644         if (reg == notreg) {
645                 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
646                         M_FMOV(reg, tempreg);
647                 } else {
648                         M_MOV(reg, tempreg);
649                 }
650                 return tempreg;
651         } else {
652                 return reg;
653         }
654 }
655
656 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
657         codegendata *cd = jd->cd;
658         s4 reg = emit_load_s2(jd, iptr, tempreg);
659         if (reg == notreg) {
660                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
661                         M_FMOV(reg, tempreg);
662                 } else {
663                         M_MOV(reg, tempreg);
664                 }
665                 return tempreg;
666         } else {
667                 return reg;
668         }
669 }
670
671 s4 emit_alloc_dst_even_odd(jitdata *jd, instruction *iptr, s4 htmpreg, s4 ltmpreg, s4 breg) {
672         codegendata *cd;
673         s4           hr, lr;
674         varinfo     *dst;
675
676         /* (r0, r1)    
677          * (r2, r3)
678          * (r4, r5)
679          * (r6, r7)
680          * (r8, r9)
681          * (r10, r11)
682          * (r12, r13) Illegal, because r13 is PV
683          * (r14, r15) Illegal, because r15 is SP
684          */
685
686         cd = jd->cd;
687         dst = VAROP(iptr->dst);
688
689         if (IS_INMEMORY(dst->flags)) {
690                 if (! IS_REG_ITMP(ltmpreg)) {
691                         M_INTMOVE(ltmpreg, breg);
692                 }
693                 if (! IS_REG_ITMP(htmpreg)) {
694                         M_INTMOVE(htmpreg, breg);
695                 }
696                 return PACK_REGS(ltmpreg, htmpreg);
697         } else {
698                 hr = GET_HIGH_REG(dst->vv.regoff);
699                 lr = GET_LOW_REG(dst->vv.regoff);
700                 if (((hr % 2) == 0) && lr == (hr + 1)) {
701                         /* the result is already in a even-odd pair */
702                         return dst->vv.regoff;                  
703                 } else if (((hr % 2) == 0) && (hr < R12)) {
704                         /* the high register is at a even position */
705                         M_INTMOVE(hr + 1, breg);
706                         return PACK_REGS(hr + 1, hr);
707                 } else if (((lr % 2) == 1) && (lr < R12)) {
708                         /* the low register is at a odd position */
709                         M_INTMOVE(lr - 1, breg);
710                         return PACK_REGS(lr, lr - 1);
711                 } else {
712                         /* no way to create an even-odd pair by 1 copy operation,
713                          * Use the temporary register pair.
714                          */
715                         if (! IS_REG_ITMP(ltmpreg)) {
716                                 M_INTMOVE(ltmpreg, breg);
717                         }
718                         if (! IS_REG_ITMP(htmpreg)) {
719                                 M_INTMOVE(htmpreg, breg);
720                         }
721                         return PACK_REGS(ltmpreg, htmpreg);
722                 }
723         }
724 }
725
726 void emit_restore_dst_even_odd(jitdata *jd, instruction *iptr, s4 htmpreg, s4 ltmpreg, s4 breg) {
727         codegendata *cd;
728         s4           hr, lr;
729         varinfo     *dst;
730
731         cd = jd->cd;
732         dst = VAROP(iptr->dst);
733
734         if (IS_INMEMORY(dst->flags)) {
735                 if (! IS_REG_ITMP(ltmpreg)) {
736                         M_INTMOVE(breg, ltmpreg);
737                 }
738                 if (! IS_REG_ITMP(htmpreg)) {
739                         M_INTMOVE(breg, htmpreg);
740                 }
741         } else {
742                 hr = GET_HIGH_REG(dst->vv.regoff);
743                 lr = GET_LOW_REG(dst->vv.regoff);
744                 if (((hr % 2) == 0) && lr == (hr + 1)) {
745                         return;
746                 } else if (((hr % 2) == 0) && (hr < R12)) {
747                         M_INTMOVE(breg, hr + 1);
748                 } else if (((lr % 2) == 1) && (lr < R12)) {
749                         M_INTMOVE(breg, lr - 1);
750                 } else {
751                         if (! IS_REG_ITMP(ltmpreg)) {
752                                 M_INTMOVE(breg, ltmpreg);
753                         }
754                         if (! IS_REG_ITMP(htmpreg)) {
755                                 M_INTMOVE(breg, htmpreg);
756                         }
757                 }
758         }
759 }
760
761 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
762         codegendata *cd;
763         varinfo *dst;
764         cd = jd->cd;
765         dst = VAROP(iptr->dst);
766         if (! IS_INMEMORY(dst->flags)) {
767                 if (dst->vv.regoff != dtmpreg) {
768                         if (IS_FLT_DBL_TYPE(dst->type)) {
769                                 M_FLTMOVE(dtmpreg, dst->vv.regoff);
770                         } else if (IS_2_WORD_TYPE(dst->type)) {
771                                 M_LNGMOVE(dtmpreg, dst->vv.regoff);
772                         } else {
773                                 M_INTMOVE(dtmpreg, dst->vv.regoff);
774                         }
775                 }
776         }
777 }
778
779 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
780
781         s4 branchdisp = disp;
782         s4 branchmpc;
783         u1 *ref;
784
785         if (N_VALID_BRANCH(branchdisp)) {
786
787                 /* valid displacement */
788
789                 switch (condition) {
790                         case BRANCH_EQ:
791                                 M_BEQ(branchdisp);
792                                 break;
793                         case BRANCH_NE:
794                                 M_BNE(branchdisp);
795                                 break;
796                         case BRANCH_LT:
797                                 M_BLT(branchdisp);
798                                 break;
799                         case BRANCH_GE:
800                                 M_BGE(branchdisp);
801                                 break;
802                         case BRANCH_GT:
803                                 M_BGT(branchdisp);
804                                 break;
805                         case BRANCH_LE:
806                                 M_BLE(branchdisp);
807                                 break;
808                         case BRANCH_UNCONDITIONAL:
809                                 M_BR(branchdisp);
810                                 break;
811                         default:
812                                 vm_abort("emit_branch: unknown condition %d", condition);
813                 }
814         } else {
815
816                 /* If LONGBRANCHES is not set, the flag and the error flag */
817
818                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
819                         cd->flags |= (CODEGENDATA_FLAG_ERROR |
820                                 CODEGENDATA_FLAG_LONGBRANCHES);
821                 }
822
823                 /* If error flag is set, do nothing. The method has to be recompiled. */
824
825                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
826                         return;
827                 }
828
829                 /* Patch the displacement to branch over the actual branch manually
830                  * to not get yet more nops.
831                  */
832
833                 branchmpc = cd->mcodeptr - cd->mcodebase;
834                 ref = cd->mcodeptr;
835
836                 switch (condition) {
837                         case BRANCH_EQ:
838                                 M_BNE(0);
839                                 break;
840                         case BRANCH_NE:
841                                 M_BEQ(0);
842                                 break;
843                         case BRANCH_LT:
844                                 M_BGE(0);
845                                 break;
846                         case BRANCH_GE:
847                                 M_BLT(0);
848                                 break;
849                         case BRANCH_GT:
850                                 M_BLE(0);
851                                 break;
852                         case BRANCH_LE:
853                                 M_BGT(0);
854                                 break;
855                         case BRANCH_UNCONDITIONAL:
856                                 /* fall through, no displacement to patch */
857                                 ref = NULL;
858                                 break;
859                         default:
860                                 vm_abort("emit_branch: unknown condition %d", condition);
861                 }
862
863                 /* The actual long branch */
864
865                 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
866                 M_ILD_DSEG(REG_ITMP3, disp);
867                 M_AADD(REG_PV, REG_ITMP3);
868                 M_JMP(RN, REG_ITMP3);
869
870                 /* Patch back the displacement */
871
872                 if (ref != NULL) {
873                         *(u4 *)ref |= (u4)((cd->mcodeptr - ref) / 2);
874                 }
875         }
876 }
877
878 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) {
879         if (INSTRUCTION_MUST_CHECK(iptr)) {
880                 M_TEST(reg);
881                 M_BNE(SZ_BRC + SZ_ILL);
882                 M_ILL(EXCEPTION_HARDWARE_ARITHMETIC);
883         }
884 }
885
886 /* emit_arrayindexoutofbounds_check ********************************************
887
888    Emit a ArrayIndexOutOfBoundsException check.
889
890 *******************************************************************************/
891
892 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
893 {
894         if (INSTRUCTION_MUST_CHECK(iptr)) {
895                 /* Size is s4, >= 0
896                  * Do unsigned comparison to catch negative indexes.
897                  */
898                 N_CL(s2, OFFSET(java_arrayheader, size), RN, s1);
899         M_BLT(SZ_BRC + SZ_ILL);
900                 M_ILL2(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
901         }
902 }
903
904 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
905         if (INSTRUCTION_MUST_CHECK(iptr)) {
906                 if (reg != RN) {
907                         M_TEST(reg);
908                 }
909                 switch (condition) {
910                         case BRANCH_LE:
911                                 M_BGT(SZ_BRC + SZ_ILL);
912                                 break;
913                         case BRANCH_EQ:
914                                 M_BNE(SZ_BRC + SZ_ILL);
915                                 break;
916                         case BRANCH_GT:
917                                 M_BLE(SZ_BRC + SZ_ILL);
918                                 break;
919                         default:
920                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
921                 }
922                 M_ILL2(s1, EXCEPTION_HARDWARE_CLASSCAST);
923         }
924 }
925
926 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) {
927         if (INSTRUCTION_MUST_CHECK(iptr)) {
928                 M_TEST(reg);
929                 M_BNE(SZ_BRC + SZ_ILL);
930                 M_ILL(EXCEPTION_HARDWARE_NULLPOINTER);
931         }
932 }
933
934 void emit_exception_check(codegendata *cd, instruction *iptr) {
935         if (INSTRUCTION_MUST_CHECK(iptr)) {
936                 M_TEST(REG_RESULT);
937                 M_BNE(SZ_BRC + SZ_ILL);
938                 M_ILL(EXCEPTION_HARDWARE_EXCEPTION);
939         }
940 }
941
942 void emit_restore_pv(codegendata *cd) {
943         s4 offset, offset_imm;
944
945         /*
946         N_BASR(REG_PV, RN);
947         disp = (s4) (cd->mcodeptr - cd->mcodebase);
948         M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
949         */
950
951         /* If the offset from the method start does not fit into an immediate
952          * value, we can't put it into the data segment!
953          */
954
955         /* Displacement from start of method to here */
956
957         offset = (s4) (cd->mcodeptr - cd->mcodebase);
958         offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
959
960         if (N_VALID_IMM(offset_imm)) {
961                 /* Get program counter */
962                 N_BASR(REG_PV, RN);
963                 /* Substract displacement */
964                 M_AADD_IMM(offset_imm, REG_PV);
965         } else {
966                 /* Save program counter and jump over displacement in instruction flow */
967                 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
968                 /* Place displacement here */
969                 /* REG_PV points now exactly to this position */
970                 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
971                 /* Substract *(REG_PV) from REG_PV */
972                 N_A(REG_PV, 0, RN, REG_PV);
973         }
974 }
975
976 /*
977  * These are local overrides for various environment variables in Emacs.
978  * Please do not remove this and leave it at the end of the file, where
979  * Emacs will automagically detect them.
980  * ---------------------------------------------------------------------
981  * Local variables:
982  * mode: c
983  * indent-tabs-mode: t
984  * c-basic-offset: 4
985  * tab-width: 4
986  * End:
987  */