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