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